github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_key_manager.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package ecdh 8 9 import ( 10 "crypto/elliptic" 11 "errors" 12 "fmt" 13 14 "github.com/google/tink/go/core/registry" 15 hybrid "github.com/google/tink/go/hybrid/subtle" 16 "github.com/google/tink/go/keyset" 17 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 18 "google.golang.org/protobuf/proto" 19 20 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite" 21 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite/ecdh/subtle" 22 ecdhpb "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" 23 ) 24 25 const ( 26 nistpECDHKWPrivateKeyVersion = 0 27 nistpECDHKWPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPrivateKey" 28 ) 29 30 // common errors. 31 var ( 32 errInvalidNISTPECDHKWPrivateKey = errors.New("nistpkw_ecdh_private_key_manager: invalid key") 33 errInvalidNISTPECDHKWPrivateKeyFormat = errors.New("nistpkw_ecdh_private_key_manager: invalid key format") 34 ) 35 36 // nistPECDHKWPrivateKeyManager is an implementation of PrivateKeyManager interface for NIST P curved key wrapping. 37 // It generates new ECDHPrivateKey (NIST P KW) keys and produces new instances of ECDHAEADCompositeDecrypt subtle. 38 type nistPECDHKWPrivateKeyManager struct{} 39 40 // Assert that nistPECDHKWPrivateKeyManager implements the PrivateKeyManager interface. 41 var _ registry.PrivateKeyManager = (*nistPECDHKWPrivateKeyManager)(nil) 42 43 // newECDHNISTPAESPrivateKeyManager creates a new nistPECDHKWPrivateKeyManager. 44 func newECDHNISTPAESPrivateKeyManager() *nistPECDHKWPrivateKeyManager { 45 return new(nistPECDHKWPrivateKeyManager) 46 } 47 48 // Primitive creates an ECDHESPrivateKey subtle for the given serialized ECDHESPrivateKey proto. 49 func (km *nistPECDHKWPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { 50 if len(serializedKey) == 0 { 51 return nil, errInvalidNISTPECDHKWPrivateKey 52 } 53 54 key := new(ecdhpb.EcdhAeadPrivateKey) 55 56 err := proto.Unmarshal(serializedKey, key) 57 if err != nil { 58 return nil, errInvalidNISTPECDHKWPrivateKey 59 } 60 61 _, err = km.validateKey(key) 62 if err != nil { 63 return nil, errInvalidNISTPECDHKWPrivateKey 64 } 65 66 rEnc, err := composite.NewRegisterCompositeAEADEncHelper(key.PublicKey.Params.EncParams.AeadEnc) 67 if err != nil { 68 return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: NewRegisterCompositeAEADEncHelper "+ 69 "failed: %w", err) 70 } 71 72 return subtle.NewECDHAEADCompositeDecrypt(rEnc, key.PublicKey.Params.EncParams.CEK), nil 73 } 74 75 // NewKey creates a new key according to the specification of ECDHESPrivateKey format. 76 func (km *nistPECDHKWPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 77 if len(serializedKeyFormat) == 0 { 78 return nil, errInvalidNISTPECDHKWPrivateKeyFormat 79 } 80 81 keyFormat := new(ecdhpb.EcdhAeadKeyFormat) 82 83 err := proto.Unmarshal(serializedKeyFormat, keyFormat) 84 if err != nil { 85 return nil, errInvalidNISTPECDHKWPrivateKeyFormat 86 } 87 88 curve, err := validateKeyFormat(keyFormat.Params) 89 if err != nil { 90 return nil, errInvalidNISTPECDHKWPrivateKeyFormat 91 } 92 93 // If CEK is present, this key is used for primitive execution only, ie this is a dummy key, not meant to be stored. 94 // This avoids creating a real key to improve performance. 95 if keyFormat.Params.EncParams.CEK != nil { 96 return &ecdhpb.EcdhAeadPrivateKey{ 97 Version: nistpECDHKWPrivateKeyVersion, 98 KeyValue: []byte{}, 99 PublicKey: &ecdhpb.EcdhAeadPublicKey{ 100 Version: nistpECDHKWPrivateKeyVersion, 101 Params: keyFormat.Params, 102 X: []byte{}, 103 Y: []byte{}, 104 }, 105 }, nil 106 } 107 108 pvt, err := hybrid.GenerateECDHKeyPair(curve) 109 if err != nil { 110 return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: GenerateECDHKeyPair failed: %w", err) 111 } 112 113 return &ecdhpb.EcdhAeadPrivateKey{ 114 Version: nistpECDHKWPrivateKeyVersion, 115 KeyValue: pvt.D.Bytes(), 116 PublicKey: &ecdhpb.EcdhAeadPublicKey{ 117 Version: nistpECDHKWPrivateKeyVersion, 118 Params: keyFormat.Params, 119 X: pvt.PublicKey.Point.X.Bytes(), 120 Y: pvt.PublicKey.Point.Y.Bytes(), 121 }, 122 }, nil 123 } 124 125 // NewKeyData creates a new KeyData according to the specification of ECDHESPrivateKey Format. 126 // It should be used solely by the key management API. 127 func (km *nistPECDHKWPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 128 key, err := km.NewKey(serializedKeyFormat) 129 if err != nil { 130 return nil, err 131 } 132 133 serializedKey, err := proto.Marshal(key) 134 if err != nil { 135 return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: Proto.Marshal failed: %w", err) 136 } 137 138 return &tinkpb.KeyData{ 139 TypeUrl: nistpECDHKWPrivateKeyTypeURL, 140 Value: serializedKey, 141 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, 142 }, nil 143 } 144 145 // PublicKeyData returns the enclosed public key data of serializedPrivKey. 146 func (km *nistPECDHKWPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { 147 privKey := new(ecdhpb.EcdhAeadPrivateKey) 148 149 err := proto.Unmarshal(serializedPrivKey, privKey) 150 if err != nil { 151 return nil, errInvalidNISTPECDHKWPrivateKey 152 } 153 154 serializedPubKey, err := proto.Marshal(privKey.PublicKey) 155 if err != nil { 156 return nil, errInvalidNISTPECDHKWPrivateKey 157 } 158 159 return &tinkpb.KeyData{ 160 TypeUrl: nistpECDHKWPublicKeyTypeURL, 161 Value: serializedPubKey, 162 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, 163 }, nil 164 } 165 166 // DoesSupport indicates if this key manager supports the given key type. 167 func (km *nistPECDHKWPrivateKeyManager) DoesSupport(typeURL string) bool { 168 return typeURL == nistpECDHKWPrivateKeyTypeURL 169 } 170 171 // TypeURL returns the key type of keys managed by this key manager. 172 func (km *nistPECDHKWPrivateKeyManager) TypeURL() string { 173 return nistpECDHKWPrivateKeyTypeURL 174 } 175 176 // validateKey validates the given ECDHPrivateKey and returns the KW curve. 177 func (km *nistPECDHKWPrivateKeyManager) validateKey(key *ecdhpb.EcdhAeadPrivateKey) (elliptic.Curve, error) { 178 err := keyset.ValidateKeyVersion(key.Version, nistpECDHKWPrivateKeyVersion) 179 if err != nil { 180 return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: invalid key: %w", err) 181 } 182 183 return validateKeyFormat(key.PublicKey.Params) 184 } 185 186 // validateKeyFormat validates the given ECDHESKeyFormat and returns the KW Curve. 187 func validateKeyFormat(params *ecdhpb.EcdhAeadParams) (elliptic.Curve, error) { 188 var ( 189 c elliptic.Curve 190 err error 191 ) 192 193 // if CEK is set, then curve is unknown, ie this is not a recipient key, it's a primitive execution key for 194 // Encryption/Decryption. Set P-384 curve for key generation 195 if params.EncParams.CEK == nil { 196 c, err = hybrid.GetCurve(params.KwParams.CurveType.String()) 197 if err != nil { 198 return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: invalid key: %w", err) 199 } 200 } else { 201 c = elliptic.P384() 202 } 203 204 km, err := registry.GetKeyManager(params.EncParams.AeadEnc.TypeUrl) 205 if err != nil { 206 return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: GetKeyManager error: %w", err) 207 } 208 209 _, err = km.NewKeyData(params.EncParams.AeadEnc.Value) 210 if err != nil { 211 return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: NewKeyData error: %w", err) 212 } 213 214 if params.KwParams.KeyType.String() != ecdhpb.KeyType_EC.String() { 215 return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: invalid key type %v", 216 params.KwParams.KeyType) 217 } 218 219 return c, nil 220 }