1*e7b1675dSTing-Kang Chang// Copyright 2022 Google LLC 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Chang// Package hybrid provides HybridEncrypt/Decrypt primitive-specific test 18*e7b1675dSTing-Kang Chang// utilities. 19*e7b1675dSTing-Kang Changpackage hybrid 20*e7b1675dSTing-Kang Chang 21*e7b1675dSTing-Kang Changimport ( 22*e7b1675dSTing-Kang Chang "errors" 23*e7b1675dSTing-Kang Chang "fmt" 24*e7b1675dSTing-Kang Chang 25*e7b1675dSTing-Kang Chang "google.golang.org/protobuf/proto" 26*e7b1675dSTing-Kang Chang "github.com/google/tink/go/keyset" 27*e7b1675dSTing-Kang Chang "github.com/google/tink/go/testkeyset" 28*e7b1675dSTing-Kang Chang hpkepb "github.com/google/tink/go/proto/hpke_go_proto" 29*e7b1675dSTing-Kang Chang tinkpb "github.com/google/tink/go/proto/tink_go_proto" 30*e7b1675dSTing-Kang Chang) 31*e7b1675dSTing-Kang Chang 32*e7b1675dSTing-Kang Changconst ( 33*e7b1675dSTing-Kang Chang // HPKE key lengths from 34*e7b1675dSTing-Kang Chang // https://www.rfc-editor.org/rfc/rfc9180.html#section-7.1. 35*e7b1675dSTing-Kang Chang hpkeX25519HKDFSHA256PrivKeyLen = 32 36*e7b1675dSTing-Kang Chang hpkeX25519HKDFSHA256PubKeyLen = 32 37*e7b1675dSTing-Kang Chang 38*e7b1675dSTing-Kang Chang hpkePrivateKeyTypeURL = "type.googleapis.com/google.crypto.tink.HpkePrivateKey" 39*e7b1675dSTing-Kang Chang) 40*e7b1675dSTing-Kang Chang 41*e7b1675dSTing-Kang Chang// KeysetHandleFromSerializedPrivateKey returns a keyset handle containing a 42*e7b1675dSTing-Kang Chang// primary key that has the specified privKeyBytes and pubKeyBytes and matches 43*e7b1675dSTing-Kang Chang// template. 44*e7b1675dSTing-Kang Chang// 45*e7b1675dSTing-Kang Chang// Supported templates include: 46*e7b1675dSTing-Kang Chang// - DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_Raw_Key_Template, 47*e7b1675dSTing-Kang Chang// which requires privKeyBytes and pubKeyBytes to be the KEM-encoding of the 48*e7b1675dSTing-Kang Chang// private and public key, respectively, i.e. SerializePrivateKey and 49*e7b1675dSTing-Kang Chang// SerializePublicKey in 50*e7b1675dSTing-Kang Chang// https://www.rfc-editor.org/rfc/rfc9180.html#section-7.1.1. 51*e7b1675dSTing-Kang Changfunc KeysetHandleFromSerializedPrivateKey(privKeyBytes, pubKeyBytes []byte, template *tinkpb.KeyTemplate) (*keyset.Handle, error) { 52*e7b1675dSTing-Kang Chang params, err := hpkeParamsFromTemplate(template) 53*e7b1675dSTing-Kang Chang if err != nil { 54*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("failed to verify key template: %v", err) 55*e7b1675dSTing-Kang Chang } 56*e7b1675dSTing-Kang Chang if len(privKeyBytes) != hpkeX25519HKDFSHA256PrivKeyLen { 57*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("privKeyBytes length is %d but should be %d", len(privKeyBytes), hpkeX25519HKDFSHA256PrivKeyLen) 58*e7b1675dSTing-Kang Chang } 59*e7b1675dSTing-Kang Chang if len(pubKeyBytes) != hpkeX25519HKDFSHA256PubKeyLen { 60*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("pubKeyBytes length is %d but should be %d", len(pubKeyBytes), hpkeX25519HKDFSHA256PubKeyLen) 61*e7b1675dSTing-Kang Chang } 62*e7b1675dSTing-Kang Chang 63*e7b1675dSTing-Kang Chang privKey := &hpkepb.HpkePrivateKey{ 64*e7b1675dSTing-Kang Chang Version: 0, 65*e7b1675dSTing-Kang Chang PrivateKey: privKeyBytes, 66*e7b1675dSTing-Kang Chang PublicKey: &hpkepb.HpkePublicKey{ 67*e7b1675dSTing-Kang Chang Version: 0, 68*e7b1675dSTing-Kang Chang Params: params, 69*e7b1675dSTing-Kang Chang PublicKey: pubKeyBytes, 70*e7b1675dSTing-Kang Chang }, 71*e7b1675dSTing-Kang Chang } 72*e7b1675dSTing-Kang Chang serializedPrivKey, err := proto.Marshal(privKey) 73*e7b1675dSTing-Kang Chang if err != nil { 74*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("failed to marshal HpkePrivateKey %v: %v", privKey, err) 75*e7b1675dSTing-Kang Chang } 76*e7b1675dSTing-Kang Chang ks := &tinkpb.Keyset{ 77*e7b1675dSTing-Kang Chang PrimaryKeyId: 1, 78*e7b1675dSTing-Kang Chang Key: []*tinkpb.Keyset_Key{ 79*e7b1675dSTing-Kang Chang { 80*e7b1675dSTing-Kang Chang KeyData: &tinkpb.KeyData{ 81*e7b1675dSTing-Kang Chang TypeUrl: hpkePrivateKeyTypeURL, 82*e7b1675dSTing-Kang Chang Value: serializedPrivKey, 83*e7b1675dSTing-Kang Chang KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, 84*e7b1675dSTing-Kang Chang }, 85*e7b1675dSTing-Kang Chang Status: tinkpb.KeyStatusType_ENABLED, 86*e7b1675dSTing-Kang Chang KeyId: 1, 87*e7b1675dSTing-Kang Chang OutputPrefixType: tinkpb.OutputPrefixType_RAW, 88*e7b1675dSTing-Kang Chang }, 89*e7b1675dSTing-Kang Chang }, 90*e7b1675dSTing-Kang Chang } 91*e7b1675dSTing-Kang Chang return testkeyset.NewHandle(ks) 92*e7b1675dSTing-Kang Chang} 93*e7b1675dSTing-Kang Chang 94*e7b1675dSTing-Kang Chang// hpkeParamsFromTemplate returns HPKE params after verifying that template is 95*e7b1675dSTing-Kang Chang// supported. 96*e7b1675dSTing-Kang Chang// 97*e7b1675dSTing-Kang Chang// Supported templates include: 98*e7b1675dSTing-Kang Chang// - DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_Raw_Key_Template. 99*e7b1675dSTing-Kang Changfunc hpkeParamsFromTemplate(template *tinkpb.KeyTemplate) (*hpkepb.HpkeParams, error) { 100*e7b1675dSTing-Kang Chang if template.GetTypeUrl() != hpkePrivateKeyTypeURL { 101*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("not key type URL %s", hpkePrivateKeyTypeURL) 102*e7b1675dSTing-Kang Chang } 103*e7b1675dSTing-Kang Chang if template.GetOutputPrefixType() != tinkpb.OutputPrefixType_RAW { 104*e7b1675dSTing-Kang Chang return nil, errors.New("not raw output prefix type") 105*e7b1675dSTing-Kang Chang } 106*e7b1675dSTing-Kang Chang keyFormat := &hpkepb.HpkeKeyFormat{} 107*e7b1675dSTing-Kang Chang if err := proto.Unmarshal(template.GetValue(), keyFormat); err != nil { 108*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("failed to unmarshal HpkeKeyFormat(%v): %v", template.GetValue(), err) 109*e7b1675dSTing-Kang Chang } 110*e7b1675dSTing-Kang Chang 111*e7b1675dSTing-Kang Chang params := keyFormat.GetParams() 112*e7b1675dSTing-Kang Chang if kem := params.GetKem(); kem != hpkepb.HpkeKem_DHKEM_X25519_HKDF_SHA256 { 113*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("HPKE KEM %s not supported", kem) 114*e7b1675dSTing-Kang Chang } 115*e7b1675dSTing-Kang Chang if kdf := params.GetKdf(); kdf != hpkepb.HpkeKdf_HKDF_SHA256 { 116*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("HPKE KDF %s not supported", kdf) 117*e7b1675dSTing-Kang Chang } 118*e7b1675dSTing-Kang Chang if aead := params.GetAead(); aead != hpkepb.HpkeAead_CHACHA20_POLY1305 { 119*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("HPKE AEAD %s not supported", aead) 120*e7b1675dSTing-Kang Chang } 121*e7b1675dSTing-Kang Chang 122*e7b1675dSTing-Kang Chang return params, nil 123*e7b1675dSTing-Kang Chang} 124