github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_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/ed25519" 11 "crypto/rand" 12 "errors" 13 "fmt" 14 15 "github.com/google/tink/go/core/registry" 16 "github.com/google/tink/go/keyset" 17 commonpb "github.com/google/tink/go/proto/common_go_proto" 18 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 19 "google.golang.org/protobuf/proto" 20 21 "github.com/trustbloc/kms-go/util/cryptoutil" 22 23 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite" 24 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/composite/ecdh/subtle" 25 ecdhpb "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" 26 ) 27 28 const ( 29 x25519ECDHKWPrivateKeyVersion = 0 30 x25519ECDHKWPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.X25519EcdhKwPrivateKey" 31 ) 32 33 // common errors. 34 var ( 35 errInvalidx25519ECDHKWPrivateKey = errors.New("x25519kw_ecdh_private_key_manager: invalid key") 36 errInvalidx25519ECDHKWPrivateKeyFormat = errors.New("x25519kw_ecdh_private_key_manager: invalid key format") 37 ) 38 39 // x25519ECDHKWPrivateKeyManager is an implementation of PrivateKeyManager interface for X25519 key wrapping. 40 // It generates new ECDHPrivateKey (X25519 KW) keys and produces new instances of ECDHAEADCompositeDecrypt subtle. 41 type x25519ECDHKWPrivateKeyManager struct{} 42 43 // Assert that x25519ECDHKWPrivateKeyManager implements the PrivateKeyManager interface. 44 var _ registry.PrivateKeyManager = (*x25519ECDHKWPrivateKeyManager)(nil) 45 46 // newX25519ECDHKWPrivateKeyManager creates a new x25519ECDHKWPrivateKeyManager. 47 func newX25519ECDHKWPrivateKeyManager() *x25519ECDHKWPrivateKeyManager { 48 return new(x25519ECDHKWPrivateKeyManager) 49 } 50 51 // Primitive creates an ECDHESPrivateKey subtle for the given serialized ECDHESPrivateKey proto. 52 func (km *x25519ECDHKWPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { 53 if len(serializedKey) == 0 { 54 return nil, errInvalidx25519ECDHKWPrivateKey 55 } 56 57 key := new(ecdhpb.EcdhAeadPrivateKey) 58 59 err := proto.Unmarshal(serializedKey, key) 60 if err != nil { 61 return nil, errInvalidx25519ECDHKWPrivateKey 62 } 63 64 err = km.validateKey(key) 65 if err != nil { 66 return nil, errInvalidx25519ECDHKWPrivateKey 67 } 68 69 rEnc, err := composite.NewRegisterCompositeAEADEncHelper(key.PublicKey.Params.EncParams.AeadEnc) 70 if err != nil { 71 return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: NewRegisterCompositeAEADEncHelper "+ 72 "failed: %w", err) 73 } 74 75 return subtle.NewECDHAEADCompositeDecrypt(rEnc, key.PublicKey.Params.EncParams.CEK), nil 76 } 77 78 // NewKey creates a new key according to the specification of ECDHESPrivateKey format. 79 func (km *x25519ECDHKWPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 80 if len(serializedKeyFormat) == 0 { 81 return nil, errInvalidx25519ECDHKWPrivateKeyFormat 82 } 83 84 keyFormat := new(ecdhpb.EcdhAeadKeyFormat) 85 86 err := proto.Unmarshal(serializedKeyFormat, keyFormat) 87 if err != nil { 88 return nil, errInvalidx25519ECDHKWPrivateKeyFormat 89 } 90 91 err = validateKeyXChachaFormat(keyFormat.Params) 92 if err != nil { 93 return nil, errInvalidx25519ECDHKWPrivateKeyFormat 94 } 95 96 // If CEK is present, this key is used for primitive execution only, ie this is a dummy key, not meant to be stored. 97 // This avoids creating a real key to improve performance. 98 if keyFormat.Params.EncParams.CEK != nil { 99 return &ecdhpb.EcdhAeadPrivateKey{ 100 Version: x25519ECDHKWPrivateKeyVersion, 101 KeyValue: []byte{}, 102 PublicKey: &ecdhpb.EcdhAeadPublicKey{ 103 Version: x25519ECDHKWPrivateKeyVersion, 104 Params: keyFormat.Params, 105 X: []byte{}, 106 }, 107 }, nil 108 } 109 110 pub, pvt, err := ed25519.GenerateKey(rand.Reader) 111 if err != nil { 112 return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: GenerateECDHKeyPair failed: %w", err) 113 } 114 115 x25519Pub, err := cryptoutil.PublicEd25519toCurve25519(pub) 116 if err != nil { 117 return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: Convert to X25519 pub key failed: %w", err) 118 } 119 120 x25519Pvt, err := cryptoutil.SecretEd25519toCurve25519(pvt) 121 if err != nil { 122 return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: Convert to X25519 priv key failed: %w", err) 123 } 124 125 return &ecdhpb.EcdhAeadPrivateKey{ 126 Version: x25519ECDHKWPrivateKeyVersion, 127 KeyValue: x25519Pvt, 128 PublicKey: &ecdhpb.EcdhAeadPublicKey{ 129 Version: x25519ECDHKWPrivateKeyVersion, 130 Params: keyFormat.Params, 131 X: x25519Pub, 132 }, 133 }, nil 134 } 135 136 // NewKeyData creates a new KeyData according to the specification of ECDHESPrivateKey Format. 137 // It should be used solely by the key management API. 138 func (km *x25519ECDHKWPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 139 key, err := km.NewKey(serializedKeyFormat) 140 if err != nil { 141 return nil, err 142 } 143 144 serializedKey, err := proto.Marshal(key) 145 if err != nil { 146 return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: Proto.Marshal failed: %w", err) 147 } 148 149 return &tinkpb.KeyData{ 150 TypeUrl: x25519ECDHKWPrivateKeyTypeURL, 151 Value: serializedKey, 152 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, 153 }, nil 154 } 155 156 // PublicKeyData returns the enclosed public key data of serializedPrivKey. 157 func (km *x25519ECDHKWPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { 158 privKey := new(ecdhpb.EcdhAeadPrivateKey) 159 160 err := proto.Unmarshal(serializedPrivKey, privKey) 161 if err != nil { 162 return nil, errInvalidx25519ECDHKWPrivateKey 163 } 164 165 serializedPubKey, err := proto.Marshal(privKey.PublicKey) 166 if err != nil { 167 return nil, errInvalidx25519ECDHKWPrivateKey 168 } 169 170 return &tinkpb.KeyData{ 171 TypeUrl: x25519ECDHKWPublicKeyTypeURL, 172 Value: serializedPubKey, 173 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, 174 }, nil 175 } 176 177 // DoesSupport indicates if this key manager supports the given key type. 178 func (km *x25519ECDHKWPrivateKeyManager) DoesSupport(typeURL string) bool { 179 return typeURL == x25519ECDHKWPrivateKeyTypeURL 180 } 181 182 // TypeURL returns the key type of keys managed by this key manager. 183 func (km *x25519ECDHKWPrivateKeyManager) TypeURL() string { 184 return x25519ECDHKWPrivateKeyTypeURL 185 } 186 187 // validateKey validates the given ECDHPrivateKey and returns the KW curve. 188 func (km *x25519ECDHKWPrivateKeyManager) validateKey(key *ecdhpb.EcdhAeadPrivateKey) error { 189 err := keyset.ValidateKeyVersion(key.Version, x25519ECDHKWPrivateKeyVersion) 190 if err != nil { 191 return fmt.Errorf("x25519kw_ecdh_private_key_manager: invalid key: %w", err) 192 } 193 194 return validateKeyXChachaFormat(key.PublicKey.Params) 195 } 196 197 // validateKeyXChachaFormat validates the given ECDHESKeyFormat and returns the KW Curve. 198 func validateKeyXChachaFormat(params *ecdhpb.EcdhAeadParams) error { 199 var err error 200 201 km, err := registry.GetKeyManager(params.EncParams.AeadEnc.TypeUrl) 202 if err != nil { 203 return fmt.Errorf("x25519kw_ecdh_private_key_manager: GetKeyManager error: %w", err) 204 } 205 206 _, err = km.NewKeyData(params.EncParams.AeadEnc.Value) 207 if err != nil { 208 return fmt.Errorf("x25519kw_ecdh_private_key_manager: NewKeyData error: %w", err) 209 } 210 211 if params.KwParams.KeyType.String() != ecdhpb.KeyType_OKP.String() { 212 return fmt.Errorf("x25519kw_ecdh_private_key_manager: invalid key type %v", 213 params.KwParams.KeyType) 214 } 215 216 // if CEK is not set, this is a KW key for storage, it must have the curve. 217 // if it is set, then this is a primitive execution key, the curve is not needed since we do content encryption. 218 if params.EncParams.CEK == nil && 219 params.KwParams.CurveType.String() != commonpb.EllipticCurveType_CURVE25519.String() { 220 return fmt.Errorf("x25519kw_ecdh_private_key_manager: invalid curve %v", 221 params.KwParams.CurveType) 222 } 223 224 return nil 225 }