1// Copyright 2022 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package hybrid 18 19import ( 20 "errors" 21 "fmt" 22 23 "google.golang.org/protobuf/proto" 24 "github.com/google/tink/go/core/registry" 25 "github.com/google/tink/go/hybrid/internal/hpke" 26 "github.com/google/tink/go/keyset" 27 "github.com/google/tink/go/subtle" 28 hpkepb "github.com/google/tink/go/proto/hpke_go_proto" 29 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 30) 31 32const ( 33 // maxSupportedHPKEPrivateKeyVersion is the max supported private key 34 // version. It must be incremented when support for new versions are 35 // implemented. 36 maxSupportedHPKEPrivateKeyVersion uint32 = 0 37 hpkePrivateKeyTypeURL = "type.googleapis.com/google.crypto.tink.HpkePrivateKey" 38) 39 40var ( 41 errInvalidHPKEPrivateKey = errors.New("invalid HPKE private key") 42 errInvalidHPKEPrivateKeyFormat = errors.New("invalid HPKE private key format") 43) 44 45// hpkePrivateKeyManager implements the KeyManager interface for HybridDecrypt. 46type hpkePrivateKeyManager struct{} 47 48var _ registry.PrivateKeyManager = (*hpkePrivateKeyManager)(nil) 49 50func (p *hpkePrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { 51 if len(serializedKey) == 0 { 52 return nil, errInvalidHPKEPrivateKey 53 } 54 key := new(hpkepb.HpkePrivateKey) 55 if err := proto.Unmarshal(serializedKey, key); err != nil { 56 return nil, errInvalidHPKEPrivateKey 57 } 58 if err := keyset.ValidateKeyVersion(key.GetVersion(), maxSupportedHPKEPrivateKeyVersion); err != nil { 59 return nil, err 60 } 61 return hpke.NewDecrypt(key) 62} 63 64// NewKey returns a set of private and public keys of key version 0. 65func (p *hpkePrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 66 if len(serializedKeyFormat) == 0 { 67 return nil, errInvalidHPKEPrivateKeyFormat 68 } 69 keyFormat := new(hpkepb.HpkeKeyFormat) 70 if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 71 return nil, errInvalidHPKEPrivateKeyFormat 72 } 73 if err := validateKeyFormat(keyFormat); err != nil { 74 return nil, err 75 } 76 77 privKeyBytes, err := subtle.GeneratePrivateKeyX25519() 78 if err != nil { 79 return nil, fmt.Errorf("generate X25519 private key: %v", err) 80 } 81 pubKeyBytes, err := subtle.PublicFromPrivateX25519(privKeyBytes) 82 if err != nil { 83 return nil, fmt.Errorf("get X25519 public key from private key: %v", err) 84 } 85 86 return &hpkepb.HpkePrivateKey{ 87 Version: 0, 88 PublicKey: &hpkepb.HpkePublicKey{ 89 Version: 0, 90 Params: keyFormat.GetParams(), 91 PublicKey: pubKeyBytes, 92 }, 93 PrivateKey: privKeyBytes, 94 }, nil 95} 96 97func (p *hpkePrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 98 key, err := p.NewKey(serializedKeyFormat) 99 if err != nil { 100 return nil, err 101 } 102 serializedKey, err := proto.Marshal(key) 103 if err != nil { 104 return nil, err 105 } 106 return &tinkpb.KeyData{ 107 TypeUrl: hpkePrivateKeyTypeURL, 108 Value: serializedKey, 109 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, 110 }, nil 111} 112 113func (p *hpkePrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { 114 privKey := new(hpkepb.HpkePrivateKey) 115 if err := proto.Unmarshal(serializedPrivKey, privKey); err != nil { 116 return nil, errInvalidHPKEPrivateKey 117 } 118 serializedPubKey, err := proto.Marshal(privKey.GetPublicKey()) 119 if err != nil { 120 return nil, errInvalidHPKEPrivateKey 121 } 122 return &tinkpb.KeyData{ 123 TypeUrl: hpkePublicKeyTypeURL, 124 Value: serializedPubKey, 125 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, 126 }, nil 127} 128 129func (p *hpkePrivateKeyManager) DoesSupport(typeURL string) bool { 130 return typeURL == hpkePrivateKeyTypeURL 131} 132 133func (p *hpkePrivateKeyManager) TypeURL() string { 134 return hpkePrivateKeyTypeURL 135} 136 137func validateKeyFormat(kf *hpkepb.HpkeKeyFormat) error { 138 params := kf.GetParams() 139 kem, kdf, aead := params.GetKem(), params.GetKdf(), params.GetAead() 140 if kem != hpkepb.HpkeKem_DHKEM_X25519_HKDF_SHA256 || 141 kdf != hpkepb.HpkeKdf_HKDF_SHA256 || 142 (aead != hpkepb.HpkeAead_AES_128_GCM && aead != hpkepb.HpkeAead_AES_256_GCM && aead != hpkepb.HpkeAead_CHACHA20_POLY1305) { 143 return errInvalidHPKEPrivateKeyFormat 144 } 145 return nil 146} 147