From bd4aa111343e553130e1ce448c4acdd7712db40a Mon Sep 17 00:00:00 2001 From: Baha Shaaban Date: Thu, 21 Jan 2021 17:10:13 -0500 Subject: [PATCH] feat: Add support for X25519 key wrapping in ECDH Tink key This change also removes redundant ECDH key templates who were originally intended to include KW primitive logic but is not necessary since KW is executed outside of the Tink key. closes #2445 Signed-off-by: Baha Shaaban --- pkg/crypto/api.go | 6 +- pkg/crypto/tinkcrypto/crypto.go | 90 ++- pkg/crypto/tinkcrypto/crypto_test.go | 228 +++++++- pkg/crypto/tinkcrypto/key_wrapper.go | 548 ++++++++++++++---- pkg/crypto/tinkcrypto/key_wrapper_test.go | 151 +++-- .../primitive/composite/ecdh/ecdh.go | 30 +- .../composite/ecdh/ecdh_factory_test.go | 18 +- .../composite/ecdh/ecdh_key_template.go | 131 +---- .../composite/ecdh/ecdh_key_template_test.go | 28 +- ...ecdh_nistpkw_aesaead_public_key_manager.go | 100 ---- ...go => ecdh_nistpkw_private_key_manager.go} | 83 ++- ... ecdh_nistpkw_private_key_manager_test.go} | 24 +- .../ecdh/ecdh_nistpkw_public_key_manager.go | 99 ++++ ...> ecdh_nistpkw_public_key_manager_test.go} | 12 +- ...nistpkw_xchachaaead_private_key_manager.go | 170 ------ ...kw_xchachaaead_private_key_manager_test.go | 271 --------- ..._nistpkw_xchachaaead_public_key_manager.go | 100 ---- ...pkw_xchachaaead_public_key_manager_test.go | 165 ------ ...dh_x25519kw_aesaead_private_key_manager.go | 180 ------ ...5519kw_aesaead_private_key_manager_test.go | 315 ---------- ...cdh_x25519kw_aesaead_public_key_manager.go | 99 ---- ...25519kw_aesaead_public_key_manager_test.go | 185 ------ ...o => ecdh_x25519kw_private_key_manager.go} | 87 ++- ...ecdh_x25519kw_private_key_manager_test.go} | 26 +- .../ecdh/ecdh_x25519kw_public_key_manager.go | 98 ++++ ... ecdh_x25519kw_public_key_manager_test.go} | 24 +- ...x25519kw_xchachaaead_public_key_manager.go | 99 ---- .../composite/keyio/composite_key_export.go | 39 +- .../keyio/composite_key_export_import_test.go | 46 +- pkg/crypto/tinkcrypto/unwrap_support.go | 47 +- pkg/crypto/tinkcrypto/wrap_support.go | 294 ++++++++++ pkg/crypto/tinkcrypto/wrap_support_test.go | 139 +++++ pkg/crypto/webkms/remotecrypto_test.go | 8 +- pkg/crypto/wrapkey_opts.go | 18 +- pkg/doc/jose/decrypter.go | 2 +- pkg/doc/jose/encrypt_test.go | 11 +- pkg/doc/jose/encrypter.go | 2 +- pkg/doc/jose/encrypter_decrypter_test.go | 2 +- pkg/internal/cryptoutil/utils.go | 6 +- pkg/internal/cryptoutil/utils_test.go | 8 +- pkg/kms/localkms/localkms.go | 6 +- pkg/kms/localkms/pubkey_writer.go | 2 +- pkg/storage/edv/encryptedformatter_test.go | 2 +- .../formattedstore/formattedstore_test.go | 2 +- 44 files changed, 1713 insertions(+), 2288 deletions(-) delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_public_key_manager.go rename pkg/crypto/tinkcrypto/primitive/composite/ecdh/{ecdh_nistpkw_aesaead_private_key_manager.go => ecdh_nistpkw_private_key_manager.go} (55%) rename pkg/crypto/tinkcrypto/primitive/composite/ecdh/{ecdh_nistpkw_aesaead_private_key_manager_test.go => ecdh_nistpkw_private_key_manager_test.go} (91%) create mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_public_key_manager.go rename pkg/crypto/tinkcrypto/primitive/composite/ecdh/{ecdh_nistpkw_aesaead_public_key_manager_test.go => ecdh_nistpkw_public_key_manager_test.go} (92%) delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_private_key_manager.go delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_private_key_manager_test.go delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_public_key_manager.go delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_public_key_manager_test.go delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_private_key_manager.go delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_private_key_manager_test.go delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_public_key_manager.go delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_public_key_manager_test.go rename pkg/crypto/tinkcrypto/primitive/composite/ecdh/{ecdh_x25519kw_xchachaaead_private_key_manager.go => ecdh_x25519kw_private_key_manager.go} (53%) rename pkg/crypto/tinkcrypto/primitive/composite/ecdh/{ecdh_x25519kw_xchachaaead_private_key_manager_test.go => ecdh_x25519kw_private_key_manager_test.go} (88%) create mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_public_key_manager.go rename pkg/crypto/tinkcrypto/primitive/composite/ecdh/{ecdh_x25519kw_xchachaaead_public_key_manager_test.go => ecdh_x25519kw_public_key_manager_test.go} (82%) delete mode 100644 pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_public_key_manager.go create mode 100644 pkg/crypto/tinkcrypto/wrap_support.go create mode 100644 pkg/crypto/tinkcrypto/wrap_support_test.go diff --git a/pkg/crypto/api.go b/pkg/crypto/api.go index 1ab57b15fb..7020199248 100644 --- a/pkg/crypto/api.go +++ b/pkg/crypto/api.go @@ -42,7 +42,8 @@ type Crypto interface { // WrapKey will execute key wrapping of cek using apu, apv and recipient public key 'recPubKey'. // 'opts' allows setting the option sender key handle using WithSender() option. It allows ECDH-1PU key wrapping - // (aka Authcrypt). The absence of this option uses ECDH-ES key wrapping (aka Anoncrypt). + // (aka Authcrypt). The absence of this option uses ECDH-ES key wrapping (aka Anoncrypt). Another option that can + // be used is WithXC20PKW() to instruct the WrapKey to use XC20P key wrapping instead of the default A256GCM. // returns: // RecipientWrappedKey containing the wrapped cek value // error in case of errors @@ -51,7 +52,8 @@ type Crypto interface { // UnwrapKey unwraps a key in recWK using recipient private key kh. // 'opts' allows setting the option sender key handle using WithSender() option. It allows ECDH-1PU key unwrapping - // (aka Authcrypt). The absence of this option uses ECDH-ES key unwrapping (aka Anoncrypt). + // (aka Authcrypt). The absence of this option uses ECDH-ES key unwrapping (aka Anoncrypt). There is no need to + // use WithXC20PKW() for UnwrapKey since the function will use the wrapping algorithm based on recWK.Alg. // returns: // unwrapped key in raw bytes // error in case of errors diff --git a/pkg/crypto/tinkcrypto/crypto.go b/pkg/crypto/tinkcrypto/crypto.go index af790f2053..ea80c7e93f 100644 --- a/pkg/crypto/tinkcrypto/crypto.go +++ b/pkg/crypto/tinkcrypto/crypto.go @@ -11,10 +11,8 @@ SPDX-License-Identifier: Apache-2.0 package tinkcrypto import ( - "crypto/ecdsa" "errors" "fmt" - "math/big" "github.com/google/tink/go/aead" aeadsubtle "github.com/google/tink/go/aead/subtle" @@ -32,6 +30,10 @@ const ( ECDHESA256KWAlg = "ECDH-ES+A256KW" // ECDH1PUA256KWAlg is the ECDH-1PU with AES-GCM 256 key wrapping algorithm. ECDH1PUA256KWAlg = "ECDH-1PU+A256KW" + // ECDHESXC20PKWAlg is the ECDH-ES with XChacha20Poly1305 key wrapping algorithm. + ECDHESXC20PKWAlg = "ECDH-ES+XC20PKW" + // ECDH1PUXC20PKWAlg is the ECDH-1PU with XChacha20Poly1305 key wrapping algorithm. + ECDH1PUXC20PKWAlg = "ECDH-1PU+XC20PKW" ) var errBadKeyHandleFormat = errors.New("bad key handle format") @@ -43,12 +45,13 @@ var errBadKeyHandleFormat = errors.New("bad key handle format") // Crypto is the default Crypto SPI implementation using Tink. type Crypto struct { - kw keyWrapper + ecKW keyWrapper + okpKW keyWrapper } // New creates a new Crypto instance. func New() (*Crypto, error) { - return &Crypto{kw: &keyWrapperSupport{}}, nil + return &Crypto{ecKW: &ecKWSupport{}, okpKW: &okpKWSupport{}}, nil } // Encrypt will encrypt msg using the implementation's corresponding encryption key and primitive in kh of a public key. @@ -203,11 +206,13 @@ func (t *Crypto) VerifyMAC(macBytes, data []byte, kh interface{}) error { } // WrapKey will do ECDH (ES or 1PU) key wrapping of cek using apu, apv and recipient public key 'recPubKey'. -// The optional 'wrapKeyOpts' specifies the sender kh for 1PU key wrapping. // This function is used with the following parameters: -// - Key Wrapping: ECDH-ES (no options)/ECDH-1PU (using crypto.WithSender() option) over A256KW as -// per https://tools.ietf.org/html/rfc7518#appendix-A.2 -// - KDF: Concat KDF as per https://tools.ietf.org/html/rfc7518#section-4.6 +// - Key Wrapping: `ECDH-ES` (no options) or `ECDH-1PU` (using crypto.WithSender() option in wrapKeyOpts) over either +// `A256KW` alg (AES256-GCM, default with no options) as per https://tools.ietf.org/html/rfc7518#appendix-A.2 or +// `XC20PKW` alg (XChacha20Poly1305, using crypto.WithXC20PKW() option in wrapKeyOpts). +// - KDF (based on recPubKey.Curve): `Concat KDF` as per https://tools.ietf.org/html/rfc7518#section-4.6 (for recPubKey +// with NIST P curves) or `Curve25519`+`Concat KDF` as per https://tools.ietf.org/html/rfc7748#section-6.1 (for +// recPubKey with X25519 curve). // returns the resulting key wrapping info as *composite.RecipientWrappedKey or error in case of wrapping failure. func (t *Crypto) WrapKey(cek, apu, apv []byte, recPubKey *cryptoapi.PublicKey, wrapKeyOpts ...cryptoapi.WrapKeyOpts) (*cryptoapi.RecipientWrappedKey, error) { @@ -221,34 +226,34 @@ func (t *Crypto) WrapKey(cek, apu, apv []byte, recPubKey *cryptoapi.PublicKey, opt(pOpts) } - c, err := t.kw.getCurve(recPubKey.Curve) + wk, err := t.deriveKEKAndWrap(cek, apu, apv, pOpts.SenderKey(), recPubKey, pOpts.UseXC20PKW()) if err != nil { - return nil, fmt.Errorf("wrapKey: failed to get curve of recipient key: %w", err) + return nil, fmt.Errorf("wrapKey: %w", err) } - pubKey := &ecdsa.PublicKey{ - Curve: c, - X: new(big.Int).SetBytes(recPubKey.X), - Y: new(big.Int).SetBytes(recPubKey.Y), - } - - ephemeralPriv, err := t.kw.generateKey(pubKey.Curve) - if err != nil { - return nil, fmt.Errorf("wrapKey: failed to generate EPK: %w", err) - } - - return t.deriveKEKAndWrap(cek, apu, apv, pOpts.SenderKey(), ephemeralPriv, pubKey, recPubKey.KID) + return wk, nil } // UnwrapKey unwraps a key in recWK using ECDH (ES or 1PU) with recipient private key kh. -// The optional 'wrapKeyOpts' specifies the sender kh for 1PU key unwrapping. -// Note, if the option was used in WrapKey(), then it must be set here as well for a successful unwrapping. // This function is used with the following parameters: -// - Key Unwrapping: ECDH-ES (no options)/ECDH-1PU (using crypto.WithSender() option) over A256KW as -// per https://tools.ietf.org/html/rfc7518#appendix-A.2 -// - KDF: Concat KDF as per https://tools.ietf.org/html/rfc7518#section-4.6 +// - Key Unwrapping: `ECDH-ES` (no options) or `ECDH-1PU` (using crypto.WithSender() option in wrapKeyOpts) over either +// `A256KW` alg (AES256-GCM, when recWK.alg is either ECDH-ES+A256KW or ECDH-1PU+A256KW) as per +// https://tools.ietf.org/html/rfc7518#appendix-A.2 or +// `XC20PKW` alg (XChacha20Poly1305, when recWK.alg is either ECDH-ES+XC20PKW or ECDH-1PU+XC20PKW). +// - KDF (based on recWk.EPK.KeyType): `Concat KDF` as per https://tools.ietf.org/html/rfc7518#section-4.6 (for type +// value as EC) or `Curve25519`+`Concat KDF` as per https://tools.ietf.org/html/rfc7748#section-6.1 (for type value +// as OKP, ie X25519 key). // returns the resulting unwrapping key or error in case of unwrapping failure. -func (t *Crypto) UnwrapKey(recWK *cryptoapi.RecipientWrappedKey, kh interface{}, +// +// Notes: +// 1- if the crypto.WithSender() option was used in WrapKey(), then it must be set here as well for successful key +// unwrapping. +// 2- unwrapping a key with recWK.alg value set as either `ECDH-1PU+A256KW` or `ECDH-1PU+XC20PKW` requires the use of +// crypto.WithSender() option (containing the sender public key) in order to execute ECDH-1PU derivation. +// 3- the ephemeral key in recWK.EPK must have the same KeyType as the recipientKH and the same Curve for NIST P +// curved keys. Unwrapping a key with non matching types/curves will result in unwrapping failure. +// 4- recipientKH must contain the private key since unwrapping is usually done on the recipient side. +func (t *Crypto) UnwrapKey(recWK *cryptoapi.RecipientWrappedKey, recipientKH interface{}, wrapKeyOpts ...cryptoapi.WrapKeyOpts) ([]byte, error) { if recWK == nil { return nil, fmt.Errorf("unwrapKey: RecipientWrappedKey is empty") @@ -260,34 +265,11 @@ func (t *Crypto) UnwrapKey(recWK *cryptoapi.RecipientWrappedKey, kh interface{}, opt(pOpts) } - privKey, ok := kh.(*keyset.Handle) - if !ok { - return nil, fmt.Errorf("unwrapKey: %w", errBadKeyHandleFormat) - } - - recipientPrivateKey, err := extractPrivKey(privKey) + key, err := t.deriveKEKAndUnwrap(recWK.Alg, recWK.EncryptedCEK, recWK.APU, recWK.APV, &recWK.EPK, pOpts.SenderKey(), + recipientKH) if err != nil { return nil, fmt.Errorf("unwrapKey: %w", err) } - // TODO: add support for 25519 key wrapping https://github.com/hyperledger/aries-framework-go/issues/2445 - recPrivKey := hybridECPrivToECDSAKey(recipientPrivateKey) - - epkCurve, err := t.kw.getCurve(recWK.EPK.Curve) - if err != nil { - return nil, fmt.Errorf("unwrapKey: failed to GetCurve: %w", err) - } - - if recipientPrivateKey.PublicKey.Curve != epkCurve { - return nil, errors.New("unwrapKey: recipient and epk keys are not on the same curve") - } - - epkPubKey := &ecdsa.PublicKey{ - Curve: epkCurve, - X: new(big.Int).SetBytes(recWK.EPK.X), - Y: new(big.Int).SetBytes(recWK.EPK.Y), - } - - return t.deriveKEKAndUnwrap(recWK.Alg, recWK.EncryptedCEK, recWK.APU, recWK.APV, pOpts.SenderKey(), - epkPubKey, recPrivKey) + return key, nil } diff --git a/pkg/crypto/tinkcrypto/crypto_test.go b/pkg/crypto/tinkcrypto/crypto_test.go index 013e6ffd40..c4f505b415 100644 --- a/pkg/crypto/tinkcrypto/crypto_test.go +++ b/pkg/crypto/tinkcrypto/crypto_test.go @@ -8,6 +8,7 @@ package tinkcrypto import ( "crypto/ecdsa" + "crypto/elliptic" "math/big" "testing" @@ -16,6 +17,7 @@ import ( hybrid "github.com/google/tink/go/hybrid/subtle" "github.com/google/tink/go/keyset" "github.com/google/tink/go/mac" + tinkpb "github.com/google/tink/go/proto/tink_go_proto" "github.com/google/tink/go/signature" "github.com/google/tink/go/subtle/random" "github.com/stretchr/testify/require" @@ -24,6 +26,7 @@ import ( "github.com/hyperledger/aries-framework-go/pkg/crypto" "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh" "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/keyio" + ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" ) const testMessage = "test message" @@ -44,7 +47,7 @@ func TestCrypto_EncryptDecrypt(t *testing.T) { badKH, err := keyset.NewHandle(aead.KMSEnvelopeAEADKeyTemplate("babdUrl", nil)) require.NoError(t, err) - badKH2, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + badKH2, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate()) require.NoError(t, err) c := Crypto{} @@ -257,7 +260,7 @@ func TestCrypto_VerifyMAC(t *testing.T) { } func TestCrypto_ECDHES_Wrap_Unwrap_Key(t *testing.T) { - recipientKeyHandle, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKeyHandle, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) c, err := New() @@ -291,20 +294,21 @@ func TestCrypto_ECDHES_Wrap_Unwrap_Key(t *testing.T) { require.EqualError(t, err, "unwrapKey: RecipientWrappedKey is empty") _, err = c.UnwrapKey(wrappedKey, nil) - require.EqualError(t, err, "unwrapKey: bad key handle format") + require.EqualError(t, err, "unwrapKey: deriveKEKAndUnwrap: bad key handle format") // test UnwrapKey with ECDHES key but different curve - ecdh384Key, err := keyset.NewHandle(ecdh.ECDH384KWAES256GCMKeyTemplate()) + ecdh384Key, err := keyset.NewHandle(ecdh.NISTP384ECDHKWKeyTemplate()) require.NoError(t, err) _, err = c.UnwrapKey(wrappedKey, ecdh384Key) - require.EqualError(t, err, "unwrapKey: recipient and epk keys are not on the same curve") + require.EqualError(t, err, "unwrapKey: deriveKEKAndUnwrap: recipient and ephemeral keys are not on the "+ + "same curve") // test UnwrapKey with wrappedKey using different algorithm origAlg := wrappedKey.Alg wrappedKey.Alg = "badAlg" _, err = c.UnwrapKey(wrappedKey, recipientKeyHandle) - require.EqualError(t, err, "unwrapKey: unsupported JWE KW Alg 'badAlg'") + require.EqualError(t, err, "unwrapKey: deriveKEKAndUnwrap: unsupported JWE KW Alg 'badAlg'") wrappedKey.Alg = origAlg @@ -314,14 +318,214 @@ func TestCrypto_ECDHES_Wrap_Unwrap_Key(t *testing.T) { require.EqualValues(t, cek, uCEK) } +func TestCrypto_ECDHES_Wrap_Unwrap_ForAllKeyTypes(t *testing.T) { + tests := []struct { + tcName string + keyTempl *tinkpb.KeyTemplate + kwAlg string + keyType string + keyCurve string + useXC20P bool + senderKT *tinkpb.KeyTemplate + err string + }{ + { + tcName: "key wrap using ECDH-ES with NIST P-256 key and A256GCM kw", + keyTempl: ecdh.NISTP256ECDHKWKeyTemplate(), + kwAlg: ECDHESA256KWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P256().Params().Name, + }, + { + tcName: "key wrap using ECDH-ES with NIST P-384 key and A256GCM kw", + keyTempl: ecdh.NISTP384ECDHKWKeyTemplate(), + kwAlg: ECDHESA256KWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P384().Params().Name, + }, + { + tcName: "key wrap using ECDH-ES with NIST P-521 key and A256GCM kw", + keyTempl: ecdh.NISTP521ECDHKWKeyTemplate(), + kwAlg: ECDHESA256KWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P521().Params().Name, + }, + { + tcName: "key wrap using ECDH-ES with X25519 key and A256GCM kw", + keyTempl: ecdh.X25519ECDHKWKeyTemplate(), + kwAlg: ECDHESA256KWAlg, + keyType: ecdhpb.KeyType_OKP.String(), + keyCurve: "X25519", + }, + { + tcName: "key wrap using ECDH-ES with NIST P-256 key and XC20P kw", + keyTempl: ecdh.NISTP256ECDHKWKeyTemplate(), + kwAlg: ECDHESXC20PKWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P256().Params().Name, + useXC20P: true, + }, + { + tcName: "key wrap using ECDH-ES with NIST P-384 key and XC20P kw", + keyTempl: ecdh.NISTP384ECDHKWKeyTemplate(), + kwAlg: ECDHESXC20PKWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P384().Params().Name, + useXC20P: true, + }, + { + tcName: "key wrap using ECDH-ES with NIST P-521 key and XC20P kw", + keyTempl: ecdh.NISTP521ECDHKWKeyTemplate(), + kwAlg: ECDHESXC20PKWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P521().Params().Name, + useXC20P: true, + }, + { + tcName: "key wrap using ECDH-ES with X25519 key and XC20P kw", + keyTempl: ecdh.X25519ECDHKWKeyTemplate(), + kwAlg: ECDHESXC20PKWAlg, + keyType: ecdhpb.KeyType_OKP.String(), + keyCurve: "X25519", + useXC20P: true, + }, + { + tcName: "key wrap using ECDH-1PU with NIST P-256 key and A256GCM kw", + keyTempl: ecdh.NISTP256ECDHKWKeyTemplate(), + kwAlg: ECDH1PUA256KWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P256().Params().Name, + senderKT: ecdh.NISTP256ECDHKWKeyTemplate(), + }, + { + tcName: "key wrap using ECDH-1PU with NIST P-384 key and A256GCM kw", + keyTempl: ecdh.NISTP384ECDHKWKeyTemplate(), + kwAlg: ECDH1PUA256KWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P384().Params().Name, + senderKT: ecdh.NISTP384ECDHKWKeyTemplate(), + }, + { + tcName: "key wrap using ECDH-1PU with NIST P-521 key and A256GCM kw", + keyTempl: ecdh.NISTP521ECDHKWKeyTemplate(), + kwAlg: ECDH1PUA256KWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P521().Params().Name, + senderKT: ecdh.NISTP521ECDHKWKeyTemplate(), + }, + { + tcName: "key wrap using ECDH-1PU with X25519 key and A256GCM kw", + keyTempl: ecdh.X25519ECDHKWKeyTemplate(), + kwAlg: ECDH1PUA256KWAlg, + keyType: ecdhpb.KeyType_OKP.String(), + keyCurve: "X25519", + senderKT: ecdh.X25519ECDHKWKeyTemplate(), + }, + { + tcName: "key wrap using ECDH-1PU with NIST P-256 key and XC20P kw", + keyTempl: ecdh.NISTP256ECDHKWKeyTemplate(), + kwAlg: ECDH1PUXC20PKWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P256().Params().Name, + senderKT: ecdh.NISTP256ECDHKWKeyTemplate(), + useXC20P: true, + }, + { + tcName: "key wrap using ECDH-1PU with NIST P-384 key and XC20P kw", + keyTempl: ecdh.NISTP384ECDHKWKeyTemplate(), + kwAlg: ECDH1PUXC20PKWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P384().Params().Name, + senderKT: ecdh.NISTP384ECDHKWKeyTemplate(), + useXC20P: true, + }, + { + tcName: "key wrap using ECDH-1PU with NIST P-521 key and XC20P kw", + keyTempl: ecdh.NISTP521ECDHKWKeyTemplate(), + kwAlg: ECDH1PUXC20PKWAlg, + keyType: ecdhpb.KeyType_EC.String(), + keyCurve: elliptic.P521().Params().Name, + senderKT: ecdh.NISTP521ECDHKWKeyTemplate(), + useXC20P: true, + }, + { + tcName: "key wrap using ECDH-1PU with X25519 key and XC20P kw", + keyTempl: ecdh.X25519ECDHKWKeyTemplate(), + kwAlg: ECDH1PUXC20PKWAlg, + keyType: ecdhpb.KeyType_OKP.String(), + keyCurve: "X25519", + senderKT: ecdh.X25519ECDHKWKeyTemplate(), + useXC20P: true, + }, + } + + c, err := New() + require.NoError(t, err) + + cek := random.GetRandomBytes(uint32(crypto.DefKeySize)) + apu := random.GetRandomBytes(uint32(10)) // or sender name + apv := random.GetRandomBytes(uint32(10)) // or recipient name + + for _, tt := range tests { + tc := tt + t.Run("Test "+tc.tcName, func(t *testing.T) { + recipientKeyHandle, err := keyset.NewHandle(tc.keyTempl) + require.NoError(t, err) + + recipientKey, err := keyio.ExtractPrimaryPublicKey(recipientKeyHandle) + require.NoError(t, err) + + var senderKH *keyset.Handle + + var wrapKeyOtps []crypto.WrapKeyOpts + if tc.useXC20P { + // WithXC20OKW option used for WrapKey() only. UnwrapKey() does not check this option, it checks kwAlg. + wrapKeyOtps = append(wrapKeyOtps, crypto.WithXC20PKW()) + } + + if tc.senderKT != nil { + senderKH, err = keyset.NewHandle(tc.senderKT) + require.NoError(t, err) + + wrapKeyOtps = append(wrapKeyOtps, crypto.WithSender(senderKH)) + } + + wrappedKey, err := c.WrapKey(cek, apu, apv, recipientKey, wrapKeyOtps...) + require.NoError(t, err) + require.NotEmpty(t, wrappedKey.EncryptedCEK) + require.NotEmpty(t, wrappedKey.EPK) + require.EqualValues(t, wrappedKey.APU, apu) + require.EqualValues(t, wrappedKey.APV, apv) + require.Equal(t, tc.kwAlg, wrappedKey.Alg) + require.Equal(t, tc.keyCurve, wrappedKey.EPK.Curve) + require.Equal(t, tc.keyType, wrappedKey.EPK.Type) + + if senderKH != nil { + var senderPubKey *crypto.PublicKey + + // mimic recipient side (by using sender public key for unwrapping instead of the private key) + senderPubKey, err = keyio.ExtractPrimaryPublicKey(senderKH) + require.NoError(t, err) + + // reset wrapKeyOpts because UnwrapKey only uses WithSender() option. + wrapKeyOtps = []crypto.WrapKeyOpts{crypto.WithSender(senderPubKey)} + } + + uCEK, err := c.UnwrapKey(wrappedKey, recipientKeyHandle, wrapKeyOtps...) + require.NoError(t, err) + require.EqualValues(t, cek, uCEK) + }) + } +} + func TestCrypto_ECDH1PU_Wrap_Unwrap_Key(t *testing.T) { - recipientKeyHandle, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKeyHandle, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) recipientKey, err := keyio.ExtractPrimaryPublicKey(recipientKeyHandle) require.NoError(t, err) - senderKH, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + senderKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) c, err := New() @@ -333,7 +537,9 @@ func TestCrypto_ECDH1PU_Wrap_Unwrap_Key(t *testing.T) { // test with bad senderKH value _, err = c.WrapKey(cek, apu, apv, recipientKey, crypto.WithSender("badKey")) - require.EqualError(t, err, "wrapKey: failed to retrieve sender key: ksToPrivateECDSAKey: bad key handle format") + require.EqualError(t, err, "wrapKey: deriveKEKAndWrap: error ECDH-1PU kek derivation: derive1PUKEK: EC key"+ + " derivation error derive1PUWithECKey: failed to retrieve sender key: ksToPrivateECDSAKey: bad key handle "+ + "format") // now test WrapKey with good key wrappedKey, err := c.WrapKey(cek, apu, apv, recipientKey, crypto.WithSender(senderKH)) @@ -371,13 +577,13 @@ func TestCrypto_ECDH1PU_Wrap_Unwrap_Key(t *testing.T) { } func TestCrypto_ECDH1PU_Wrap_Unwrap_Key_Using_CryptoPubKey_as_SenderKey(t *testing.T) { - recipientKeyHandle, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKeyHandle, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) recipientKey, err := keyio.ExtractPrimaryPublicKey(recipientKeyHandle) require.NoError(t, err) - senderKH, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + senderKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) c, err := New() diff --git a/pkg/crypto/tinkcrypto/key_wrapper.go b/pkg/crypto/tinkcrypto/key_wrapper.go index 4bb8f272e2..752b63e890 100644 --- a/pkg/crypto/tinkcrypto/key_wrapper.go +++ b/pkg/crypto/tinkcrypto/key_wrapper.go @@ -7,19 +7,17 @@ SPDX-License-Identifier: Apache-2.0 package tinkcrypto import ( - "crypto" - "crypto/aes" - "crypto/cipher" "crypto/ecdsa" "crypto/elliptic" - "crypto/rand" - "encoding/binary" + "errors" "fmt" "math/big" hybrid "github.com/google/tink/go/hybrid/subtle" "github.com/google/tink/go/keyset" josecipher "github.com/square/go-jose/v3/cipher" + "golang.org/x/crypto/chacha20poly1305" + "golang.org/x/crypto/curve25519" cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto" "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/keyio" @@ -29,167 +27,447 @@ import ( const defKeySize = 32 -type keyWrapper interface { - getCurve(curve string) (elliptic.Curve, error) - generateKey(curve elliptic.Curve) (*ecdsa.PrivateKey, error) - createCipher(key []byte) (cipher.Block, error) - wrap(block cipher.Block, cek []byte) ([]byte, error) - unwrap(block cipher.Block, encryptedKey []byte) ([]byte, error) - deriveSender1Pu(kwAlg string, apu, apv []byte, ephemeralPriv, senderPrivKey *ecdsa.PrivateKey, - recPubKey *ecdsa.PublicKey, keySize int) ([]byte, error) - deriveRecipient1Pu(kwAlg string, apu, apv []byte, ephemeralPub, senderPubKey *ecdsa.PublicKey, - recPrivKey *ecdsa.PrivateKey, keySize int) ([]byte, error) -} +// deriveKEKAndWrap is the entry point for Crypto.WrapKey(). +func (t *Crypto) deriveKEKAndWrap(cek, apu, apv []byte, senderKH interface{}, recPubKey *cryptoapi.PublicKey, + useXC20PKW bool) (*cryptoapi.RecipientWrappedKey, error) { + var ( + kek []byte + epk *cryptoapi.PublicKey + wrappingAlg string + err error + ) -type keyWrapperSupport struct{} + if senderKH != nil { // ecdh1pu + wrappingAlg, kek, epk, err = t.derive1PUKEK(apu, apv, senderKH, recPubKey, useXC20PKW) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndWrap: error ECDH-1PU kek derivation: %w", err) + } + } else { // ecdhes + wrappingAlg, kek, epk, err = t.deriveESKEK(apu, apv, recPubKey, useXC20PKW) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndWrap: error ECDH-ES kek derivation: %w", err) + } + } -func (w *keyWrapperSupport) getCurve(curve string) (elliptic.Curve, error) { - return hybrid.GetCurve(curve) + return t.wrapRaw(kek, cek, apu, apv, wrappingAlg, recPubKey.KID, epk, useXC20PKW) } -func (w *keyWrapperSupport) generateKey(curve elliptic.Curve) (*ecdsa.PrivateKey, error) { - return ecdsa.GenerateKey(curve, rand.Reader) -} +func (t *Crypto) wrapRaw(kek, cek, apu, apv []byte, alg, kid string, epk *cryptoapi.PublicKey, + useXC20PKW bool) (*cryptoapi.RecipientWrappedKey, error) { + var wk []byte -func (w *keyWrapperSupport) createCipher(kek []byte) (cipher.Block, error) { - return aes.NewCipher(kek) -} + if useXC20PKW { // nolint: nestif // XC20P key wrap + aead, err := t.okpKW.createPrimitive(kek) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndWrap: failed to create new XC20P primitive: %w", err) + } -func (w *keyWrapperSupport) wrap(block cipher.Block, cek []byte) ([]byte, error) { - return josecipher.KeyWrap(block, cek) -} + wk, err = t.okpKW.wrap(aead, cek) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndWrap: failed to XC20P wrap key: %w", err) + } + } else { // A256GCM key wrap + block, err := t.ecKW.createPrimitive(kek) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndWrap: failed to create new AES Cipher: %w", err) + } + + wk, err = t.ecKW.wrap(block, cek) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndWrap: failed to AES wrap key: %w", err) + } + } -func (w *keyWrapperSupport) unwrap(block cipher.Block, encryptedKey []byte) ([]byte, error) { - return josecipher.KeyUnwrap(block, encryptedKey) + return &cryptoapi.RecipientWrappedKey{ + KID: kid, + EncryptedCEK: wk, + EPK: *epk, + APU: apu, + APV: apv, + Alg: alg, + }, nil } -func (w *keyWrapperSupport) deriveSender1Pu(alg string, apu, apv []byte, ephemeralPriv, senderPrivKey *ecdsa.PrivateKey, - recPubKey *ecdsa.PublicKey, keySize int) ([]byte, error) { - ze := josecipher.DeriveECDHES(alg, apu, apv, ephemeralPriv, recPubKey, keySize) - zs := josecipher.DeriveECDHES(alg, apu, apv, senderPrivKey, recPubKey, keySize) +// deriveKEKAndUnwrap is the entry point for Crypto.UnwrapKey(). +// nolint: funlen, gocognit, gocyclo +func (t *Crypto) deriveKEKAndUnwrap(alg string, encCEK, apu, apv []byte, epk *cryptoapi.PublicKey, senderKH, + recKH interface{}) ([]byte, error) { + var ( + kek []byte + err error + ) - return derive1Pu(alg, ze, zs, apu, apv, keySize) -} + privKey, ok := recKH.(*keyset.Handle) + if !ok { + return nil, fmt.Errorf("deriveKEKAndUnwrap: %w", errBadKeyHandleFormat) + } -func (w *keyWrapperSupport) deriveRecipient1Pu(alg string, apu, apv []byte, ephemeralPub, senderPubKey *ecdsa.PublicKey, - recPrivKey *ecdsa.PrivateKey, keySize int) ([]byte, error) { - // DeriveECDHES checks if keys are on the same curve - ze := josecipher.DeriveECDHES(alg, apu, apv, recPrivKey, ephemeralPub, keySize) - zs := josecipher.DeriveECDHES(alg, apu, apv, recPrivKey, senderPubKey, keySize) + recipientPrivateKey, err := extractPrivKey(privKey) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: %w", err) + } - return derive1Pu(alg, ze, zs, apu, apv, keySize) -} + switch alg { + case ECDH1PUA256KWAlg, ECDH1PUXC20PKWAlg: + if senderKH == nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: sender's public keyset handle option is required for "+ + "'%s'", ECDH1PUA256KWAlg) + } -func (t *Crypto) deriveKEKAndWrap(cek, apu, apv []byte, senderKH interface{}, ephemeralPrivKey *ecdsa.PrivateKey, - recPubKey *ecdsa.PublicKey, recKID string) (*cryptoapi.RecipientWrappedKey, error) { - var kek []byte + switch epk.Type { + case ecdhpb.KeyType_EC.String(): + var ( + senderPubKey *ecdsa.PublicKey + epkCurve elliptic.Curve + ) + + senderPubKey, err = ksToPublicECDSAKey(senderKH, t.ecKW) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to retrieve sender key: %w", err) + } + + epkCurve, err = t.ecKW.getCurve(epk.Curve) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to GetCurve: %w", err) + } + + epkPubKey := &ecdsa.PublicKey{ + Curve: epkCurve, + X: new(big.Int).SetBytes(epk.X), + Y: new(big.Int).SetBytes(epk.Y), + } + + recPrivECKey, ok := recipientPrivateKey.(*hybrid.ECPrivateKey) + if !ok { + return nil, errors.New("deriveKEKAndUnwrap: recipient key is not an EC key") + } + + recPrivKey := hybridECPrivToECDSAKey(recPrivECKey) + + kek, err = t.ecKW.deriveRecipient1Pu(alg, apu, apv, epkPubKey, senderPubKey, recPrivKey, defKeySize) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to derive kek: %w", err) + } + case ecdhpb.KeyType_OKP.String(): + var senderPubKey []byte + + senderPubKey, err = ksToPublicX25519Key(senderKH) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to retrieve sender key: %w", err) + } + + recPrivOKPKey, ok := recipientPrivateKey.([]byte) + if !ok { + return nil, errors.New("deriveKEKAndUnwrap: recipient key is not an OKP key") + } + + kek, err = t.okpKW.deriveRecipient1Pu(alg, apu, apv, epk.X, senderPubKey, recPrivOKPKey, + defKeySize) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to derive kek: %w", err) + } + default: + return nil, errors.New("deriveKEKAndUnwrap: invalid EPK key type for ECDH-1PU") + } + case ECDHESA256KWAlg, ECDHESXC20PKWAlg: + switch epk.Type { + case ecdhpb.KeyType_EC.String(): + var epkCurve elliptic.Curve + + epkCurve, err = t.ecKW.getCurve(epk.Curve) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to GetCurve: %w", err) + } + + epkPubKey := &ecdsa.PublicKey{ + Curve: epkCurve, + X: new(big.Int).SetBytes(epk.X), + Y: new(big.Int).SetBytes(epk.Y), + } + + recPrivECKey, ok := recipientPrivateKey.(*hybrid.ECPrivateKey) + if !ok { + return nil, errors.New("deriveKEKAndUnwrap: recipient key is not an EC key") + } + + recPrivKey := hybridECPrivToECDSAKey(recPrivECKey) + + if recPrivKey.Curve != epkPubKey.Curve { + return nil, errors.New("deriveKEKAndUnwrap: recipient and ephemeral keys are not on the same curve") + } + + kek = josecipher.DeriveECDHES(alg, apu, apv, recPrivKey, epkPubKey, defKeySize) + case ecdhpb.KeyType_OKP.String(): + recPrivOKPKey, ok := recipientPrivateKey.([]byte) + if !ok { + return nil, errors.New("deriveKEKAndUnwrap: recipient key is not an OKP key") + } + + recPrivKeyChacha := new([chacha20poly1305.KeySize]byte) + copy(recPrivKeyChacha[:], recPrivOKPKey) + + epkChacha := new([chacha20poly1305.KeySize]byte) + copy(epkChacha[:], epk.X) + + kek, err = cryptoutil.Derive25519KEK([]byte(alg), apu, apv, recPrivKeyChacha, epkChacha) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to derive kek: %w", err) + } + default: + return nil, errors.New("deriveKEKAndUnwrap: invalid EPK key type for ECDH-ES") + } + default: + return nil, fmt.Errorf("deriveKEKAndUnwrap: unsupported JWE KW Alg '%s'", alg) + } - // TODO: add support for 25519 key wrapping https://github.com/hyperledger/aries-framework-go/issues/2445 - keyType := ecdhpb.KeyType_EC.String() - wrappingAlg := ECDHESA256KWAlg + var wk []byte - if senderKH != nil { // ecdh1pu - wrappingAlg = ECDH1PUA256KWAlg + // key unwrapping does not depend on an option (like key wrapping), because kw primitive can be detected from alg. + switch alg { + case ECDHESXC20PKWAlg, ECDH1PUXC20PKWAlg: // XC20P key unwrap + aead, err := t.okpKW.createPrimitive(kek) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to create new XC20P primitive: %w", err) + } - senderPrivKey, err := ksToPrivateECDSAKey(senderKH) + wk, err = t.okpKW.unwrap(aead, encCEK) + if err != nil { + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to XC20P unwrap key: %w", err) + } + case ECDHESA256KWAlg, ECDH1PUA256KWAlg: // A256GCM key unwrap + block, err := t.ecKW.createPrimitive(kek) if err != nil { - return nil, fmt.Errorf("wrapKey: failed to retrieve sender key: %w", err) + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to create new AES Cipher: %w", err) } - kek, err = t.kw.deriveSender1Pu(wrappingAlg, apu, apv, ephemeralPrivKey, senderPrivKey, recPubKey, defKeySize) + wk, err = t.ecKW.unwrap(block, encCEK) if err != nil { - return nil, fmt.Errorf("wrapKey: failed to derive key: %w", err) + return nil, fmt.Errorf("deriveKEKAndUnwrap: failed to AES unwrap key: %w", err) } - } else { // ecdhes - kek = josecipher.DeriveECDHES(wrappingAlg, apu, apv, ephemeralPrivKey, recPubKey, defKeySize) + default: + return nil, fmt.Errorf("deriveKEKAndUnwrap: cannot unwrap with bad kw alg: '%s'", alg) + } + + return wk, nil +} + +func (t *Crypto) derive1PUKEK(apu, apv []byte, senderKH interface{}, recPubKey *cryptoapi.PublicKey, + useXC20PKW bool) (string, []byte, *cryptoapi.PublicKey, error) { + var ( + kek []byte + epk *cryptoapi.PublicKey + wrappingAlg string + err error + ) + + switch recPubKey.Type { + case ecdhpb.KeyType_EC.String(): + wrappingAlg, kek, epk, err = t.derive1PUWithECKey(apu, apv, senderKH, recPubKey, useXC20PKW) + if err != nil { + return "", nil, nil, fmt.Errorf("derive1PUKEK: EC key derivation error %w", err) + } + case ecdhpb.KeyType_OKP.String(): + wrappingAlg, kek, epk, err = t.derive1PUWithOKPKey(apu, apv, senderKH, recPubKey, useXC20PKW) + if err != nil { + return "", nil, nil, fmt.Errorf("derive1PUKEK: OKP key derivation error %w", err) + } + default: + return "", nil, nil, errors.New("derive1PUKEK: invalid recipient key type for ECDH-1PU") } - block, err := t.kw.createCipher(kek) + return wrappingAlg, kek, epk, nil +} + +func (t *Crypto) deriveESKEK(apu, apv []byte, recPubKey *cryptoapi.PublicKey, + useXC20PKW bool) (string, []byte, *cryptoapi.PublicKey, error) { + var ( + kek []byte + epk *cryptoapi.PublicKey + wrappingAlg string + err error + ) + + switch recPubKey.Type { + case ecdhpb.KeyType_EC.String(): + wrappingAlg, kek, epk, err = t.deriveESWithECKey(apu, apv, recPubKey, useXC20PKW) + if err != nil { + return "", nil, nil, fmt.Errorf("deriveESKEK: error %w", err) + } + case ecdhpb.KeyType_OKP.String(): + wrappingAlg, kek, epk, err = t.deriveESWithOKPKey(apu, apv, recPubKey, useXC20PKW) + if err != nil { + return "", nil, nil, fmt.Errorf("deriveESKEK: error %w", err) + } + default: + return "", nil, nil, errors.New("deriveESKEK: invalid recipient key type for ECDH-ES") + } + + return wrappingAlg, kek, epk, nil +} + +func (t *Crypto) derive1PUWithECKey(apu, apv []byte, senderKH interface{}, recPubKey *cryptoapi.PublicKey, + useXC20PKW bool) (string, []byte, *cryptoapi.PublicKey, error) { + wrappingAlg := ECDH1PUA256KWAlg + + if useXC20PKW { + wrappingAlg = ECDH1PUXC20PKWAlg + } + + senderPrivKey, err := ksToPrivateECDSAKey(senderKH) if err != nil { - return nil, fmt.Errorf("wrapKey: failed to create new Cipher: %w", err) + return "", nil, nil, fmt.Errorf("derive1PUWithECKey: failed to retrieve sender key: %w", err) } - wk, err := t.kw.wrap(block, cek) + pubKey, ephemeralPrivKey, err := t.convertRecKeyAndGenEPKEC(recPubKey) if err != nil { - return nil, fmt.Errorf("wrapKey: failed to wrap key: %w", err) + return "", nil, nil, err } - return &cryptoapi.RecipientWrappedKey{ - KID: recKID, - EncryptedCEK: wk, - EPK: cryptoapi.PublicKey{ - X: ephemeralPrivKey.PublicKey.X.Bytes(), - Y: ephemeralPrivKey.PublicKey.Y.Bytes(), - Curve: ephemeralPrivKey.PublicKey.Curve.Params().Name, - Type: keyType, - }, - APU: apu, - APV: apv, - Alg: wrappingAlg, - }, nil + kek, err := t.ecKW.deriveSender1Pu(wrappingAlg, apu, apv, ephemeralPrivKey, senderPrivKey, pubKey, defKeySize) + if err != nil { + return "", nil, nil, fmt.Errorf("derive1PUWithECKey: failed to derive key: %w", err) + } + + epk := &cryptoapi.PublicKey{ + X: ephemeralPrivKey.PublicKey.X.Bytes(), + Y: ephemeralPrivKey.PublicKey.Y.Bytes(), + Curve: ephemeralPrivKey.PublicKey.Curve.Params().Name, + Type: recPubKey.Type, + } + + return wrappingAlg, kek, epk, nil } -func (t *Crypto) deriveKEKAndUnwrap(alg string, encCEK, apu, apv []byte, senderKH interface{}, - epkPubKey *ecdsa.PublicKey, recPrivKey *ecdsa.PrivateKey) ([]byte, error) { - var kek []byte +func (t *Crypto) deriveESWithECKey(apu, apv []byte, recPubKey *cryptoapi.PublicKey, + useXC20PKW bool) (string, []byte, *cryptoapi.PublicKey, error) { + wrappingAlg := ECDHESA256KWAlg - switch alg { - case ECDH1PUA256KWAlg: - if senderKH == nil { - return nil, fmt.Errorf("unwrap: sender's public keyset handle option is required for "+ - "'%s'", ECDH1PUA256KWAlg) - } + if useXC20PKW { + wrappingAlg = ECDHESXC20PKWAlg + } - senderPubKey, err := ksToPublicECDSAKey(senderKH, t.kw) - if err != nil { - return nil, fmt.Errorf("unwrapKey: failed to retrieve sender key: %w", err) - } + recECPubKey, ephemeralPrivKey, err := t.convertRecKeyAndGenEPKEC(recPubKey) + if err != nil { + return "", nil, nil, fmt.Errorf("deriveESWithECKey: failed to generate ephemeral key: %w", err) + } - kek, err = t.kw.deriveRecipient1Pu(alg, apu, apv, epkPubKey, senderPubKey, recPrivKey, defKeySize) - if err != nil { - return nil, fmt.Errorf("unwrapKey: failed to derive kek: %w", err) - } - case ECDHESA256KWAlg: - kek = josecipher.DeriveECDHES(alg, apu, apv, recPrivKey, epkPubKey, defKeySize) - default: - return nil, fmt.Errorf("unwrapKey: unsupported JWE KW Alg '%s'", alg) + kek := josecipher.DeriveECDHES(wrappingAlg, apu, apv, ephemeralPrivKey, recECPubKey, defKeySize) + epk := &cryptoapi.PublicKey{ + X: ephemeralPrivKey.PublicKey.X.Bytes(), + Y: ephemeralPrivKey.PublicKey.Y.Bytes(), + Curve: ephemeralPrivKey.PublicKey.Curve.Params().Name, + Type: recPubKey.Type, + } + + return wrappingAlg, kek, epk, nil +} + +func (t *Crypto) derive1PUWithOKPKey(apu, apv []byte, senderKH interface{}, recPubKey *cryptoapi.PublicKey, + useXC20PKW bool) (string, []byte, *cryptoapi.PublicKey, error) { + wrappingAlg := ECDH1PUXC20PKWAlg + + if !useXC20PKW { + wrappingAlg = ECDH1PUA256KWAlg } - block, err := t.kw.createCipher(kek) + senderPrivKey, err := ksToPrivateX25519Key(senderKH) if err != nil { - return nil, fmt.Errorf("unwrapKey: failed to create new Cipher: %w", err) + return "", nil, nil, fmt.Errorf("derive1PUWithOKPKey: failed to retrieve sender key: %w", err) } - wk, err := t.kw.unwrap(block, encCEK) + ephemeralPubKey, ephemeralPrivKey, err := t.generateEphemeralOKPKey() if err != nil { - return nil, fmt.Errorf("unwrapKey: failed to unwrap key: %w", err) + return "", nil, nil, fmt.Errorf("derive1PUWithOKPKey: failed to generate ephemeral key: %w", err) } - return wk, nil + kek, err := t.okpKW.deriveSender1Pu(wrappingAlg, apu, apv, ephemeralPrivKey, senderPrivKey, recPubKey.X, defKeySize) + if err != nil { + return "", nil, nil, fmt.Errorf("derive1PUWithOKPKey: failed to derive key: %w", err) + } + + epk := &cryptoapi.PublicKey{ + X: ephemeralPubKey, + Curve: "X25519", + Type: recPubKey.Type, + } + + return wrappingAlg, kek, epk, nil } -func derive1Pu(kwAlg string, ze, zs, apu, apv []byte, keySize int) ([]byte, error) { - z := append(ze, zs...) - algID := cryptoutil.LengthPrefix([]byte(kwAlg)) - ptyUInfo := cryptoutil.LengthPrefix(apu) - ptyVInfo := cryptoutil.LengthPrefix(apv) +func (t *Crypto) deriveESWithOKPKey(apu, apv []byte, recPubKey *cryptoapi.PublicKey, + useXC20PKW bool) (string, []byte, *cryptoapi.PublicKey, error) { + wrappingAlg := ECDHESA256KWAlg - supPubLen := 4 - supPubInfo := make([]byte, supPubLen) + if useXC20PKW { + wrappingAlg = ECDHESXC20PKWAlg + } - byteLen := 8 - binary.BigEndian.PutUint32(supPubInfo, uint32(keySize)*uint32(byteLen)) + ephemeralPubKey, ephemeralPrivKey, err := t.generateEphemeralOKPKey() + if err != nil { + return "", nil, nil, fmt.Errorf("deriveESWithOKPKey: failed to generate ephemeral key: %w", err) + } - reader := josecipher.NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, []byte{}) + ephemeralPrivChacha := new([chacha20poly1305.KeySize]byte) + copy(ephemeralPrivChacha[:], ephemeralPrivKey) - kek := make([]byte, keySize) + recPubKeyChacha := new([chacha20poly1305.KeySize]byte) + copy(recPubKeyChacha[:], recPubKey.X) - _, err := reader.Read(kek) + kek, err := cryptoutil.Derive25519KEK([]byte(wrappingAlg), apu, apv, ephemeralPrivChacha, recPubKeyChacha) if err != nil { - return nil, err + return "", nil, nil, fmt.Errorf("deriveESWithOKPKey: failed to derive 25519 kek: %w", err) } - return kek, nil + epk := &cryptoapi.PublicKey{ + X: ephemeralPubKey, + Curve: "X25519", + Type: recPubKey.Type, + } + + return wrappingAlg, kek, epk, nil +} + +// convertRecKeyAndGenEPKEC converts recPubKey into *ecdsa.PublicKey and generates an ephemeral EC private key +// as *ecdsa.PrivateKey. +func (t *Crypto) convertRecKeyAndGenEPKEC(recPubKey *cryptoapi.PublicKey) (*ecdsa.PublicKey, *ecdsa.PrivateKey, + error) { + c, err := t.ecKW.getCurve(recPubKey.Curve) + if err != nil { + return nil, nil, fmt.Errorf("convertRecKeyAndGenEPKEC: failed to get curve of recipient key: %w", + err) + } + + recECPubKey := &ecdsa.PublicKey{ + Curve: c, + X: new(big.Int).SetBytes(recPubKey.X), + Y: new(big.Int).SetBytes(recPubKey.Y), + } + + ephemeralPrivKey, err := t.ecKW.generateKey(recECPubKey.Curve) + if err != nil { + return nil, nil, fmt.Errorf("convertRecKeyAndGenEPKEC: failed to generate EPK: %w", err) + } + + return recECPubKey, ephemeralPrivKey.(*ecdsa.PrivateKey), nil +} + +func (t *Crypto) generateEphemeralOKPKey() ([]byte, []byte, error) { + ephemeralPrivKey, err := t.okpKW.generateKey(nil) + if err != nil { + return nil, nil, err + } + + ephemeralPrivKeyByte, ok := ephemeralPrivKey.([]byte) + if !ok { + return nil, nil, errors.New("invalid ephemeral key type, not OKP, want []byte for OKP") + } + + ephemeralPubKey, err := curve25519.X25519(ephemeralPrivKeyByte, curve25519.Basepoint) + if err != nil { + return nil, nil, err + } + + return ephemeralPubKey, ephemeralPrivKeyByte, nil } func ksToPrivateECDSAKey(ks interface{}) (*ecdsa.PrivateKey, error) { @@ -203,7 +481,31 @@ func ksToPrivateECDSAKey(ks interface{}) (*ecdsa.PrivateKey, error) { return nil, fmt.Errorf("ksToPrivateECDSAKey: failed to extract sender key: %w", err) } - return hybridECPrivToECDSAKey(senderHPrivKey), nil + prvKey, ok := senderHPrivKey.(*hybrid.ECPrivateKey) + if !ok { + return nil, errors.New("ksToPrivateECDSAKey: not an EC key") + } + + return hybridECPrivToECDSAKey(prvKey), nil +} + +func ksToPrivateX25519Key(ks interface{}) ([]byte, error) { + senderKH, ok := ks.(*keyset.Handle) + if !ok { + return nil, fmt.Errorf("ksToPrivateX25519Key: %w", errBadKeyHandleFormat) + } + + senderPrivKey, err := extractPrivKey(senderKH) + if err != nil { + return nil, fmt.Errorf("ksToPrivateX25519Key: failed to extract sender key: %w", err) + } + + prvKey, ok := senderPrivKey.([]byte) + if !ok { + return nil, errors.New("ksToPrivateX25519Key: not an OKP key") + } + + return prvKey, nil } func ksToPublicECDSAKey(ks interface{}, kw keyWrapper) (*ecdsa.PublicKey, error) { @@ -241,3 +543,19 @@ func ksToPublicECDSAKey(ks interface{}, kw keyWrapper) (*ecdsa.PublicKey, error) return nil, fmt.Errorf("ksToPublicECDSAKey: unsupported keyset type %+v", kst) } } + +func ksToPublicX25519Key(ks interface{}) ([]byte, error) { + switch kst := ks.(type) { + case *keyset.Handle: + sPubKey, err := keyio.ExtractPrimaryPublicKey(kst) + if err != nil { + return nil, fmt.Errorf("ksToPublicX25519Key: failed to extract public key from keyset handle: %w", err) + } + + return sPubKey.X, nil + case *cryptoapi.PublicKey: + return kst.X, nil + default: + return nil, fmt.Errorf("ksToPublicX25519Key: unsupported keyset type %+v", kst) + } +} diff --git a/pkg/crypto/tinkcrypto/key_wrapper_test.go b/pkg/crypto/tinkcrypto/key_wrapper_test.go index 38a5e744f6..cbf1abd01b 100644 --- a/pkg/crypto/tinkcrypto/key_wrapper_test.go +++ b/pkg/crypto/tinkcrypto/key_wrapper_test.go @@ -12,16 +12,22 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" + "encoding/hex" "errors" + "fmt" "testing" "github.com/google/tink/go/aead" "github.com/google/tink/go/keyset" + commonpb "github.com/google/tink/go/proto/common_go_proto" "github.com/google/tink/go/subtle/random" "github.com/stretchr/testify/require" + "golang.org/x/crypto/curve25519" + cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto" "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh" "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/keyio" + ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" ) type mockKeyWrapperSupport struct { @@ -45,34 +51,34 @@ func (w *mockKeyWrapperSupport) getCurve(curve string) (elliptic.Curve, error) { return w.getCurveVal, w.getCurveErr } -func (w *mockKeyWrapperSupport) generateKey(curve elliptic.Curve) (*ecdsa.PrivateKey, error) { +func (w *mockKeyWrapperSupport) generateKey(curve elliptic.Curve) (interface{}, error) { return w.generateKeyVal, w.generateKeyErr } -func (w *mockKeyWrapperSupport) createCipher(kek []byte) (cipher.Block, error) { +func (w *mockKeyWrapperSupport) createPrimitive(kek []byte) (interface{}, error) { return w.createCipherVal, w.createCipherErr } -func (w *mockKeyWrapperSupport) wrap(block cipher.Block, cek []byte) ([]byte, error) { +func (w *mockKeyWrapperSupport) wrap(block interface{}, cek []byte) ([]byte, error) { return w.wrapVal, w.wrapErr } -func (w *mockKeyWrapperSupport) unwrap(block cipher.Block, wrappedKey []byte) ([]byte, error) { +func (w *mockKeyWrapperSupport) unwrap(block interface{}, wrappedKey []byte) ([]byte, error) { return w.unwrapVal, w.unwrapErr } -func (w *mockKeyWrapperSupport) deriveSender1Pu(kwAlg string, apu, apv []byte, epPriv, sePrivKey *ecdsa.PrivateKey, - recPubKey *ecdsa.PublicKey, keySize int) ([]byte, error) { +func (w *mockKeyWrapperSupport) deriveSender1Pu(kwAlg string, apu, apv []byte, epPriv, sePrivKey, recPubKey interface{}, + keySize int) ([]byte, error) { return w.deriveSen1PuVal, w.deriveSen1PuErr } -func (w *mockKeyWrapperSupport) deriveRecipient1Pu(kwAlg string, apu, apv []byte, epPub, sePubKey *ecdsa.PublicKey, - recPrivKey *ecdsa.PrivateKey, keySize int) ([]byte, error) { +func (w *mockKeyWrapperSupport) deriveRecipient1Pu(kwAlg string, apu, apv []byte, epPub, sePubKey, rPrivKey interface{}, + keySize int) ([]byte, error) { return w.deriveRec1PuVal, w.deriveRec1PuErr } func TestWrapKey_Failure(t *testing.T) { - recipientKeyHandle, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKeyHandle, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) recipientKey, err := keyio.ExtractPrimaryPublicKey(recipientKeyHandle) @@ -83,37 +89,42 @@ func TestWrapKey_Failure(t *testing.T) { apv := []byte("recipient") // test WrapKey with mocked getCurve error - c := Crypto{kw: &mockKeyWrapperSupport{getCurveErr: errors.New("bad Curve")}} + c := Crypto{ecKW: &mockKeyWrapperSupport{getCurveErr: errors.New("bad Curve")}} _, err = c.WrapKey(cek, apu, apv, recipientKey) - require.EqualError(t, err, "wrapKey: failed to get curve of recipient key: bad Curve") + require.EqualError(t, err, "wrapKey: deriveKEKAndWrap: error ECDH-ES kek derivation: deriveESKEK: error "+ + "deriveESWithECKey: failed to generate ephemeral key: convertRecKeyAndGenEPKEC: failed to get curve of "+ + "recipient key: bad Curve") // test WrapKey with mocked generateKey error - c = Crypto{kw: &mockKeyWrapperSupport{generateKeyErr: errors.New("genKey failed")}} + c = Crypto{ecKW: &mockKeyWrapperSupport{generateKeyErr: errors.New("genKey failed")}} _, err = c.WrapKey(cek, apu, apv, recipientKey) - require.EqualError(t, err, "wrapKey: failed to generate EPK: genKey failed") + require.EqualError(t, err, "wrapKey: deriveKEKAndWrap: error ECDH-ES kek derivation: deriveESKEK: error "+ + "deriveESWithECKey: failed to generate ephemeral key: convertRecKeyAndGenEPKEC: failed to generate EPK: "+ + "genKey failed") epk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) - // test WrapKey with mocked createCipher error + // test WrapKey with mocked createPrimitive error c = Crypto{ - kw: &mockKeyWrapperSupport{ - createCipherErr: errors.New("createCipher failed"), + ecKW: &mockKeyWrapperSupport{ + createCipherErr: errors.New("createPrimitive failed"), generateKeyVal: epk, }, } _, err = c.WrapKey(cek, apu, apv, recipientKey) - require.EqualError(t, err, "wrapKey: failed to create new Cipher: createCipher failed") + require.EqualError(t, err, "wrapKey: deriveKEKAndWrap: failed to create new AES Cipher: createPrimitive "+ + "failed") aesCipher, err := aes.NewCipher(random.GetRandomBytes(uint32(defKeySize))) require.NoError(t, err) // test WrapKey with mocked Wrap call error c = Crypto{ - kw: &mockKeyWrapperSupport{ + ecKW: &mockKeyWrapperSupport{ createCipherVal: aesCipher, generateKeyVal: epk, wrapErr: errors.New("wrap error"), @@ -121,11 +132,11 @@ func TestWrapKey_Failure(t *testing.T) { } _, err = c.WrapKey(cek, apu, apv, recipientKey) - require.EqualError(t, err, "wrapKey: failed to wrap key: wrap error") + require.EqualError(t, err, "wrapKey: deriveKEKAndWrap: failed to AES wrap key: wrap error") } func TestUnwrapKey_Failure(t *testing.T) { - recipientKeyHandle, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKeyHandle, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) recipientKey, err := keyio.ExtractPrimaryPublicKey(recipientKeyHandle) @@ -142,28 +153,28 @@ func TestUnwrapKey_Failure(t *testing.T) { require.NoError(t, err) // test UnwrapKey with mocked getCurve error - c := Crypto{kw: &mockKeyWrapperSupport{getCurveErr: errors.New("bad Curve")}} + c := Crypto{ecKW: &mockKeyWrapperSupport{getCurveErr: errors.New("bad Curve")}} _, err = c.UnwrapKey(wpKey, recipientKeyHandle) - require.EqualError(t, err, "unwrapKey: failed to GetCurve: bad Curve") + require.EqualError(t, err, "unwrapKey: deriveKEKAndUnwrap: failed to GetCurve: bad Curve") - // test UnwrapKey with mocked createCipher error + // test UnwrapKey with mocked createPrimitive error c = Crypto{ - kw: &mockKeyWrapperSupport{ - createCipherErr: errors.New("createCipher failed"), + ecKW: &mockKeyWrapperSupport{ + createCipherErr: errors.New("createPrimitive failed"), getCurveVal: elliptic.P256(), }, } _, err = c.UnwrapKey(wpKey, recipientKeyHandle) - require.EqualError(t, err, "unwrapKey: failed to create new Cipher: createCipher failed") + require.EqualError(t, err, "unwrapKey: deriveKEKAndUnwrap: failed to create new AES Cipher: createPrimitive failed") // test UnwrapKey with mocked unwrap error aesCipher, err := aes.NewCipher(random.GetRandomBytes(uint32(defKeySize))) require.NoError(t, err) c = Crypto{ - kw: &mockKeyWrapperSupport{ + ecKW: &mockKeyWrapperSupport{ createCipherVal: aesCipher, getCurveVal: elliptic.P256(), unwrapErr: errors.New("unwrap error"), @@ -171,11 +182,11 @@ func TestUnwrapKey_Failure(t *testing.T) { } _, err = c.UnwrapKey(wpKey, recipientKeyHandle) - require.EqualError(t, err, "unwrapKey: failed to unwrap key: unwrap error") + require.EqualError(t, err, "unwrapKey: deriveKEKAndUnwrap: failed to AES unwrap key: unwrap error") } func Test_ksToPrivateECDSAKey_Failure(t *testing.T) { - recipientKey, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKey, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) recipientKeyPub, err := recipientKey.Public() @@ -184,7 +195,7 @@ func Test_ksToPrivateECDSAKey_Failure(t *testing.T) { _, err = ksToPrivateECDSAKey(recipientKeyPub) require.EqualError(t, err, "ksToPrivateECDSAKey: failed to extract sender key: extractPrivKey: "+ "can't extract unsupported private key 'type.hyperledger.org/hyperledger.aries.crypto.tink"+ - ".EcdhNistPKwAesAeadPublicKey'") + ".NistPEcdhKwPublicKey'") } func Test_ksToPublicECDSAKey_Failure(t *testing.T) { @@ -199,7 +210,7 @@ func Test_ksToPublicECDSAKey_Failure(t *testing.T) { "extractPrimaryPublicKey: failed to get public key content: exporting unencrypted secret key material "+ "is forbidden") - recipientKey, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKey, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) kw := &mockKeyWrapperSupport{ @@ -212,27 +223,85 @@ func Test_ksToPublicECDSAKey_Failure(t *testing.T) { func Test_deriveKEKAndUnwrap_Failure(t *testing.T) { c := Crypto{ - kw: &mockKeyWrapperSupport{}, + ecKW: &mockKeyWrapperSupport{}, } - _, err := c.deriveKEKAndUnwrap(ECDH1PUA256KWAlg, nil, nil, nil, nil, nil, nil) - require.EqualError(t, err, "unwrap: sender's public keyset handle option is required for 'ECDH-1PU+A256KW'") + recKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) + require.NoError(t, err) + + _, err = c.deriveKEKAndUnwrap(ECDH1PUA256KWAlg, nil, nil, nil, nil, nil, nil) + require.EqualError(t, err, "deriveKEKAndUnwrap: bad key handle format") - c.kw = &mockKeyWrapperSupport{ + _, err = c.deriveKEKAndUnwrap(ECDH1PUA256KWAlg, nil, nil, nil, nil, nil, recKH) + require.EqualError(t, err, "deriveKEKAndUnwrap: sender's public keyset handle option is required for "+ + "'ECDH-1PU+A256KW'") + + c.ecKW = &mockKeyWrapperSupport{ getCurveErr: errors.New("getCurve error"), } - senderKH, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + senderKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) - _, err = c.deriveKEKAndUnwrap(ECDH1PUA256KWAlg, nil, nil, nil, senderKH, nil, nil) - require.EqualError(t, err, "unwrapKey: failed to retrieve sender key: ksToPublicECDSAKey: failed to "+ + epk := &cryptoapi.PublicKey{ + Type: ecdhpb.KeyType_EC.String(), + } + + _, err = c.deriveKEKAndUnwrap(ECDH1PUA256KWAlg, nil, nil, nil, epk, senderKH, recKH) + require.EqualError(t, err, "deriveKEKAndUnwrap: failed to retrieve sender key: ksToPublicECDSAKey: failed to "+ "GetCurve: getCurve error") - c.kw = &mockKeyWrapperSupport{ + c.ecKW = &mockKeyWrapperSupport{ deriveRec1PuErr: errors.New("derive recipient 1pu error"), } - _, err = c.deriveKEKAndUnwrap(ECDH1PUA256KWAlg, nil, nil, nil, senderKH, nil, nil) - require.EqualError(t, err, "unwrapKey: failed to derive kek: derive recipient 1pu error") + epk.Curve = commonpb.EllipticCurveType_NIST_P256.String() + _, err = c.deriveKEKAndUnwrap(ECDH1PUA256KWAlg, nil, nil, nil, epk, senderKH, recKH) + require.EqualError(t, err, "deriveKEKAndUnwrap: failed to derive kek: derive recipient 1pu error") +} + +func TestX25519ECDHVector(t *testing.T) { + // keys from test vector found on https://tools.ietf.org/html/rfc7748#section-6.1 + alicePrivKeyHex := "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" + alicePrivKey, err := hex.DecodeString(alicePrivKeyHex) + require.NoError(t, err) + + alicePubKey, err := curve25519.X25519(alicePrivKey, curve25519.Basepoint) + require.NoError(t, err) + + alicePubKeyVectorHex := "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" + alicePubKeyVector, err := hex.DecodeString(alicePubKeyVectorHex) + require.NoError(t, err) + + require.EqualValues(t, alicePubKeyVector, alicePubKey) + require.Equal(t, alicePubKeyVectorHex, fmt.Sprintf("%x", alicePubKey)) + + bobPrivKeyHex := "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" + bobPrivKey, err := hex.DecodeString(bobPrivKeyHex) + require.NoError(t, err) + + bobPubKey, err := curve25519.X25519(bobPrivKey, curve25519.Basepoint) + require.NoError(t, err) + + bobPubKeyVectorHex := "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" + bobPubKeyVector, err := hex.DecodeString(bobPubKeyVectorHex) + require.NoError(t, err) + + require.EqualValues(t, bobPubKeyVector, bobPubKey) + require.Equal(t, bobPubKeyVectorHex, fmt.Sprintf("%x", bobPubKey)) + + sharedSecretFromAlice, err := curve25519.X25519(alicePrivKey, bobPubKey) + require.NoError(t, err) + + sharedSecretFromBob, err := curve25519.X25519(bobPrivKey, alicePubKey) + require.NoError(t, err) + + require.EqualValues(t, sharedSecretFromAlice, sharedSecretFromBob) + + sharedSecretVectorHex := "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" // nolint: gosec // test + sharedSecretVector, err := hex.DecodeString(sharedSecretVectorHex) + require.NoError(t, err) + + require.EqualValues(t, sharedSecretVector, sharedSecretFromAlice) + require.EqualValues(t, sharedSecretVector, sharedSecretFromBob) } diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh.go index b77043278c..5a33ea30a3 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh.go @@ -29,7 +29,7 @@ SPDX-License-Identifier: Apache-2.0 // // func main() { // // create recipient side keyset handle -// recKH, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) +// recKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) // if err != nil { // //handle error // } @@ -53,7 +53,7 @@ SPDX-License-Identifier: Apache-2.0 // // see pkg/crypto/tinkcrypto to see how you can wrap a shared secret (cek) // // // once a cek is created create an ECDH KH that can be used to encrypt plaintext as follows -// kt := ecdh.AES256GCMKeyTemplateWithCEK(cek) +// kt := ecdh.NISTPECDHAES256GCMKeyTemplateWithCEK(cek) // // kh, err := keyset.NewHandle(kt) // if err != nil { @@ -75,7 +75,7 @@ SPDX-License-Identifier: Apache-2.0 // } // // // to decrypt, recreate kh for the cek (once unwrapped from pkg/crypto) -// kt = ecdh.AES256GCMKeyTemplateWithCEK(cek) +// kt = ecdh.NISTPECDHAES256GCMKeyTemplateWithCEK(cek) // // kh, err = keyset.NewHandle(kt) // if err != nil { @@ -113,32 +113,12 @@ func init() { panic(fmt.Sprintf("ecdh.init() failed: %v", err)) } - err = registry.RegisterKeyManager(newECDHX25519XChachaPublicKeyManager()) + err = registry.RegisterKeyManager(newX25519ECDHKWPrivateKeyManager()) if err != nil { panic(fmt.Sprintf("ecdh.init() failed: %v", err)) } - err = registry.RegisterKeyManager(newECDHX25519XChachaPrivateKeyManager()) - if err != nil { - panic(fmt.Sprintf("ecdh.init() failed: %v", err)) - } - - err = registry.RegisterKeyManager(newECDHNISTPXChachaPrivateKeyManager()) - if err != nil { - panic(fmt.Sprintf("ecdh.init() failed: %v", err)) - } - - err = registry.RegisterKeyManager(newECDHNISTPXChachaPublicKeyManager()) - if err != nil { - panic(fmt.Sprintf("ecdh.init() failed: %v", err)) - } - - err = registry.RegisterKeyManager(newECDHX25519AESPublicKeyManager()) - if err != nil { - panic(fmt.Sprintf("ecdh.init() failed: %v", err)) - } - - err = registry.RegisterKeyManager(newECDHX25519AESPrivateKeyManager()) + err = registry.RegisterKeyManager(newX25519ECDHKWPublicKeyManager()) if err != nil { panic(fmt.Sprintf("ecdh.init() failed: %v", err)) } diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_factory_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_factory_test.go index a2069d6652..9af9d6a746 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_factory_test.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_factory_test.go @@ -47,7 +47,7 @@ func TestECDHESFactory(t *testing.T) { require.NoError(t, err) primaryPrivKey := testutil.NewKey( - testutil.NewKeyData(ecdhNISTPAESPrivateKeyTypeURL, sPrimaryPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), + testutil.NewKeyData(nistpECDHKWPrivateKeyTypeURL, sPrimaryPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), tinkpb.KeyStatusType_ENABLED, 8, tinkpb.OutputPrefixType_RAW) rawPrivProto := generateECDHAEADPrivateKey(t, c, rawPtFmt, kt, rawEncT, cek) @@ -56,7 +56,7 @@ func TestECDHESFactory(t *testing.T) { require.NoError(t, err) rawPrivKey := testutil.NewKey( - testutil.NewKeyData(ecdhNISTPAESPrivateKeyTypeURL, sRawPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), + testutil.NewKeyData(nistpECDHKWPrivateKeyTypeURL, sRawPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), tinkpb.KeyStatusType_ENABLED, 11, tinkpb.OutputPrefixType_RAW) x25519XChachaPrivProto := generateECDHAEADPrivateKey(t, commonpb.EllipticCurveType_CURVE25519, primaryPtFmt, @@ -66,7 +66,7 @@ func TestECDHESFactory(t *testing.T) { require.NoError(t, err) x25519XChachaPrivKey := testutil.NewKey( - testutil.NewKeyData(ecdhX25519XChachaPrivateKeyTypeURL, sX25519XChachaPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), + testutil.NewKeyData(x25519ECDHKWPrivateKeyTypeURL, sX25519XChachaPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), tinkpb.KeyStatusType_ENABLED, 15, tinkpb.OutputPrefixType_RAW) privKeys := []*tinkpb.Keyset_Key{primaryPrivKey, rawPrivKey, x25519XChachaPrivKey} @@ -239,7 +239,7 @@ func TestECDHESFactoryWithBadKeysetType(t *testing.T) { require.NoError(t, err) primaryPrivKey := testutil.NewKey( - testutil.NewKeyData(ecdhNISTPAESPrivateKeyTypeURL, sPrimaryPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), + testutil.NewKeyData(nistpECDHKWPrivateKeyTypeURL, sPrimaryPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), tinkpb.KeyStatusType_ENABLED, 8, tinkpb.OutputPrefixType_RAW) rawPrivProto := generateECDHAEADPrivateKey(t, c, rawPtFmt, kt, rawEncT, cek) @@ -248,7 +248,7 @@ func TestECDHESFactoryWithBadKeysetType(t *testing.T) { require.NoError(t, err) rawPrivKey := testutil.NewKey( - testutil.NewKeyData(ecdhNISTPAESPrivateKeyTypeURL, sRawPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), + testutil.NewKeyData(nistpECDHKWPrivateKeyTypeURL, sRawPriv, tinkpb.KeyData_ASYMMETRIC_PRIVATE), tinkpb.KeyStatusType_ENABLED, 11, tinkpb.OutputPrefixType_RAW) badPrivKeyProto, err := testutil.GenerateECIESAEADHKDFPrivateKey(c, commonpb.HashType_SHA256, primaryPtFmt, @@ -303,7 +303,7 @@ func TestNewEncryptPrimitiveSetFail(t *testing.T) { require.EqualError(t, err, "ecdh_factory: not a CompositeEncrypt primitive") require.Nil(t, encPrimitiveSet) - validKH, err := keyset.NewHandle(ECDH256KWAES256GCMKeyTemplate()) + validKH, err := keyset.NewHandle(NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) validPubKH, err := validKH.Public() @@ -339,7 +339,7 @@ func TestNewEncryptPrimitiveSetFail(t *testing.T) { } func TestEncryptPrimitiveSetFail(t *testing.T) { - validKH, err := keyset.NewHandle(ECDH256KWAES256GCMKeyTemplate()) + validKH, err := keyset.NewHandle(NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) validPubKH, err := validKH.Public() @@ -384,7 +384,7 @@ func TestNewDecryptPrimitiveSetFail(t *testing.T) { require.EqualError(t, err, "ecdh_factory: not a CompositeDecrypt primitive") require.Nil(t, decPrimitiveSet) - validKH, err := keyset.NewHandle(ECDH256KWAES256GCMKeyTemplate()) + validKH, err := keyset.NewHandle(NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) // primitives of a valid Private keyset.Handle do Decrypt() (while Public Handle do Encrypt()) @@ -417,7 +417,7 @@ func TestNewDecryptPrimitiveSetFail(t *testing.T) { } func TestDecryptPrimitiveSetFail(t *testing.T) { - validKH, err := keyset.NewHandle(ECDH256KWAES256GCMKeyTemplate()) + validKH, err := keyset.NewHandle(NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) validPubKH, err := validKH.Public() diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_key_template.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_key_template.go index 12b16ecedc..cd01b0eecf 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_key_template.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_key_template.go @@ -15,128 +15,69 @@ import ( ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" ) -// ECDH256KWAES256GCMKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for AES256-GCM content -// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). It is used to represent a key -// to execute the CompositeDecrypt primitive with the following parameters: -// - Content Encryption: AES256-GCM +// NISTP256ECDHKWKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for JWE content +// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). // Keys from this template represent a valid recipient public/private key pairs and can be stored in the KMS. The // recipient key represented in this key template uses the following key wrapping curve: // - NIST curve P-256. -func ECDH256KWAES256GCMKeyTemplate() *tinkpb.KeyTemplate { - return createKeyTemplate(true, true, commonpb.EllipticCurveType_NIST_P256, nil) +func NISTP256ECDHKWKeyTemplate() *tinkpb.KeyTemplate { + return createKeyTemplate(true, commonpb.EllipticCurveType_NIST_P256, nil) } -// ECDH384KWAES256GCMKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for AES256-GCM content -// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). It is used to represent a key -// to execute the CompositeDecrypt primitive with the following parameters: -// - Content Encryption: AES256-GCM +// NISTP384ECDHKWKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for JWE content +// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). // Keys from this template represent a valid recipient public/private key pairs and can be stored in the KMS. The // recipient key represented in this key template uses the following key wrapping curve: // - NIST curve P-384 -func ECDH384KWAES256GCMKeyTemplate() *tinkpb.KeyTemplate { - return createKeyTemplate(true, true, commonpb.EllipticCurveType_NIST_P384, nil) +func NISTP384ECDHKWKeyTemplate() *tinkpb.KeyTemplate { + return createKeyTemplate(true, commonpb.EllipticCurveType_NIST_P384, nil) } -// ECDH521KWAES256GCMKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for AES256-GCM content -// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). It is used to represent a key -// to execute the CompositeDecrypt primitive with the following parameters: -// - Content Encryption: AES256-GCM +// NISTP521ECDHKWKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for JWE content +// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). // Keys from this template represent a valid recipient public/private key pairs and can be stored in the KMS. The // recipient key represented in this key template uses the following key wrapping curve: // - NIST curve P-521 -func ECDH521KWAES256GCMKeyTemplate() *tinkpb.KeyTemplate { - return createKeyTemplate(true, true, commonpb.EllipticCurveType_NIST_P521, nil) +func NISTP521ECDHKWKeyTemplate() *tinkpb.KeyTemplate { + return createKeyTemplate(true, commonpb.EllipticCurveType_NIST_P521, nil) } -// ECDH256KWXChachaKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for XChacha20Poly1305 content -// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). It is used to represent -// a key to execute the CompositeDecrypt primitive with the following parameters: -// - Content Encryption: XChacha20Poly1305 -// Keys from this template represent a valid recipient public/private key pairs and can be stored in the KMS. The -// recipient key represented in this key template uses the following key wrapping curve: -// - NIST curve P-256. -func ECDH256KWXChachaKeyTemplate() *tinkpb.KeyTemplate { - return createKeyTemplate(true, false, commonpb.EllipticCurveType_NIST_P256, nil) -} - -// ECDH384KWXChachaKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for XChacha20Poly1305 content -// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). It is used to represent -// a key to execute the CompositeDecrypt primitive with the following parameters: -// - Content Encryption: XChacha20Poly1305 -// Keys from this template represent a valid recipient public/private key pairs and can be stored in the KMS. The -// recipient key represented in this key template uses the following key wrapping curve: -// - NIST curve P-384 -func ECDH384KWXChachaKeyTemplate() *tinkpb.KeyTemplate { - return createKeyTemplate(true, false, commonpb.EllipticCurveType_NIST_P384, nil) -} - -// ECDH521KWXChachaKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for XChacha20Poly1305 content -// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). It is used to represent -// a key to execute the CompositeDecrypt primitive with the following parameters: -// - Content Encryption: XChacha20Poly1305 -// Keys from this template represent a valid recipient public/private key pairs and can be stored in the KMS. The -// recipient key represented in this key template uses the following key wrapping curve: -// - NIST curve P-521 -func ECDH521KWXChachaKeyTemplate() *tinkpb.KeyTemplate { - return createKeyTemplate(true, false, commonpb.EllipticCurveType_NIST_P521, nil) -} - -// X25519XChachaECDHKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for XChacha20Poly1305 content -// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). It is used to represent a key -// to execute the CompositeDecrypt primitive with the following parameters: -// - Content Encryption: XChaha20Poly1305 -// Keys from this template represent a valid recipient public/private key pairs and can be stored in the KMS.The -// recipient key represented in this key template uses the following key wrapping curve: -// - Curve25519 -func X25519XChachaECDHKeyTemplate() *tinkpb.KeyTemplate { - return createKeyTemplate(false, false, commonpb.EllipticCurveType_CURVE25519, nil) -} - -// X25519AES256GCMECDHKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for AES256-GCM content -// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). It is used to represent a key -// to execute the CompositeDecrypt primitive with the following parameters: -// - Content Encryption: AES256-GCM +// X25519ECDHKWKeyTemplate is a KeyTemplate that generates a key that accepts a CEK for JWE content +// encryption. CEK wrapping is done outside of this Tink key (in the tinkcrypto service). // Keys from this template represent a valid recipient public/private key pairs and can be stored in the KMS.The // recipient key represented in this key template uses the following key wrapping curve: // - Curve25519 -func X25519AES256GCMECDHKeyTemplate() *tinkpb.KeyTemplate { - return createKeyTemplate(false, true, commonpb.EllipticCurveType_CURVE25519, nil) +func X25519ECDHKWKeyTemplate() *tinkpb.KeyTemplate { + return createKeyTemplate(false, commonpb.EllipticCurveType_CURVE25519, nil) } -// AES256GCMKeyTemplateWithCEK is similar to ECDH256KWAES256GCMKeyTemplate but adding the cek to execute the +// NISTPECDHAES256GCMKeyTemplateWithCEK is similar to NISTP256ECDHKWKeyTemplate but adding the cek to execute the // CompositeEncrypt primitive for encrypting a message targeted to one ore more recipients. KW is not executed by this // template, so it is ignored and set to NIST P Curved key by default. // Keys from this template offer valid CompositeEncrypt primitive execution only and should not be stored in the KMS. // The key created from this template has no recipient key info linked to it. It is exclusively used for primitive -// execution. -func AES256GCMKeyTemplateWithCEK(cek []byte) *tinkpb.KeyTemplate { +// execution using content encryption algorithm: +// - AES256-GCM +func NISTPECDHAES256GCMKeyTemplateWithCEK(cek []byte) *tinkpb.KeyTemplate { // the curve passed in the template below is ignored when executing the primitive, it's hardcoded to pass key // key format validation only. - return createKeyTemplate(true, true, 0, cek) + return createKeyTemplate(true, 0, cek) } -// XChachaKeyTemplateWithCEK is similar to X25519XChachaECDHKeyTemplate but adding the cek to execute the +// X25519ECDHXChachaKeyTemplateWithCEK is similar to X25519ECDHKWKeyTemplate but adding the cek to execute the // CompositeEncrypt primitive for encrypting a message targeted to one ore more recipients. // Keys from this template offer valid CompositeEncrypt primitive execution only and should not be stored in the KMS. // The key created from this template has no recipient key info linked to it. It is exclusively used for primitive -// execution. -func XChachaKeyTemplateWithCEK(cek []byte) *tinkpb.KeyTemplate { - return createKeyTemplate(false, false, 0, cek) +// execution using content encryption algorithm: +// - XChacha20Poly1305 +func X25519ECDHXChachaKeyTemplateWithCEK(cek []byte) *tinkpb.KeyTemplate { + return createKeyTemplate(false, 0, cek) } -// createKeyTemplate creates a new ECDH-AEAD key template with the set cek for primitive execution. Boolean flags used: +// createKeyTemplate creates a new ECDH-AEAD key template with the set cek for primitive execution. Boolean flag used: // - nistpKW flag to state if kw is either NIST P curves (true) or Curve25519 (false) -// - aesEnc flag to state if content encryption is either AES256-GCM (true) or XChacha20Poly1305 (false) -func createKeyTemplate(nistpKW, aesEnc bool, c commonpb.EllipticCurveType, cek []byte) *tinkpb.KeyTemplate { - var encTemplate *tinkpb.KeyTemplate - - typeURL, keyType := getTypeParams(nistpKW, aesEnc) - - if aesEnc { - encTemplate = aead.AES256GCMKeyTemplate() - } else { - encTemplate = aead.XChaCha20Poly1305KeyTemplate() - } +func createKeyTemplate(nistpKW bool, c commonpb.EllipticCurveType, cek []byte) *tinkpb.KeyTemplate { + typeURL, keyType, encTemplate := getTypeParams(nistpKW) format := &ecdhpb.EcdhAeadKeyFormat{ Params: &ecdhpb.EcdhAeadParams{ @@ -164,18 +105,10 @@ func createKeyTemplate(nistpKW, aesEnc bool, c commonpb.EllipticCurveType, cek [ } } -func getTypeParams(nispKW, aesEnc bool) (string, ecdhpb.KeyType) { +func getTypeParams(nispKW bool) (string, ecdhpb.KeyType, *tinkpb.KeyTemplate) { if nispKW { - if aesEnc { - return ecdhNISTPAESPrivateKeyTypeURL, ecdhpb.KeyType_EC - } - - return ecdhNISTPXChachaPrivateKeyTypeURL, ecdhpb.KeyType_EC - } - - if aesEnc { - return ecdhX25519AESPrivateKeyTypeURL, ecdhpb.KeyType_OKP + return nistpECDHKWPrivateKeyTypeURL, ecdhpb.KeyType_EC, aead.AES256GCMKeyTemplate() } - return ecdhX25519XChachaPrivateKeyTypeURL, ecdhpb.KeyType_OKP + return x25519ECDHKWPrivateKeyTypeURL, ecdhpb.KeyType_OKP, aead.XChaCha20Poly1305KeyTemplate() } diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_key_template_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_key_template_test.go index 6b6a95fcbd..daf8a47d05 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_key_template_test.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_key_template_test.go @@ -23,35 +23,19 @@ func TestECDHESKeyTemplateSuccess(t *testing.T) { }{ { tcName: "create ECDH NIST P-256 KW with AES256-GCM key templates test", - tmplFunc: ECDH256KWAES256GCMKeyTemplate, + tmplFunc: NISTP256ECDHKWKeyTemplate, }, { tcName: "create ECDH NIST P-384 KW AES256-GCM key templates test", - tmplFunc: ECDH384KWAES256GCMKeyTemplate, + tmplFunc: NISTP384ECDHKWKeyTemplate, }, { tcName: "create ECDH NIST P-521 KW AES256-GCM key templates test", - tmplFunc: ECDH521KWAES256GCMKeyTemplate, + tmplFunc: NISTP521ECDHKWKeyTemplate, }, { tcName: "creat ECDH X25519 KW with XChacha20Poly1305 key templates test", - tmplFunc: X25519XChachaECDHKeyTemplate, - }, - { - tcName: "create ECDH NIST P-256 KW with XChacha20Poly1305 key templates test", - tmplFunc: ECDH256KWXChachaKeyTemplate, - }, - { - tcName: "create ECDH NIST P-384 KW XChacha20Poly1305 key templates test", - tmplFunc: ECDH384KWXChachaKeyTemplate, - }, - { - tcName: "create ECDH NIST P-521 KW key XChacha20Poly1305 templates test", - tmplFunc: ECDH521KWXChachaKeyTemplate, - }, - { - tcName: "creat ECDH X25519 KW with AES256-GCM key templates test", - tmplFunc: X25519AES256GCMECDHKeyTemplate, + tmplFunc: X25519ECDHKWKeyTemplate, }, } @@ -81,9 +65,9 @@ func TestECDHESKeyTemplateSuccess(t *testing.T) { // now try to create a new KH for primitive execution and try to encrypt if strings.Contains(tc.tcName, "XChacha") { - kt = XChachaKeyTemplateWithCEK(cek) + kt = X25519ECDHXChachaKeyTemplateWithCEK(cek) } else { - kt = AES256GCMKeyTemplateWithCEK(cek) + kt = NISTPECDHAES256GCMKeyTemplateWithCEK(cek) } kh, err = keyset.NewHandle(kt) diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_public_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_public_key_manager.go deleted file mode 100644 index 6e664fcd8a..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_public_key_manager.go +++ /dev/null @@ -1,100 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "crypto/elliptic" - "errors" - "fmt" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/core/registry" - "github.com/google/tink/go/keyset" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh/subtle" - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" -) - -const ( - ecdhNISTPAESPublicKeyVersion = 0 - ecdhNISTPAESPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwAesAeadPublicKey" -) - -// common errors. -var errInvalidECDHNISTPAESPublicKey = errors.New("ecdh_nistpkw_aesaead_public_key_manager: invalid key") - -// ecdhNISTPAESPublicKeyManager is an implementation of KeyManager interface for NIST P curved key wrapping and -// AES-GCM content encryption. -// It generates new ECDHPublicKey (AES) keys and produces new instances of ECDHAEADCompositeEncrypt subtle. -type ecdhNISTPAESPublicKeyManager struct{} - -// Assert that ecdhNISTPAESPublicKeyManager implements the KeyManager interface. -var _ registry.KeyManager = (*ecdhNISTPAESPublicKeyManager)(nil) - -// newECDHNISTPAESPublicKeyManager creates a new ecdhNISTPAESPublicKeyManager. -func newECDHNISTPAESPublicKeyManager() *ecdhNISTPAESPublicKeyManager { - return new(ecdhNISTPAESPublicKeyManager) -} - -// Primitive creates an ECDHESPublicKey subtle for the given serialized ECDHESPublicKey proto. -func (km *ecdhNISTPAESPublicKeyManager) Primitive(serializedKey []byte) (interface{}, error) { - if len(serializedKey) == 0 { - return nil, errInvalidECDHNISTPAESPublicKey - } - - ecdhPubKey := new(ecdhpb.EcdhAeadPublicKey) - - err := proto.Unmarshal(serializedKey, ecdhPubKey) - if err != nil { - return nil, errInvalidECDHNISTPAESPublicKey - } - - _, err = km.validateKey(ecdhPubKey) - if err != nil { - return nil, errInvalidECDHNISTPAESPublicKey - } - - rEnc, err := composite.NewRegisterCompositeAEADEncHelper(ecdhPubKey.Params.EncParams.AeadEnc) - if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_public_key_manager: NewRegisterCompositeAEADEncHelper "+ - "failed: %w", err) - } - - return subtle.NewECDHAEADCompositeEncrypt(rEnc, ecdhPubKey.Params.EncParams.CEK), nil -} - -// DoesSupport indicates if this key manager supports the given key type. -func (km *ecdhNISTPAESPublicKeyManager) DoesSupport(typeURL string) bool { - return typeURL == ecdhNISTPAESPublicKeyTypeURL -} - -// TypeURL returns the key type of keys managed by this key manager. -func (km *ecdhNISTPAESPublicKeyManager) TypeURL() string { - return ecdhNISTPAESPublicKeyTypeURL -} - -// NewKey is not implemented for public key manager. -func (km *ecdhNISTPAESPublicKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { - return nil, errors.New("ecdh_nistpkw_aesaead_public_key_manager: NewKey not implemented") -} - -// NewKeyData is not implemented for public key manager. -func (km *ecdhNISTPAESPublicKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { - return nil, errors.New("ecdh_nistpkw_aesaead_public_key_manager: NewKeyData not implemented") -} - -// validateKey validates the given EcdhAeadPublicKey. -func (km *ecdhNISTPAESPublicKeyManager) validateKey(key *ecdhpb.EcdhAeadPublicKey) (elliptic.Curve, error) { - err := keyset.ValidateKeyVersion(key.Version, ecdhNISTPAESPublicKeyVersion) - if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_public_key_manager: invalid key: %w", err) - } - - return validateKeyFormat(key.Params) -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_private_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_key_manager.go similarity index 55% rename from pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_private_key_manager.go rename to pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_key_manager.go index f9f5e4595e..dadbd17af1 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_private_key_manager.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_key_manager.go @@ -23,50 +23,49 @@ import ( ) const ( - ecdhNISTPAESPrivateKeyVersion = 0 - ecdhNISTPAESPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwAesAeadPrivateKey" + nistpECDHKWPrivateKeyVersion = 0 + nistpECDHKWPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPrivateKey" ) // common errors. var ( - errInvalidECDHNISTPAESPrivateKey = errors.New("ecdh_nistpkw_aesaead_private_key_manager: invalid key") - errInvalidECDHNISTPAESPrivateKeyFormat = errors.New("ecdh_nistpkw_aesaead_private_key_manager: invalid key format") // nolint:lll + errInvalidNISTPECDHKWPrivateKey = errors.New("nistpkw_ecdh_private_key_manager: invalid key") + errInvalidNISTPECDHKWPrivateKeyFormat = errors.New("nistpkw_ecdh_private_key_manager: invalid key format") ) -// ecdhNISTPAESPrivateKeyManager is an implementation of PrivateKeyManager interface for NIST P curved key wrapping and -// AES-GCM content encryption. +// nistPECDHKWPrivateKeyManager is an implementation of PrivateKeyManager interface for NIST P curved key wrapping. // It generates new ECDHPrivateKey (NIST P KW) keys and produces new instances of ECDHAEADCompositeDecrypt subtle. -type ecdhNISTPAESPrivateKeyManager struct{} +type nistPECDHKWPrivateKeyManager struct{} -// Assert that ecdhNISTPAESPrivateKeyManager implements the PrivateKeyManager interface. -var _ registry.PrivateKeyManager = (*ecdhNISTPAESPrivateKeyManager)(nil) +// Assert that nistPECDHKWPrivateKeyManager implements the PrivateKeyManager interface. +var _ registry.PrivateKeyManager = (*nistPECDHKWPrivateKeyManager)(nil) -// newECDHNISTPAESPrivateKeyManager creates a new ecdhNISTPAESPrivateKeyManager. -func newECDHNISTPAESPrivateKeyManager() *ecdhNISTPAESPrivateKeyManager { - return new(ecdhNISTPAESPrivateKeyManager) +// newECDHNISTPAESPrivateKeyManager creates a new nistPECDHKWPrivateKeyManager. +func newECDHNISTPAESPrivateKeyManager() *nistPECDHKWPrivateKeyManager { + return new(nistPECDHKWPrivateKeyManager) } // Primitive creates an ECDHESPrivateKey subtle for the given serialized ECDHESPrivateKey proto. -func (km *ecdhNISTPAESPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { +func (km *nistPECDHKWPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { if len(serializedKey) == 0 { - return nil, errInvalidECDHNISTPAESPrivateKey + return nil, errInvalidNISTPECDHKWPrivateKey } key := new(ecdhpb.EcdhAeadPrivateKey) err := proto.Unmarshal(serializedKey, key) if err != nil { - return nil, errInvalidECDHNISTPAESPrivateKey + return nil, errInvalidNISTPECDHKWPrivateKey } _, err = km.validateKey(key) if err != nil { - return nil, errInvalidECDHNISTPAESPrivateKey + return nil, errInvalidNISTPECDHKWPrivateKey } rEnc, err := composite.NewRegisterCompositeAEADEncHelper(key.PublicKey.Params.EncParams.AeadEnc) if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_private_key_manager: NewRegisterCompositeAEADEncHelper "+ + return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: NewRegisterCompositeAEADEncHelper "+ "failed: %w", err) } @@ -74,33 +73,33 @@ func (km *ecdhNISTPAESPrivateKeyManager) Primitive(serializedKey []byte) (interf } // NewKey creates a new key according to the specification of ECDHESPrivateKey format. -func (km *ecdhNISTPAESPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { +func (km *nistPECDHKWPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { if len(serializedKeyFormat) == 0 { - return nil, errInvalidECDHNISTPAESPrivateKeyFormat + return nil, errInvalidNISTPECDHKWPrivateKeyFormat } keyFormat := new(ecdhpb.EcdhAeadKeyFormat) err := proto.Unmarshal(serializedKeyFormat, keyFormat) if err != nil { - return nil, errInvalidECDHNISTPAESPrivateKeyFormat + return nil, errInvalidNISTPECDHKWPrivateKeyFormat } curve, err := validateKeyFormat(keyFormat.Params) if err != nil { - return nil, errInvalidECDHNISTPAESPrivateKeyFormat + return nil, errInvalidNISTPECDHKWPrivateKeyFormat } pvt, err := hybrid.GenerateECDHKeyPair(curve) if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_private_key_manager: GenerateECDHKeyPair failed: %w", err) + return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: GenerateECDHKeyPair failed: %w", err) } return &ecdhpb.EcdhAeadPrivateKey{ - Version: ecdhNISTPAESPrivateKeyVersion, + Version: nistpECDHKWPrivateKeyVersion, KeyValue: pvt.D.Bytes(), PublicKey: &ecdhpb.EcdhAeadPublicKey{ - Version: ecdhNISTPAESPrivateKeyVersion, + Version: nistpECDHKWPrivateKeyVersion, Params: keyFormat.Params, X: pvt.PublicKey.Point.X.Bytes(), Y: pvt.PublicKey.Point.Y.Bytes(), @@ -110,7 +109,7 @@ func (km *ecdhNISTPAESPrivateKeyManager) NewKey(serializedKeyFormat []byte) (pro // NewKeyData creates a new KeyData according to the specification of ECDHESPrivateKey Format. // It should be used solely by the key management API. -func (km *ecdhNISTPAESPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { +func (km *nistPECDHKWPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { key, err := km.NewKey(serializedKeyFormat) if err != nil { return nil, err @@ -118,52 +117,52 @@ func (km *ecdhNISTPAESPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) serializedKey, err := proto.Marshal(key) if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_private_key_manager: Proto.Marshal failed: %w", err) + return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: Proto.Marshal failed: %w", err) } return &tinkpb.KeyData{ - TypeUrl: ecdhNISTPAESPrivateKeyTypeURL, + TypeUrl: nistpECDHKWPrivateKeyTypeURL, Value: serializedKey, KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, }, nil } // PublicKeyData returns the enclosed public key data of serializedPrivKey. -func (km *ecdhNISTPAESPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { +func (km *nistPECDHKWPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { privKey := new(ecdhpb.EcdhAeadPrivateKey) err := proto.Unmarshal(serializedPrivKey, privKey) if err != nil { - return nil, errInvalidECDHNISTPAESPrivateKey + return nil, errInvalidNISTPECDHKWPrivateKey } serializedPubKey, err := proto.Marshal(privKey.PublicKey) if err != nil { - return nil, errInvalidECDHNISTPAESPrivateKey + return nil, errInvalidNISTPECDHKWPrivateKey } return &tinkpb.KeyData{ - TypeUrl: ecdhNISTPAESPublicKeyTypeURL, + TypeUrl: nistpECDHKWPublicKeyTypeURL, Value: serializedPubKey, KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, }, nil } // DoesSupport indicates if this key manager supports the given key type. -func (km *ecdhNISTPAESPrivateKeyManager) DoesSupport(typeURL string) bool { - return typeURL == ecdhNISTPAESPrivateKeyTypeURL +func (km *nistPECDHKWPrivateKeyManager) DoesSupport(typeURL string) bool { + return typeURL == nistpECDHKWPrivateKeyTypeURL } // TypeURL returns the key type of keys managed by this key manager. -func (km *ecdhNISTPAESPrivateKeyManager) TypeURL() string { - return ecdhNISTPAESPrivateKeyTypeURL +func (km *nistPECDHKWPrivateKeyManager) TypeURL() string { + return nistpECDHKWPrivateKeyTypeURL } // validateKey validates the given ECDHPrivateKey and returns the KW curve. -func (km *ecdhNISTPAESPrivateKeyManager) validateKey(key *ecdhpb.EcdhAeadPrivateKey) (elliptic.Curve, error) { - err := keyset.ValidateKeyVersion(key.Version, ecdhNISTPAESPrivateKeyVersion) +func (km *nistPECDHKWPrivateKeyManager) validateKey(key *ecdhpb.EcdhAeadPrivateKey) (elliptic.Curve, error) { + err := keyset.ValidateKeyVersion(key.Version, nistpECDHKWPrivateKeyVersion) if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_private_key_manager: invalid key: %w", err) + return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: invalid key: %w", err) } return validateKeyFormat(key.PublicKey.Params) @@ -181,7 +180,7 @@ func validateKeyFormat(params *ecdhpb.EcdhAeadParams) (elliptic.Curve, error) { if params.EncParams.CEK == nil { c, err = hybrid.GetCurve(params.KwParams.CurveType.String()) if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_private_key_manager: invalid key: %w", err) + return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: invalid key: %w", err) } } else { c = elliptic.P384() @@ -189,16 +188,16 @@ func validateKeyFormat(params *ecdhpb.EcdhAeadParams) (elliptic.Curve, error) { km, err := registry.GetKeyManager(params.EncParams.AeadEnc.TypeUrl) if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_private_key_manager: GetKeyManager error: %w", err) + return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: GetKeyManager error: %w", err) } _, err = km.NewKeyData(params.EncParams.AeadEnc.Value) if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_private_key_manager: NewKeyData error: %w", err) + return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: NewKeyData error: %w", err) } if params.KwParams.KeyType.String() != ecdhpb.KeyType_EC.String() { - return nil, fmt.Errorf("ecdh_nistpkw_aesaead_private_key_manager: invalid key type %v", + return nil, fmt.Errorf("nistpkw_ecdh_private_key_manager: invalid key type %v", params.KwParams.KeyType) } diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_private_key_manager_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_key_manager_test.go similarity index 91% rename from pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_private_key_manager_test.go rename to pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_key_manager_test.go index ddf6740b60..10031932a8 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_private_key_manager_test.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_key_manager_test.go @@ -30,15 +30,15 @@ func TestECDHNISTPAESPrivateKeyManager_Primitive(t *testing.T) { t.Run("Test private key manager Primitive() with empty serialized key", func(t *testing.T) { p, err := km.Primitive([]byte("")) - require.EqualError(t, err, errInvalidECDHNISTPAESPrivateKey.Error(), - "ecdhNISTPAESPrivateKeyManager primitive from empty serialized key must fail") + require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKey.Error(), + "nistPECDHKWPrivateKeyManager primitive from empty serialized key must fail") require.Empty(t, p) }) t.Run("Test private key manager Primitive() with bad serialize key", func(t *testing.T) { p, err := km.Primitive([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHNISTPAESPrivateKey.Error(), - "ecdhNISTPAESPrivateKeyManager primitive from bad serialized key must fail") + require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKey.Error(), + "nistPECDHKWPrivateKeyManager primitive from bad serialized key must fail") require.Empty(t, p) }) @@ -169,8 +169,8 @@ func TestECDHNISTPAESPrivateKeyManager_Primitive(t *testing.T) { p, err := km.Primitive(sPrivKey) if bytes.Equal(tt.encTmp.Value, badSerializedFormat) { - require.EqualError(t, err, errInvalidECDHNISTPAESPrivateKey.Error(), - "ecdhNISTPAESPrivateKeyManager primitive from serialized key with invalid serialized key") + require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKey.Error(), + "nistPECDHKWPrivateKeyManager primitive from serialized key with invalid serialized key") require.Empty(t, p) return @@ -191,7 +191,7 @@ func TestECDHNISTPAESPrivateKeyManager_Primitive(t *testing.T) { func TestEcdhNISTPAESPrivateKeyManager_DoesSupport(t *testing.T) { km := newECDHNISTPAESPrivateKeyManager() require.False(t, km.DoesSupport("bad/url")) - require.True(t, km.DoesSupport(ecdhNISTPAESPrivateKeyTypeURL)) + require.True(t, km.DoesSupport(nistpECDHKWPrivateKeyTypeURL)) } func TestEcdhNISTPAESPrivateKeyManager_NewKey(t *testing.T) { @@ -199,13 +199,13 @@ func TestEcdhNISTPAESPrivateKeyManager_NewKey(t *testing.T) { t.Run("Test private key manager NewKey() with nil key", func(t *testing.T) { k, err := km.NewKey(nil) - require.EqualError(t, err, errInvalidECDHNISTPAESPrivateKeyFormat.Error()) + require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKeyFormat.Error()) require.Empty(t, k) }) t.Run("Test private key manager NewKey() with bad serialize key", func(t *testing.T) { p, err := km.NewKey([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHNISTPAESPrivateKeyFormat.Error(), + require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKeyFormat.Error(), "ECDHESPrivate NewKey() from bad serialized key must fail") require.Empty(t, p) }) @@ -322,14 +322,14 @@ func TestEcdhNISTPAESPrivateKeyManager_NewKey(t *testing.T) { if strings.Contains(tt.tcName, "success") { require.NoError(t, err) require.NotEmpty(t, kd) - require.Equal(t, kd.TypeUrl, ecdhNISTPAESPrivateKeyTypeURL) + require.Equal(t, kd.TypeUrl, nistpECDHKWPrivateKeyTypeURL) require.Equal(t, kd.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PRIVATE) return } if bytes.Equal(tt.encTmp.Value, badSerializedFormat) { - require.EqualError(t, err, errInvalidECDHNISTPAESPrivateKeyFormat.Error(), - "ecdhNISTPAESPrivateKeyManager NewKey from serialized key with invalid serialized key") + require.EqualError(t, err, errInvalidNISTPECDHKWPrivateKeyFormat.Error(), + "nistPECDHKWPrivateKeyManager NewKey from serialized key with invalid serialized key") require.Empty(t, p) return diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_public_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_public_key_manager.go new file mode 100644 index 0000000000..67502e62c8 --- /dev/null +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_public_key_manager.go @@ -0,0 +1,99 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package ecdh + +import ( + "crypto/elliptic" + "errors" + "fmt" + + "github.com/golang/protobuf/proto" + "github.com/google/tink/go/core/registry" + "github.com/google/tink/go/keyset" + tinkpb "github.com/google/tink/go/proto/tink_go_proto" + + "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" + "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh/subtle" + ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" +) + +const ( + nistpECDHKWPublicKeyVersion = 0 + nistpECDHKWPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPublicKey" +) + +// common errors. +var errInvalidNISTPECDHKWPublicKey = errors.New("nistpkw_ecdh_public_key_manager: invalid key") + +// nistPECDHKWPublicKeyManager is an implementation of KeyManager interface for NIST P curved key wrapping. +// It generates new ECDHPublicKey (AES) keys and produces new instances of ECDHAEADCompositeEncrypt subtle. +type nistPECDHKWPublicKeyManager struct{} + +// Assert that nistPECDHKWPublicKeyManager implements the KeyManager interface. +var _ registry.KeyManager = (*nistPECDHKWPublicKeyManager)(nil) + +// newECDHNISTPAESPublicKeyManager creates a new nistPECDHKWPublicKeyManager. +func newECDHNISTPAESPublicKeyManager() *nistPECDHKWPublicKeyManager { + return new(nistPECDHKWPublicKeyManager) +} + +// Primitive creates an ECDHESPublicKey subtle for the given serialized ECDHESPublicKey proto. +func (km *nistPECDHKWPublicKeyManager) Primitive(serializedKey []byte) (interface{}, error) { + if len(serializedKey) == 0 { + return nil, errInvalidNISTPECDHKWPublicKey + } + + ecdhPubKey := new(ecdhpb.EcdhAeadPublicKey) + + err := proto.Unmarshal(serializedKey, ecdhPubKey) + if err != nil { + return nil, errInvalidNISTPECDHKWPublicKey + } + + _, err = km.validateKey(ecdhPubKey) + if err != nil { + return nil, errInvalidNISTPECDHKWPublicKey + } + + rEnc, err := composite.NewRegisterCompositeAEADEncHelper(ecdhPubKey.Params.EncParams.AeadEnc) + if err != nil { + return nil, fmt.Errorf("nistpkw_ecdh_public_key_manager: NewRegisterCompositeAEADEncHelper "+ + "failed: %w", err) + } + + return subtle.NewECDHAEADCompositeEncrypt(rEnc, ecdhPubKey.Params.EncParams.CEK), nil +} + +// DoesSupport indicates if this key manager supports the given key type. +func (km *nistPECDHKWPublicKeyManager) DoesSupport(typeURL string) bool { + return typeURL == nistpECDHKWPublicKeyTypeURL +} + +// TypeURL returns the key type of keys managed by this key manager. +func (km *nistPECDHKWPublicKeyManager) TypeURL() string { + return nistpECDHKWPublicKeyTypeURL +} + +// NewKey is not implemented for public key manager. +func (km *nistPECDHKWPublicKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { + return nil, errors.New("nistpkw_ecdh_public_key_manager: NewKey not implemented") +} + +// NewKeyData is not implemented for public key manager. +func (km *nistPECDHKWPublicKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { + return nil, errors.New("nistpkw_ecdh_public_key_manager: NewKeyData not implemented") +} + +// validateKey validates the given EcdhAeadPublicKey. +func (km *nistPECDHKWPublicKeyManager) validateKey(key *ecdhpb.EcdhAeadPublicKey) (elliptic.Curve, error) { + err := keyset.ValidateKeyVersion(key.Version, nistpECDHKWPublicKeyVersion) + if err != nil { + return nil, fmt.Errorf("nistpkw_ecdh_public_key_manager: invalid key: %w", err) + } + + return validateKeyFormat(key.Params) +} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_public_key_manager_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_public_key_manager_test.go similarity index 92% rename from pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_public_key_manager_test.go rename to pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_public_key_manager_test.go index 1fc6927ad0..131e892a1d 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_aesaead_public_key_manager_test.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_public_key_manager_test.go @@ -29,14 +29,14 @@ func TestECDHNISTPAESPublicKeyManager_Primitive(t *testing.T) { t.Run("Test public key manager Primitive() with empty serialized key", func(t *testing.T) { p, err := km.Primitive([]byte("")) - require.EqualError(t, err, errInvalidECDHNISTPAESPublicKey.Error(), + require.EqualError(t, err, errInvalidNISTPECDHKWPublicKey.Error(), "newECDHNISTPAESPublicKeyManager primitive from empty serialized key must fail") require.Empty(t, p) }) t.Run("Test public key manager Primitive() with bad serialize key", func(t *testing.T) { p, err := km.Primitive([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHNISTPAESPublicKey.Error(), + require.EqualError(t, err, errInvalidNISTPECDHKWPublicKey.Error(), "newECDHNISTPAESPublicKeyManager primitive from bad serialized key must fail") require.Empty(t, p) }) @@ -150,7 +150,7 @@ func TestECDHNISTPAESPublicKeyManager_Primitive(t *testing.T) { p, err := km.Primitive(sPubKey) if strings.Contains(tt.tcName, "with bad content encryption key size") { - require.EqualError(t, err, errInvalidECDHNISTPAESPublicKey.Error(), + require.EqualError(t, err, errInvalidNISTPECDHKWPublicKey.Error(), "newECDHNISTPAESPublicKeyManager primitive from serialized key with invalid serialized key") require.Empty(t, p) @@ -172,7 +172,7 @@ func TestECDHNISTPAESPublicKeyManager_Primitive(t *testing.T) { func TestEcdhNISTPAESPublicKeyManager_DoesSupport(t *testing.T) { km := newECDHNISTPAESPublicKeyManager() require.False(t, km.DoesSupport("bad/url")) - require.True(t, km.DoesSupport(ecdhNISTPAESPublicKeyTypeURL)) + require.True(t, km.DoesSupport(nistpECDHKWPublicKeyTypeURL)) } func TestEcdhNISTPAESPublicKeyManager_NewKeyAndNewKeyData(t *testing.T) { @@ -180,13 +180,13 @@ func TestEcdhNISTPAESPublicKeyManager_NewKeyAndNewKeyData(t *testing.T) { t.Run("Test public key manager NewKey()", func(t *testing.T) { k, err := km.NewKey(nil) - require.EqualError(t, err, "ecdh_nistpkw_aesaead_public_key_manager: NewKey not implemented") + require.EqualError(t, err, "nistpkw_ecdh_public_key_manager: NewKey not implemented") require.Empty(t, k) }) t.Run("Test private key manager NewKeyData()", func(t *testing.T) { p, err := km.NewKeyData(nil) - require.EqualError(t, err, "ecdh_nistpkw_aesaead_public_key_manager: NewKeyData not implemented") + require.EqualError(t, err, "nistpkw_ecdh_public_key_manager: NewKeyData not implemented") require.Empty(t, p) }) } diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_private_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_private_key_manager.go deleted file mode 100644 index cbf0327295..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_private_key_manager.go +++ /dev/null @@ -1,170 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "crypto/elliptic" - "errors" - "fmt" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/core/registry" - hybrid "github.com/google/tink/go/hybrid/subtle" - "github.com/google/tink/go/keyset" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh/subtle" - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" -) - -const ( - ecdhNISTPXChachaPrivateKeyVersion = 0 - ecdhNISTPXChachaPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwXChachaAeadPrivateKey" // nolint:lll -) - -// common errors. -var ( - errInvalidECDHNISTPXChachaPrivateKey = errors.New("ecdh_nistpkw_xchachaaead_private_key_manager: invalid key") // nolint:lll - errInvalidECDHNISTPXChachaPrivateKeyFormat = errors.New("ecdh_nistpkw_xchachaaead_private_key_manager: invalid key format") // nolint:lll -) - -// ecdhNISTPXChachaPrivateKeyManager is an implementation of PrivateKeyManager interface for NIST P curved key wrapping -// and XChacha20Poly1305 content encryption. -// It generates new ECDHPrivateKey (NIST P KW) keys and produces new instances of ECDHAEADCompositeDecrypt subtle. -type ecdhNISTPXChachaPrivateKeyManager struct{} - -// Assert that ecdhNISTPXChachaPrivateKeyManager implements the PrivateKeyManager interface. -var _ registry.PrivateKeyManager = (*ecdhNISTPXChachaPrivateKeyManager)(nil) - -// newECDHNISTPXChachaPrivateKeyManager creates a new ecdhNISTPXChachaPrivateKeyManager. -func newECDHNISTPXChachaPrivateKeyManager() *ecdhNISTPXChachaPrivateKeyManager { - return new(ecdhNISTPXChachaPrivateKeyManager) -} - -// Primitive creates an ECDHESPrivateKey subtle for the given serialized ECDHESPrivateKey proto. -func (km *ecdhNISTPXChachaPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { - if len(serializedKey) == 0 { - return nil, errInvalidECDHNISTPXChachaPrivateKey - } - - key := new(ecdhpb.EcdhAeadPrivateKey) - - err := proto.Unmarshal(serializedKey, key) - if err != nil { - return nil, errInvalidECDHNISTPXChachaPrivateKey - } - - _, err = km.validateKey(key) - if err != nil { - return nil, errInvalidECDHNISTPXChachaPrivateKey - } - - rEnc, err := composite.NewRegisterCompositeAEADEncHelper(key.PublicKey.Params.EncParams.AeadEnc) - if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_xchachaaead_private_key_manager: NewRegisterCompositeAEADEncHelper "+ - "failed: %w", err) - } - - return subtle.NewECDHAEADCompositeDecrypt(rEnc, key.PublicKey.Params.EncParams.CEK), nil -} - -// NewKey creates a new key according to the specification of ECDHESPrivateKey format. -func (km *ecdhNISTPXChachaPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { - if len(serializedKeyFormat) == 0 { - return nil, errInvalidECDHNISTPXChachaPrivateKeyFormat - } - - keyFormat := new(ecdhpb.EcdhAeadKeyFormat) - - err := proto.Unmarshal(serializedKeyFormat, keyFormat) - if err != nil { - return nil, errInvalidECDHNISTPXChachaPrivateKeyFormat - } - - curve, err := validateKeyFormat(keyFormat.Params) - if err != nil { - return nil, errInvalidECDHNISTPXChachaPrivateKeyFormat - } - - pvt, err := hybrid.GenerateECDHKeyPair(curve) - if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_xchachaaead_private_key_manager: GenerateECDHKeyPair failed: %w", err) - } - - return &ecdhpb.EcdhAeadPrivateKey{ - Version: ecdhNISTPXChachaPrivateKeyVersion, - KeyValue: pvt.D.Bytes(), - PublicKey: &ecdhpb.EcdhAeadPublicKey{ - Version: ecdhNISTPXChachaPrivateKeyVersion, - Params: keyFormat.Params, - X: pvt.PublicKey.Point.X.Bytes(), - Y: pvt.PublicKey.Point.Y.Bytes(), - }, - }, nil -} - -// NewKeyData creates a new KeyData according to the specification of ECDHESPrivateKey Format. -// It should be used solely by the key management API. -func (km *ecdhNISTPXChachaPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { - key, err := km.NewKey(serializedKeyFormat) - if err != nil { - return nil, err - } - - serializedKey, err := proto.Marshal(key) - if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_xchachaaead_private_key_manager: Proto.Marshal failed: %w", err) - } - - return &tinkpb.KeyData{ - TypeUrl: ecdhNISTPXChachaPrivateKeyTypeURL, - Value: serializedKey, - KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, - }, nil -} - -// PublicKeyData returns the enclosed public key data of serializedPrivKey. -func (km *ecdhNISTPXChachaPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { - privKey := new(ecdhpb.EcdhAeadPrivateKey) - - err := proto.Unmarshal(serializedPrivKey, privKey) - if err != nil { - return nil, errInvalidECDHNISTPXChachaPrivateKey - } - - serializedPubKey, err := proto.Marshal(privKey.PublicKey) - if err != nil { - return nil, errInvalidECDHNISTPXChachaPrivateKey - } - - return &tinkpb.KeyData{ - TypeUrl: ecdhNISTPXChachaPublicKeyTypeURL, - Value: serializedPubKey, - KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, - }, nil -} - -// DoesSupport indicates if this key manager supports the given key type. -func (km *ecdhNISTPXChachaPrivateKeyManager) DoesSupport(typeURL string) bool { - return typeURL == ecdhNISTPXChachaPrivateKeyTypeURL -} - -// TypeURL returns the key type of keys managed by this key manager. -func (km *ecdhNISTPXChachaPrivateKeyManager) TypeURL() string { - return ecdhNISTPXChachaPrivateKeyTypeURL -} - -// validateKey validates the given ECDHPrivateKey and returns the KW curve. -func (km *ecdhNISTPXChachaPrivateKeyManager) validateKey(key *ecdhpb.EcdhAeadPrivateKey) (elliptic.Curve, error) { - err := keyset.ValidateKeyVersion(key.Version, ecdhNISTPXChachaPrivateKeyVersion) - if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_xchachaaead_private_key_manager: invalid key: %w", err) - } - - return validateKeyFormat(key.PublicKey.Params) -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_private_key_manager_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_private_key_manager_test.go deleted file mode 100644 index 5f2654dc8f..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_private_key_manager_test.go +++ /dev/null @@ -1,271 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "crypto/elliptic" - "crypto/rand" - "strings" - "testing" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/aead" - hybrid "github.com/google/tink/go/hybrid/subtle" - commonpb "github.com/google/tink/go/proto/common_go_proto" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - "github.com/stretchr/testify/require" - - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" -) - -func TestECDHNISTPXChachaPrivateKeyManager_Primitive(t *testing.T) { - km := newECDHNISTPXChachaPrivateKeyManager() - - t.Run("Test private key manager Primitive() with empty serialized key", func(t *testing.T) { - p, err := km.Primitive([]byte("")) - require.EqualError(t, err, errInvalidECDHNISTPXChachaPrivateKey.Error(), - "ecdhNISTPXChachaPrivateKeyManager primitive from empty serialized key must fail") - require.Empty(t, p) - }) - - t.Run("Test private key manager Primitive() with bad serialize key", func(t *testing.T) { - p, err := km.Primitive([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHNISTPXChachaPrivateKey.Error(), - "ecdhNISTPXChachaPrivateKeyManager primitive from bad serialized key must fail") - require.Empty(t, p) - }) - - flagTests := []struct { - tcName string - version uint32 - curveType commonpb.EllipticCurveType - keyType ecdhpb.KeyType - ecPtFmt commonpb.EcPointFormat - encTmp *tinkpb.KeyTemplate - }{ - { - tcName: "private key manager Primitive() using key with bad version", - version: 9999, - curveType: commonpb.EllipticCurveType_NIST_P256, - keyType: ecdhpb.KeyType_EC, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager Primitive() using key with bad curve", - version: 0, - curveType: commonpb.EllipticCurveType_UNKNOWN_CURVE, - keyType: ecdhpb.KeyType_EC, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager Primitive() using key with bad key type", - version: 0, - curveType: commonpb.EllipticCurveType_NIST_P256, - keyType: ecdhpb.KeyType_UNKNOWN_KEY_TYPE, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "success private key manager Primitive()", - version: 0, - curveType: commonpb.EllipticCurveType_NIST_P256, - keyType: ecdhpb.KeyType_EC, - ecPtFmt: commonpb.EcPointFormat_UNCOMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager Primitive() using key with bad key template URL", - version: 0, - curveType: commonpb.EllipticCurveType_NIST_P256, - keyType: ecdhpb.KeyType_EC, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: "bad.type/url/value", - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - } - - for _, tc := range flagTests { - tt := tc - t.Run("Test "+tt.tcName, func(t *testing.T) { - c := tt.curveType - encT := tt.encTmp - ptFmt := tt.ecPtFmt - v := tt.version - - // temporarily reset curvType if its unknown type so subtle.GetCurve() below doesn't fail - if tt.curveType.String() == commonpb.EllipticCurveType_UNKNOWN_CURVE.String() { - c = commonpb.EllipticCurveType_NIST_P256 - } - - crv, err := hybrid.GetCurve(c.String()) - require.NoError(t, err) - d, x, y, err := elliptic.GenerateKey(crv, rand.Reader) - require.NoError(t, err) - - // set back curvType if it was unknown to proceed with the test - if tt.curveType.String() == commonpb.EllipticCurveType_UNKNOWN_CURVE.String() { - c = tt.curveType - } - - privKeyProto := &ecdhpb.EcdhAeadPrivateKey{ - Version: v, - PublicKey: &ecdhpb.EcdhAeadPublicKey{ - Version: v, // if v > 0 to force an error when calling km.Primitive() - Params: &ecdhpb.EcdhAeadParams{ - KwParams: &ecdhpb.EcdhKwParams{ - CurveType: c, // unknown curve type to force an error when calling km.Primitive() - KeyType: tt.keyType, // invalid key type to force error when calling km.Primitive() - }, - EncParams: &ecdhpb.EcdhAeadEncParams{ - AeadEnc: encT, // invalid data enc key template to get an error when calling km.Primitive() - }, - EcPointFormat: ptFmt, - }, - X: x.Bytes(), - Y: y.Bytes(), - }, - KeyValue: d, - } - - sPrivKey, err := proto.Marshal(privKeyProto) - require.NoError(t, err) - - p, err := km.Primitive(sPrivKey) - if strings.Contains(tt.tcName, "success") { - require.NoError(t, err) - require.NotEmpty(t, p) - return - } - - require.Errorf(t, err, tt.tcName) - require.Empty(t, p) - }) - } -} - -func TestEcdhNISTPXChachaPrivateKeyManager_DoesSupport(t *testing.T) { - km := newECDHNISTPXChachaPrivateKeyManager() - require.False(t, km.DoesSupport("bad/url")) - require.True(t, km.DoesSupport(ecdhNISTPXChachaPrivateKeyTypeURL)) -} - -func TestEcdhNISTPXChachaPrivateKeyManager_NewKey(t *testing.T) { - km := newECDHNISTPXChachaPrivateKeyManager() - - t.Run("Test private key manager NewKey() with nil key", func(t *testing.T) { - k, err := km.NewKey(nil) - require.EqualError(t, err, errInvalidECDHNISTPXChachaPrivateKeyFormat.Error()) - require.Empty(t, k) - }) - - t.Run("Test private key manager NewKey() with bad serialize key", func(t *testing.T) { - p, err := km.NewKey([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHNISTPXChachaPrivateKeyFormat.Error(), - "ecdhNISTPXChachaPrivateKeyManager NewKey() from bad serialized key must fail") - require.Empty(t, p) - }) - - flagTests := []struct { - tcName string - curveType commonpb.EllipticCurveType - keyType ecdhpb.KeyType - ecPtFmt commonpb.EcPointFormat - encTmp *tinkpb.KeyTemplate - }{ - { - tcName: "success private key manager NewKey() and NewKeyData()", - curveType: commonpb.EllipticCurveType_NIST_P256, - keyType: ecdhpb.KeyType_EC, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager NewKey() and NewKeyData() using key with bad curve", - curveType: commonpb.EllipticCurveType_UNKNOWN_CURVE, - keyType: ecdhpb.KeyType_EC, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager NewKey() and NewKeyData() using key with bad key type", - curveType: commonpb.EllipticCurveType_NIST_P256, - keyType: ecdhpb.KeyType_UNKNOWN_KEY_TYPE, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager NewKey() and NewKeyData() using key with bad key template URL", - curveType: commonpb.EllipticCurveType_NIST_P256, - keyType: ecdhpb.KeyType_EC, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: "bad.type/url/value", - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - } - - for _, tc := range flagTests { - tt := tc - t.Run("Test "+tt.tcName, func(t *testing.T) { - encT := tt.encTmp - ptFmt := tt.ecPtFmt - - privKeyProto := &ecdhpb.EcdhAeadKeyFormat{ - Params: &ecdhpb.EcdhAeadParams{ - KwParams: &ecdhpb.EcdhKwParams{ - CurveType: tt.curveType, // unknown curve type to force an error when calling km.NewKey() - KeyType: tt.keyType, // unknown curve type to force an error when calling km.NewKey() - }, - EncParams: &ecdhpb.EcdhAeadEncParams{ - AeadEnc: encT, // invalid data enc key template to force an error when calling km.NewKey() - }, - EcPointFormat: ptFmt, // unknown EC Point format type to force an error when calling km.NewKey() - }, - } - - sPrivKey, err := proto.Marshal(privKeyProto) - require.NoError(t, err) - - p, err := km.NewKey(sPrivKey) - if strings.Contains(tt.tcName, "success") { - require.NoError(t, err) - require.NotEmpty(t, p) - - sp, e := proto.Marshal(p) - require.NoError(t, e) - require.NotEmpty(t, sp) - - // try PublicKeyData() with bad serialized private key - pubK, e := km.PublicKeyData([]byte("bad serialized private key")) - require.Error(t, e) - require.Empty(t, pubK) - - // try PublicKeyData() with valid serialized private key - pubK, e = km.PublicKeyData(sp) - require.NoError(t, e) - require.NotEmpty(t, pubK) - } - - kd, err := km.NewKeyData(sPrivKey) - if strings.Contains(tt.tcName, "success") { - require.NoError(t, err) - require.NotEmpty(t, kd) - require.Equal(t, kd.TypeUrl, ecdhNISTPXChachaPrivateKeyTypeURL) - require.Equal(t, kd.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PRIVATE) - return - } - - require.Errorf(t, err, tt.tcName) - require.Empty(t, p) - }) - } -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_public_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_public_key_manager.go deleted file mode 100644 index 5eabe0b68e..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_public_key_manager.go +++ /dev/null @@ -1,100 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "crypto/elliptic" - "errors" - "fmt" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/core/registry" - "github.com/google/tink/go/keyset" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh/subtle" - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" -) - -const ( - ecdhNISTPXChachaPublicKeyVersion = 0 - ecdhNISTPXChachaPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwXChachaAeadPublicKey" // nolint:lll -) - -// common errors. -var errInvalidECDHNISTPXChachaPublicKey = errors.New("ecdh_nistpkw_xchachaaead_public_key_manager: invalid key") - -// ecdhNISTPXChachaPublicKeyManager is an implementation of KeyManager interface for NIST P curved key wrapping and -// XChacha20Poly1305 content encryption. -// It generates new ECDHPublicKey (X25519) keys and produces new instances of ECDHAEADCompositeEncrypt subtle. -type ecdhNISTPXChachaPublicKeyManager struct{} - -// Assert that ecdhNISTPXChachaPublicKeyManager implements the KeyManager interface. -var _ registry.KeyManager = (*ecdhNISTPXChachaPublicKeyManager)(nil) - -// newECDHNISTPXChachaPublicKeyManager creates a new ecdhNISTPXChachaPublicKeyManager. -func newECDHNISTPXChachaPublicKeyManager() *ecdhNISTPXChachaPublicKeyManager { - return new(ecdhNISTPXChachaPublicKeyManager) -} - -// Primitive creates an ECDHESPublicKey subtle for the given serialized ECDHESPublicKey proto. -func (km *ecdhNISTPXChachaPublicKeyManager) Primitive(serializedKey []byte) (interface{}, error) { - if len(serializedKey) == 0 { - return nil, errInvalidECDHNISTPXChachaPublicKey - } - - ecdhPubKey := new(ecdhpb.EcdhAeadPublicKey) - - err := proto.Unmarshal(serializedKey, ecdhPubKey) - if err != nil { - return nil, errInvalidECDHNISTPXChachaPublicKey - } - - _, err = km.validateKey(ecdhPubKey) - if err != nil { - return nil, errInvalidECDHNISTPXChachaPublicKey - } - - rEnc, err := composite.NewRegisterCompositeAEADEncHelper(ecdhPubKey.Params.EncParams.AeadEnc) - if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_xchachaaead_public_key_manager: NewRegisterCompositeAEADEncHelper "+ - "failed: %w", err) - } - - return subtle.NewECDHAEADCompositeEncrypt(rEnc, ecdhPubKey.Params.EncParams.CEK), nil -} - -// DoesSupport indicates if this key manager supports the given key type. -func (km *ecdhNISTPXChachaPublicKeyManager) DoesSupport(typeURL string) bool { - return typeURL == ecdhNISTPXChachaPublicKeyTypeURL -} - -// TypeURL returns the key type of keys managed by this key manager. -func (km *ecdhNISTPXChachaPublicKeyManager) TypeURL() string { - return ecdhNISTPXChachaPublicKeyTypeURL -} - -// NewKey is not implemented for public key manager. -func (km *ecdhNISTPXChachaPublicKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { - return nil, errors.New("ecdh_nistpkw_xchachaaead_public_key_manager: NewKey not implemented") -} - -// NewKeyData is not implemented for public key manager. -func (km *ecdhNISTPXChachaPublicKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { - return nil, errors.New("ecdh_nistpkw_xchachaaead_public_key_manager: NewKeyData not implemented") -} - -// validateKey validates the given EcdhAeadPublicKey. -func (km *ecdhNISTPXChachaPublicKeyManager) validateKey(key *ecdhpb.EcdhAeadPublicKey) (elliptic.Curve, error) { - err := keyset.ValidateKeyVersion(key.Version, ecdhNISTPXChachaPublicKeyVersion) - if err != nil { - return nil, fmt.Errorf("ecdh_nistpkw_xchachaaead_public_key_manager: invalid key: %w", err) - } - - return validateKeyFormat(key.Params) -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_public_key_manager_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_public_key_manager_test.go deleted file mode 100644 index 9f11c07822..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_xchachaaead_public_key_manager_test.go +++ /dev/null @@ -1,165 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "crypto/elliptic" - "crypto/rand" - "strings" - "testing" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/aead" - hybrid "github.com/google/tink/go/hybrid/subtle" - commonpb "github.com/google/tink/go/proto/common_go_proto" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - "github.com/stretchr/testify/require" - - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" -) - -func TestECDHNISTPXChachaPublicKeyManager_Primitive(t *testing.T) { - km := newECDHNISTPXChachaPublicKeyManager() - - t.Run("Test public key manager Primitive() with empty serialized key", func(t *testing.T) { - p, err := km.Primitive([]byte("")) - require.EqualError(t, err, errInvalidECDHNISTPXChachaPublicKey.Error(), - "ecdhNISTPXChachaPublicKeyManager primitive from empty serialized key must fail") - require.Empty(t, p) - }) - - t.Run("Test public key manager Primitive() with bad serialize key", func(t *testing.T) { - p, err := km.Primitive([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHNISTPXChachaPublicKey.Error(), - "ecdhNISTPXChachaPublicKeyManager primitive from bad serialized key must fail") - require.Empty(t, p) - }) - - flagTests := []struct { - tcName string - version uint32 - curveType commonpb.EllipticCurveType - ecPtFmt commonpb.EcPointFormat - encTmp *tinkpb.KeyTemplate - }{ - { - tcName: "public key manager Primitive() using key with bad version", - version: 9999, - curveType: commonpb.EllipticCurveType_NIST_P256, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "public key manager Primitive() using key with bad curve", - version: 0, - curveType: commonpb.EllipticCurveType_UNKNOWN_CURVE, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "success public key manager Primitive()", - version: 0, - curveType: commonpb.EllipticCurveType_NIST_P256, - ecPtFmt: commonpb.EcPointFormat_UNCOMPRESSED, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "public key manager Primitive() using key with bad key template URL", - version: 0, - curveType: commonpb.EllipticCurveType_NIST_P256, - ecPtFmt: commonpb.EcPointFormat_COMPRESSED, - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: "bad.type/url/value", - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - } - - for _, tc := range flagTests { - tt := tc - t.Run("Test "+tt.tcName, func(t *testing.T) { - c := tt.curveType - encT := tt.encTmp - ptFmt := tt.ecPtFmt - v := tt.version - - // temporarily reset curvType if its unknown type so subtle.GetCurve() below doesn't fail - if tt.curveType.String() == commonpb.EllipticCurveType_UNKNOWN_CURVE.String() { - c = commonpb.EllipticCurveType_NIST_P256 - } - - crv, err := hybrid.GetCurve(c.String()) - require.NoError(t, err) - _, x, y, err := elliptic.GenerateKey(crv, rand.Reader) - require.NoError(t, err) - - // set back curvType if it was unknown to proceed with the test - if tt.curveType.String() == commonpb.EllipticCurveType_UNKNOWN_CURVE.String() { - c = tt.curveType - } - - pubKeyProto := &ecdhpb.EcdhAeadPublicKey{ - Version: v, // if v > 0 to force an error when calling km.Primitive() - Params: &ecdhpb.EcdhAeadParams{ - KwParams: &ecdhpb.EcdhKwParams{ - CurveType: c, // unknown curve type to force an error when calling km.Primitive() - KeyType: ecdhpb.KeyType_EC, - }, - EncParams: &ecdhpb.EcdhAeadEncParams{ - AeadEnc: encT, // invalid data enc key template to force an error when calling km.Primitive() - }, - EcPointFormat: ptFmt, // unknown EC Point format type to force an error when calling km.Primitive() - }, - X: x.Bytes(), - Y: y.Bytes(), - } - - sPubKey, err := proto.Marshal(pubKeyProto) - require.NoError(t, err) - - p, err := km.Primitive(sPubKey) - if strings.Contains(tt.tcName, "with bad content encryption key size") { - require.EqualError(t, err, errInvalidECDHNISTPXChachaPublicKey.Error(), - "ecdhNISTPXChachaPublicKeyManager primitive from serialized key with invalid serialized key") - require.Empty(t, p) - - return - } - - if strings.Contains(tt.tcName, "success") { - require.NoError(t, err) - require.NotEmpty(t, p) - return - } - - require.Errorf(t, err, tt.tcName) - require.Empty(t, p) - }) - } -} - -func TestEcdhNISTPXChachaPublicKeyManager_DoesSupport(t *testing.T) { - km := newECDHNISTPXChachaPublicKeyManager() - require.False(t, km.DoesSupport("bad/url")) - require.True(t, km.DoesSupport(ecdhNISTPXChachaPublicKeyTypeURL)) -} - -func TestEcdhNISTPXChachaPublicKeyManager_NewKeyAndNewKeyData(t *testing.T) { - km := newECDHNISTPXChachaPublicKeyManager() - - t.Run("Test public key manager NewKey()", func(t *testing.T) { - k, err := km.NewKey(nil) - require.EqualError(t, err, "ecdh_nistpkw_xchachaaead_public_key_manager: NewKey not implemented") - require.Empty(t, k) - }) - - t.Run("Test private key manager NewKeyData()", func(t *testing.T) { - p, err := km.NewKeyData(nil) - require.EqualError(t, err, "ecdh_nistpkw_xchachaaead_public_key_manager: NewKeyData not implemented") - require.Empty(t, p) - }) -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_private_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_private_key_manager.go deleted file mode 100644 index 484c1b87ef..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_private_key_manager.go +++ /dev/null @@ -1,180 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "crypto/ed25519" - "crypto/rand" - "errors" - "fmt" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/core/registry" - "github.com/google/tink/go/keyset" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh/subtle" - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" - "github.com/hyperledger/aries-framework-go/pkg/internal/cryptoutil" -) - -const ( - ecdhX25519AESPrivateKeyVersion = 0 - ecdhX25519AESPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhX25519KwAesAeadPrivateKey" -) - -// common errors. -var ( - errInvalidECDHX25519AESPrivateKey = errors.New("ecdh_x25519kw_aesaead_private_key_manager: invalid key") - errInvalidECDHX25519AESPrivateKeyFormat = errors.New("ecdh_x25519kw_aesaead_private_key_manager: invalid key format") // nolint:lll -) - -// ecdhX25519AESPrivateKeyManager is an implementation of PrivateKeyManager interface for X25519 key wrapping and -// AES-GCM content encryption. -// It generates new ECDHPrivateKey (X25519 KW) keys and produces new instances of ECDHAEADCompositeDecrypt subtle. -type ecdhX25519AESPrivateKeyManager struct{} - -// Assert that ecdhX25519AESPrivateKeyManager implements the PrivateKeyManager interface. -var _ registry.PrivateKeyManager = (*ecdhX25519AESPrivateKeyManager)(nil) - -// newECDHX25519AESPrivateKeyManager creates a new ecdhX25519AESPrivateKeyManager. -func newECDHX25519AESPrivateKeyManager() *ecdhX25519AESPrivateKeyManager { - return new(ecdhX25519AESPrivateKeyManager) -} - -// Primitive creates an ECDHESPrivateKey subtle for the given serialized ECDHESPrivateKey proto. -func (km *ecdhX25519AESPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { - if len(serializedKey) == 0 { - return nil, errInvalidECDHX25519AESPrivateKey - } - - key := new(ecdhpb.EcdhAeadPrivateKey) - - err := proto.Unmarshal(serializedKey, key) - if err != nil { - return nil, errInvalidECDHX25519AESPrivateKey - } - - err = km.validateKey(key) - if err != nil { - return nil, errInvalidECDHX25519AESPrivateKey - } - - rEnc, err := composite.NewRegisterCompositeAEADEncHelper(key.PublicKey.Params.EncParams.AeadEnc) - if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_aesaead_private_key_manager: NewRegisterCompositeAEADEncHelper "+ - "failed: %w", err) - } - - return subtle.NewECDHAEADCompositeDecrypt(rEnc, key.PublicKey.Params.EncParams.CEK), nil -} - -// NewKey creates a new key according to the specification of ECDHESPrivateKey format. -func (km *ecdhX25519AESPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { - if len(serializedKeyFormat) == 0 { - return nil, errInvalidECDHX25519AESPrivateKeyFormat - } - - keyFormat := new(ecdhpb.EcdhAeadKeyFormat) - - err := proto.Unmarshal(serializedKeyFormat, keyFormat) - if err != nil { - return nil, errInvalidECDHX25519AESPrivateKeyFormat - } - - err = validateKeyXChachaFormat(keyFormat.Params) - if err != nil { - return nil, errInvalidECDHX25519AESPrivateKeyFormat - } - - pub, pvt, err := ed25519.GenerateKey(rand.Reader) - if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_aesaead_private_key_manager: GenerateECDHKeyPair failed: %w", err) - } - - x25519Pub, err := cryptoutil.PublicEd25519toCurve25519(pub) - if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_aesaead_private_key_manager: Convert to X25519 pub key failed: %w", err) - } - - x25519Pvt, err := cryptoutil.SecretEd25519toCurve25519(pvt) - if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_aesaead_private_key_manager: Convert to X25519 priv key failed: %w", err) - } - - return &ecdhpb.EcdhAeadPrivateKey{ - Version: ecdhX25519AESPrivateKeyVersion, - KeyValue: x25519Pvt, - PublicKey: &ecdhpb.EcdhAeadPublicKey{ - Version: ecdhX25519AESPrivateKeyVersion, - Params: keyFormat.Params, - X: x25519Pub, - }, - }, nil -} - -// NewKeyData creates a new KeyData according to the specification of ECDHESPrivateKey Format. -// It should be used solely by the key management API. -func (km *ecdhX25519AESPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { - key, err := km.NewKey(serializedKeyFormat) - if err != nil { - return nil, err - } - - serializedKey, err := proto.Marshal(key) - if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_aesaead_private_key_manager: Proto.Marshal failed: %w", err) - } - - return &tinkpb.KeyData{ - TypeUrl: ecdhX25519AESPrivateKeyTypeURL, - Value: serializedKey, - KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, - }, nil -} - -// PublicKeyData returns the enclosed public key data of serializedPrivKey. -func (km *ecdhX25519AESPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { - privKey := new(ecdhpb.EcdhAeadPrivateKey) - - err := proto.Unmarshal(serializedPrivKey, privKey) - if err != nil { - return nil, errInvalidECDHX25519AESPrivateKey - } - - serializedPubKey, err := proto.Marshal(privKey.PublicKey) - if err != nil { - return nil, errInvalidECDHX25519AESPrivateKey - } - - return &tinkpb.KeyData{ - TypeUrl: ecdhX25519AESPublicKeyTypeURL, - Value: serializedPubKey, - KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, - }, nil -} - -// DoesSupport indicates if this key manager supports the given key type. -func (km *ecdhX25519AESPrivateKeyManager) DoesSupport(typeURL string) bool { - return typeURL == ecdhX25519AESPrivateKeyTypeURL -} - -// TypeURL returns the key type of keys managed by this key manager. -func (km *ecdhX25519AESPrivateKeyManager) TypeURL() string { - return ecdhX25519AESPrivateKeyTypeURL -} - -// validateKey validates the given ECDHPrivateKey and returns the KW curve. -func (km *ecdhX25519AESPrivateKeyManager) validateKey(key *ecdhpb.EcdhAeadPrivateKey) error { - err := keyset.ValidateKeyVersion(key.Version, ecdhX25519AESPrivateKeyVersion) - if err != nil { - return fmt.Errorf("ecdh_x25519kw_aesaead_private_key_manager: invalid key: %w", err) - } - - return validateKeyXChachaFormat(key.PublicKey.Params) -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_private_key_manager_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_private_key_manager_test.go deleted file mode 100644 index bddbf7644d..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_private_key_manager_test.go +++ /dev/null @@ -1,315 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "bytes" - "crypto/ed25519" - "crypto/rand" - "strings" - "testing" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/aead" - gcmpb "github.com/google/tink/go/proto/aes_gcm_go_proto" - commonpb "github.com/google/tink/go/proto/common_go_proto" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - "github.com/stretchr/testify/require" - - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" - "github.com/hyperledger/aries-framework-go/pkg/internal/cryptoutil" -) - -func TestECDHX25519AESPrivateKeyManager_Primitive(t *testing.T) { - km := newECDHX25519AESPrivateKeyManager() - - t.Run("Test private key manager Primitive() with empty serialized key", func(t *testing.T) { - p, err := km.Primitive([]byte("")) - require.EqualError(t, err, errInvalidECDHX25519AESPrivateKey.Error(), - "ecdhX25519AESPrivateKeyManager primitive from empty serialized key must fail") - require.Empty(t, p) - }) - - t.Run("Test private key manager Primitive() with bad serialize key", func(t *testing.T) { - p, err := km.Primitive([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHX25519AESPrivateKey.Error(), - "ecdhX25519AESPrivateKeyManager primitive from bad serialized key must fail") - require.Empty(t, p) - }) - - format := &gcmpb.AesGcmKeyFormat{ - KeySize: 32, - } - serializedFormat, err := proto.Marshal(format) - require.NoError(t, err) - - format = &gcmpb.AesGcmKeyFormat{ - KeySize: 99, // bad AES128GCM size - } - - badSerializedFormat, err := proto.Marshal(format) - require.NoError(t, err) - - flagTests := []struct { - tcName string - version uint32 - curveType commonpb.EllipticCurveType - keyType ecdhpb.KeyType - encTmp *tinkpb.KeyTemplate - }{ - { - tcName: "private key manager Primitive() using key with bad version", - version: 9999, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: aead.AES256GCMKeyTemplate(), - }, - { - tcName: "private key manager Primitive() using key with bad curve", - version: 0, - curveType: commonpb.EllipticCurveType_UNKNOWN_CURVE, - keyType: ecdhpb.KeyType_OKP, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager Primitive() using key with bad key type", - version: 0, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_UNKNOWN_KEY_TYPE, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "success private key manager Primitive()", - version: 0, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: aead.AES256GCMKeyTemplate(), - }, - { - tcName: "private key manager Primitive() using key with bad key template URL", - version: 0, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: "bad.type/url/value", - Value: serializedFormat, - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - { - tcName: "private key manager Primitive() using key with bad dem key size", - version: 0, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: composite.AESGCMTypeURL, - Value: badSerializedFormat, - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - } - - for _, tc := range flagTests { - tt := tc - t.Run("Test "+tt.tcName, func(t *testing.T) { - pub, pvt, err := ed25519.GenerateKey(rand.Reader) - require.NoError(t, err) - - x25519Pub, err := cryptoutil.PublicEd25519toCurve25519(pub) - require.NoError(t, err) - - x25519Pvt, err := cryptoutil.SecretEd25519toCurve25519(pvt) - require.NoError(t, err) - - params := &ecdhpb.EcdhAeadParams{ - KwParams: &ecdhpb.EcdhKwParams{ - CurveType: tt.curveType, // unknown curve to force an error when calling km.NewKey() - KeyType: tt.keyType, // invalid key type to force error when calling km.Primitive() - }, - EncParams: &ecdhpb.EcdhAeadEncParams{ - AeadEnc: tt.encTmp, - CEK: []byte{}, - }, - EcPointFormat: commonpb.EcPointFormat_UNCOMPRESSED, - } - - privKeyProto := &ecdhpb.EcdhAeadPrivateKey{ - Version: tt.version, - KeyValue: x25519Pvt, - PublicKey: &ecdhpb.EcdhAeadPublicKey{ - Version: ecdhX25519AESPrivateKeyVersion, - Params: params, - X: x25519Pub, - }, - } - - sPrivKey, err := proto.Marshal(privKeyProto) - require.NoError(t, err) - - p, err := km.Primitive(sPrivKey) - if bytes.Equal(tt.encTmp.Value, badSerializedFormat) { - require.EqualError(t, err, errInvalidECDHX25519AESPrivateKey.Error(), - "ecdhX25519AESPrivateKeyManager primitive from serialized key with invalid serialized key") - require.Empty(t, p) - - return - } - - if strings.Contains(tt.tcName, "success") { - require.NoError(t, err) - require.NotEmpty(t, p) - return - } - - require.Errorf(t, err, tt.tcName) - require.Empty(t, p) - }) - } -} - -func TestECDHX25519AESPrivateKeyManager_DoesSupport(t *testing.T) { - km := newECDHX25519AESPrivateKeyManager() - require.False(t, km.DoesSupport("bad/url")) - require.True(t, km.DoesSupport(ecdhX25519AESPrivateKeyTypeURL)) -} - -func TestECDHX25519AESPrivateKeyManager_NewKey(t *testing.T) { - km := newECDHX25519AESPrivateKeyManager() - - t.Run("Test private key manager NewKey() with nil key", func(t *testing.T) { - k, err := km.NewKey(nil) - require.EqualError(t, err, errInvalidECDHX25519AESPrivateKeyFormat.Error()) - require.Empty(t, k) - }) - - t.Run("Test private key manager NewKey() with bad serialize key", func(t *testing.T) { - p, err := km.NewKey([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHX25519AESPrivateKeyFormat.Error(), - "ecdhX25519AESPrivateKeyManager NewKey() from bad serialized key must fail") - require.Empty(t, p) - }) - - format := &gcmpb.AesGcmKeyFormat{ - KeySize: 32, - } - - serializedFormat, err := proto.Marshal(format) - require.NoError(t, err) - - format = &gcmpb.AesGcmKeyFormat{ - KeySize: 99, // bad AES128GCM size - } - - badSerializedFormat, err := proto.Marshal(format) - require.NoError(t, err) - - flagTests := []struct { - tcName string - curveType commonpb.EllipticCurveType - keyType ecdhpb.KeyType - encTmp *tinkpb.KeyTemplate - }{ - { - tcName: "success private key manager NewKey() and NewKeyData()", - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: aead.AES256GCMKeyTemplate(), - }, - { - tcName: "private key manager NewKey() and NewKeyData() using key with bad curve", - curveType: commonpb.EllipticCurveType_UNKNOWN_CURVE, - keyType: ecdhpb.KeyType_OKP, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager NewKey() and NewKeyData() using key with bad key type", - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_UNKNOWN_KEY_TYPE, - encTmp: aead.AES256GCMKeyTemplate(), - }, - { - tcName: "private key manager NewKey() and NewKeyData() using key with bad key template URL", - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: "bad.type/url/value", - Value: serializedFormat, - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - { - tcName: "private key manager NewKey() and NewKeyData() using key with bad dem key size", - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: composite.AESGCMTypeURL, - Value: badSerializedFormat, - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - } - - for _, tc := range flagTests { - tt := tc - t.Run("Test "+tt.tcName, func(t *testing.T) { - privKeyProto := &ecdhpb.EcdhAeadKeyFormat{ - Params: &ecdhpb.EcdhAeadParams{ - KwParams: &ecdhpb.EcdhKwParams{ - CurveType: tt.curveType, // unknown curve to force an error when calling km.NewKey() - KeyType: tt.keyType, // unknown curve type to force an error when calling km.NewKey() - }, - EncParams: &ecdhpb.EcdhAeadEncParams{ - AeadEnc: tt.encTmp, // invalid data enc key template to force an error when calling km.NewKey() - }, - EcPointFormat: commonpb.EcPointFormat_UNCOMPRESSED, - }, - } - - sPrivKey, err := proto.Marshal(privKeyProto) - require.NoError(t, err) - - p, err := km.NewKey(sPrivKey) - if strings.Contains(tt.tcName, "success") { - require.NoError(t, err) - require.NotEmpty(t, p) - - sp, e := proto.Marshal(p) - require.NoError(t, e) - require.NotEmpty(t, sp) - - // try PublicKeyData() with bad serialized private key - pubK, e := km.PublicKeyData([]byte("bad serialized private key")) - require.Error(t, e) - require.Empty(t, pubK) - - // try PublicKeyData() with valid serialized private key - pubK, e = km.PublicKeyData(sp) - require.NoError(t, e) - require.NotEmpty(t, pubK) - } - - kd, err := km.NewKeyData(sPrivKey) - if strings.Contains(tt.tcName, "success") { - require.NoError(t, err) - require.NotEmpty(t, kd) - require.Equal(t, kd.TypeUrl, ecdhX25519AESPrivateKeyTypeURL) - require.Equal(t, kd.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PRIVATE) - return - } - - if bytes.Equal(tt.encTmp.Value, badSerializedFormat) { - require.EqualError(t, err, errInvalidECDHX25519AESPrivateKeyFormat.Error(), - "ecdhX25519AESPrivateKeyManager NewKey from serialized key with invalid serialized key") - require.Empty(t, p) - - return - } - - require.Errorf(t, err, tt.tcName) - require.Empty(t, p) - }) - } -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_public_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_public_key_manager.go deleted file mode 100644 index 7dfb3110e1..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_public_key_manager.go +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "errors" - "fmt" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/core/registry" - "github.com/google/tink/go/keyset" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh/subtle" - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" -) - -const ( - ecdhX25519AESPublicKeyVersion = 0 - ecdhX25519AESPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhX25519KwAesAeadPublicKey" -) - -// common errors. -var errInvalidECDHX25519AESPublicKey = errors.New("ecdh_x25519kw_aesaead_public_key_manager: invalid key") - -// ecdhX25519AESPublicKeyManager is an implementation of KeyManager interface for X25519 key wrapping and -// AES20Poly1305 content encryption. -// It generates new ECDHPublicKey (X25519) keys and produces new instances of ECDHAEADCompositeEncrypt subtle. -type ecdhX25519AESPublicKeyManager struct{} - -// Assert that ecdhX25519AESPublicKeyManager implements the KeyManager interface. -var _ registry.KeyManager = (*ecdhX25519AESPublicKeyManager)(nil) - -// newECDHX25519AESPublicKeyManager creates a new ecdhX25519AESPublicKeyManager. -func newECDHX25519AESPublicKeyManager() *ecdhX25519AESPublicKeyManager { - return new(ecdhX25519AESPublicKeyManager) -} - -// Primitive creates an ECDHESAESPublicKey subtle for the given serialized ECDHESAESPublicKey proto. -func (km *ecdhX25519AESPublicKeyManager) Primitive(serializedKey []byte) (interface{}, error) { - if len(serializedKey) == 0 { - return nil, errInvalidECDHX25519AESPublicKey - } - - ecdhPubKey := new(ecdhpb.EcdhAeadPublicKey) - - err := proto.Unmarshal(serializedKey, ecdhPubKey) - if err != nil { - return nil, errInvalidECDHX25519AESPublicKey - } - - err = km.validateKey(ecdhPubKey) - if err != nil { - return nil, errInvalidECDHX25519AESPublicKey - } - - rEnc, err := composite.NewRegisterCompositeAEADEncHelper(ecdhPubKey.Params.EncParams.AeadEnc) - if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_aesaead_public_key_manager: NewRegisterCompositeAEADEncHelper "+ - "failed: %w", err) - } - - return subtle.NewECDHAEADCompositeEncrypt(rEnc, ecdhPubKey.Params.EncParams.CEK), nil -} - -// DoesSupport indicates if this key manager supports the given key type. -func (km *ecdhX25519AESPublicKeyManager) DoesSupport(typeURL string) bool { - return typeURL == ecdhX25519AESPublicKeyTypeURL -} - -// TypeURL returns the key type of keys managed by this key manager. -func (km *ecdhX25519AESPublicKeyManager) TypeURL() string { - return ecdhX25519AESPublicKeyTypeURL -} - -// NewKey is not implemented for public key manager. -func (km *ecdhX25519AESPublicKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { - return nil, errors.New("ecdh_x25519kw_aesaead_public_key_manager: NewKey not implemented") -} - -// NewKeyData is not implemented for public key manager. -func (km *ecdhX25519AESPublicKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { - return nil, errors.New("ecdh_x25519kw_aesaead_public_key_manager: NewKeyData not implemented") -} - -// validateKey validates the given EcdhAeadPublicKey. -func (km *ecdhX25519AESPublicKeyManager) validateKey(key *ecdhpb.EcdhAeadPublicKey) error { - err := keyset.ValidateKeyVersion(key.Version, ecdhX25519AESPublicKeyVersion) - if err != nil { - return fmt.Errorf("ecdh_x25519kw_aesaead_public_key_manager: invalid key: %w", err) - } - - return validateKeyXChachaFormat(key.Params) -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_public_key_manager_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_public_key_manager_test.go deleted file mode 100644 index 3be1f0642c..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_aesaead_public_key_manager_test.go +++ /dev/null @@ -1,185 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "crypto/ed25519" - "crypto/rand" - "strings" - "testing" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/aead" - gcmpb "github.com/google/tink/go/proto/aes_gcm_go_proto" - commonpb "github.com/google/tink/go/proto/common_go_proto" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - "github.com/stretchr/testify/require" - - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" - "github.com/hyperledger/aries-framework-go/pkg/internal/cryptoutil" -) - -func TestECDHX25519AESPublicKeyManager_Primitive(t *testing.T) { - km := newECDHX25519AESPublicKeyManager() - - t.Run("Test public key manager Primitive() with empty serialized key", func(t *testing.T) { - p, err := km.Primitive([]byte("")) - require.EqualError(t, err, errInvalidECDHX25519AESPublicKey.Error(), - "ecdhX25519AESPublicKeyManager primitive from empty serialized key must fail") - require.Empty(t, p) - }) - - t.Run("Test public key manager Primitive() with bad serialize key", func(t *testing.T) { - p, err := km.Primitive([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHX25519AESPublicKey.Error(), - "ecdhX25519AESPublicKeyManager primitive from bad serialized key must fail") - require.Empty(t, p) - }) - - format := &gcmpb.AesGcmKeyFormat{ - KeySize: 32, - } - - serializedFormat, err := proto.Marshal(format) - require.NoError(t, err) - - format = &gcmpb.AesGcmKeyFormat{ - KeySize: 99, // bad AES128GCM size - } - - badSerializedFormat, err := proto.Marshal(format) - require.NoError(t, err) - - flagTests := []struct { - tcName string - version uint32 - curveType commonpb.EllipticCurveType - keyType ecdhpb.KeyType - encTmp *tinkpb.KeyTemplate - }{ - { - tcName: "public key manager Primitive() using key with bad version", - version: 9999, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "private key manager NewKey() and NewKeyData() using key with bad curve", - version: 0, - curveType: commonpb.EllipticCurveType_UNKNOWN_CURVE, - keyType: ecdhpb.KeyType_OKP, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "public key manager Primitive() using key with bad key type", - version: 0, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_EC, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "success public key manager Primitive()", - version: 0, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: aead.XChaCha20Poly1305KeyTemplate(), - }, - { - tcName: "public key manager Primitive() using key with bad key template URL", - version: 0, - curveType: commonpb.EllipticCurveType_CURVE25519, - keyType: ecdhpb.KeyType_OKP, - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: "bad.type/url/value", - Value: serializedFormat, - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - { - tcName: "public key manager Primitive() using key with bad content encryption key size", - version: 0, - curveType: commonpb.EllipticCurveType_CURVE25519, - encTmp: &tinkpb.KeyTemplate{ - TypeUrl: composite.AESGCMTypeURL, - Value: badSerializedFormat, - OutputPrefixType: tinkpb.OutputPrefixType_RAW, - }, - }, - } - - for _, tc := range flagTests { - tt := tc - t.Run("Test "+tt.tcName, func(t *testing.T) { - pub, _, err := ed25519.GenerateKey(rand.Reader) - require.NoError(t, err) - - x25519Pub, err := cryptoutil.PublicEd25519toCurve25519(pub) - require.NoError(t, err) - - pubKeyProto := &ecdhpb.EcdhAeadPublicKey{ - Version: tt.version, // if version > 0 to force an error when calling km.Primitive() - Params: &ecdhpb.EcdhAeadParams{ - KwParams: &ecdhpb.EcdhKwParams{ - CurveType: tt.curveType, // unknown curve to force an error when calling km.NewKey() - KeyType: tt.keyType, // invalid key type to force error when calling km.Primitive() - }, - EncParams: &ecdhpb.EcdhAeadEncParams{ - AeadEnc: tt.encTmp, // invalid data enc key template to force error when calling km.Primitive() - CEK: []byte{}, - }, - EcPointFormat: commonpb.EcPointFormat_UNCOMPRESSED, - }, - X: x25519Pub, - } - - sPubKey, err := proto.Marshal(pubKeyProto) - require.NoError(t, err) - - p, err := km.Primitive(sPubKey) - if strings.Contains(tt.tcName, "with bad content encryption key size") { - require.EqualError(t, err, errInvalidECDHX25519AESPublicKey.Error(), - "ecdhX25519AESPublicKeyManager primitive from serialized key with invalid serialized key") - require.Empty(t, p) - - return - } - - if strings.Contains(tt.tcName, "success") { - require.NoError(t, err) - require.NotEmpty(t, p) - return - } - - require.Errorf(t, err, tt.tcName) - require.Empty(t, p) - }) - } -} - -func TestEcdhX25519AESPublicKeyManager_DoesSupport(t *testing.T) { - km := newECDHX25519AESPublicKeyManager() - require.False(t, km.DoesSupport("bad/url")) - require.True(t, km.DoesSupport(ecdhX25519AESPublicKeyTypeURL)) -} - -func TestEcdhX25519AESPublicKeyManager_NewKeyAndNewKeyData(t *testing.T) { - km := newECDHX25519AESPublicKeyManager() - - t.Run("Test public key manager NewKey()", func(t *testing.T) { - k, err := km.NewKey(nil) - require.EqualError(t, err, "ecdh_x25519kw_aesaead_public_key_manager: NewKey not implemented") - require.Empty(t, k) - }) - - t.Run("Test private key manager NewKeyData()", func(t *testing.T) { - p, err := km.NewKeyData(nil) - require.EqualError(t, err, "ecdh_x25519kw_aesaead_public_key_manager: NewKeyData not implemented") - require.Empty(t, p) - }) -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_private_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_private_key_manager.go similarity index 53% rename from pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_private_key_manager.go rename to pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_private_key_manager.go index 3c901ec7a2..284b240a64 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_private_key_manager.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_private_key_manager.go @@ -25,50 +25,49 @@ import ( ) const ( - ecdhX25519XChachaPrivateKeyVersion = 0 - ecdhX25519XChachaPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhX25519KwXChachaAeadPrivateKey" // nolint:lll + x25519ECDHKWPrivateKeyVersion = 0 + x25519ECDHKWPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.X25519EcdhKwPrivateKey" ) // common errors. var ( - errInvalidECDHX25519XChachaPrivateKey = errors.New("ecdh_x25519kw_xchachaaead_private_key_manager: invalid key") // nolint:lll - errInvalidECDHX25519XChachaPrivateKeyFormat = errors.New("ecdh_x25519kw_xchachaaead_private_key_manager: invalid key format") // nolint:lll + errInvalidx25519ECDHKWPrivateKey = errors.New("x25519kw_ecdh_private_key_manager: invalid key") + errInvalidx25519ECDHKWPrivateKeyFormat = errors.New("x25519kw_ecdh_private_key_manager: invalid key format") ) -// ecdhX25519XChachaPrivateKeyManager is an implementation of PrivateKeyManager interface for X25519 key wrapping and -// XChacha20Poly1305 content encryption. +// x25519ECDHKWPrivateKeyManager is an implementation of PrivateKeyManager interface for X25519 key wrapping. // It generates new ECDHPrivateKey (X25519 KW) keys and produces new instances of ECDHAEADCompositeDecrypt subtle. -type ecdhX25519XChachaPrivateKeyManager struct{} +type x25519ECDHKWPrivateKeyManager struct{} -// Assert that ecdhX25519XChachaPrivateKeyManager implements the PrivateKeyManager interface. -var _ registry.PrivateKeyManager = (*ecdhX25519XChachaPrivateKeyManager)(nil) +// Assert that x25519ECDHKWPrivateKeyManager implements the PrivateKeyManager interface. +var _ registry.PrivateKeyManager = (*x25519ECDHKWPrivateKeyManager)(nil) -// newECDHX25519XChachaPrivateKeyManager creates a new ecdhX25519XChachaPrivateKeyManager. -func newECDHX25519XChachaPrivateKeyManager() *ecdhX25519XChachaPrivateKeyManager { - return new(ecdhX25519XChachaPrivateKeyManager) +// newX25519ECDHKWPrivateKeyManager creates a new x25519ECDHKWPrivateKeyManager. +func newX25519ECDHKWPrivateKeyManager() *x25519ECDHKWPrivateKeyManager { + return new(x25519ECDHKWPrivateKeyManager) } // Primitive creates an ECDHESPrivateKey subtle for the given serialized ECDHESPrivateKey proto. -func (km *ecdhX25519XChachaPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { +func (km *x25519ECDHKWPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) { if len(serializedKey) == 0 { - return nil, errInvalidECDHX25519XChachaPrivateKey + return nil, errInvalidx25519ECDHKWPrivateKey } key := new(ecdhpb.EcdhAeadPrivateKey) err := proto.Unmarshal(serializedKey, key) if err != nil { - return nil, errInvalidECDHX25519XChachaPrivateKey + return nil, errInvalidx25519ECDHKWPrivateKey } err = km.validateKey(key) if err != nil { - return nil, errInvalidECDHX25519XChachaPrivateKey + return nil, errInvalidx25519ECDHKWPrivateKey } rEnc, err := composite.NewRegisterCompositeAEADEncHelper(key.PublicKey.Params.EncParams.AeadEnc) if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: NewRegisterCompositeAEADEncHelper "+ + return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: NewRegisterCompositeAEADEncHelper "+ "failed: %w", err) } @@ -76,43 +75,43 @@ func (km *ecdhX25519XChachaPrivateKeyManager) Primitive(serializedKey []byte) (i } // NewKey creates a new key according to the specification of ECDHESPrivateKey format. -func (km *ecdhX25519XChachaPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { +func (km *x25519ECDHKWPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { if len(serializedKeyFormat) == 0 { - return nil, errInvalidECDHX25519XChachaPrivateKeyFormat + return nil, errInvalidx25519ECDHKWPrivateKeyFormat } keyFormat := new(ecdhpb.EcdhAeadKeyFormat) err := proto.Unmarshal(serializedKeyFormat, keyFormat) if err != nil { - return nil, errInvalidECDHX25519XChachaPrivateKeyFormat + return nil, errInvalidx25519ECDHKWPrivateKeyFormat } err = validateKeyXChachaFormat(keyFormat.Params) if err != nil { - return nil, errInvalidECDHX25519XChachaPrivateKeyFormat + return nil, errInvalidx25519ECDHKWPrivateKeyFormat } pub, pvt, err := ed25519.GenerateKey(rand.Reader) if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: GenerateECDHKeyPair failed: %w", err) + return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: GenerateECDHKeyPair failed: %w", err) } x25519Pub, err := cryptoutil.PublicEd25519toCurve25519(pub) if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: Convert to X25519 pub key failed: %w", err) + return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: Convert to X25519 pub key failed: %w", err) } x25519Pvt, err := cryptoutil.SecretEd25519toCurve25519(pvt) if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: Convert to X25519 priv key failed: %w", err) + return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: Convert to X25519 priv key failed: %w", err) } return &ecdhpb.EcdhAeadPrivateKey{ - Version: ecdhX25519XChachaPrivateKeyVersion, + Version: x25519ECDHKWPrivateKeyVersion, KeyValue: x25519Pvt, PublicKey: &ecdhpb.EcdhAeadPublicKey{ - Version: ecdhX25519XChachaPrivateKeyVersion, + Version: x25519ECDHKWPrivateKeyVersion, Params: keyFormat.Params, X: x25519Pub, }, @@ -121,7 +120,7 @@ func (km *ecdhX25519XChachaPrivateKeyManager) NewKey(serializedKeyFormat []byte) // NewKeyData creates a new KeyData according to the specification of ECDHESPrivateKey Format. // It should be used solely by the key management API. -func (km *ecdhX25519XChachaPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { +func (km *x25519ECDHKWPrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { key, err := km.NewKey(serializedKeyFormat) if err != nil { return nil, err @@ -129,52 +128,52 @@ func (km *ecdhX25519XChachaPrivateKeyManager) NewKeyData(serializedKeyFormat []b serializedKey, err := proto.Marshal(key) if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: Proto.Marshal failed: %w", err) + return nil, fmt.Errorf("x25519kw_ecdh_private_key_manager: Proto.Marshal failed: %w", err) } return &tinkpb.KeyData{ - TypeUrl: ecdhX25519XChachaPrivateKeyTypeURL, + TypeUrl: x25519ECDHKWPrivateKeyTypeURL, Value: serializedKey, KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, }, nil } // PublicKeyData returns the enclosed public key data of serializedPrivKey. -func (km *ecdhX25519XChachaPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { +func (km *x25519ECDHKWPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { privKey := new(ecdhpb.EcdhAeadPrivateKey) err := proto.Unmarshal(serializedPrivKey, privKey) if err != nil { - return nil, errInvalidECDHX25519XChachaPrivateKey + return nil, errInvalidx25519ECDHKWPrivateKey } serializedPubKey, err := proto.Marshal(privKey.PublicKey) if err != nil { - return nil, errInvalidECDHX25519XChachaPrivateKey + return nil, errInvalidx25519ECDHKWPrivateKey } return &tinkpb.KeyData{ - TypeUrl: ecdhX25519XChachaPublicKeyTypeURL, + TypeUrl: x25519ECDHKWPublicKeyTypeURL, Value: serializedPubKey, KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, }, nil } // DoesSupport indicates if this key manager supports the given key type. -func (km *ecdhX25519XChachaPrivateKeyManager) DoesSupport(typeURL string) bool { - return typeURL == ecdhX25519XChachaPrivateKeyTypeURL +func (km *x25519ECDHKWPrivateKeyManager) DoesSupport(typeURL string) bool { + return typeURL == x25519ECDHKWPrivateKeyTypeURL } // TypeURL returns the key type of keys managed by this key manager. -func (km *ecdhX25519XChachaPrivateKeyManager) TypeURL() string { - return ecdhX25519XChachaPrivateKeyTypeURL +func (km *x25519ECDHKWPrivateKeyManager) TypeURL() string { + return x25519ECDHKWPrivateKeyTypeURL } // validateKey validates the given ECDHPrivateKey and returns the KW curve. -func (km *ecdhX25519XChachaPrivateKeyManager) validateKey(key *ecdhpb.EcdhAeadPrivateKey) error { - err := keyset.ValidateKeyVersion(key.Version, ecdhX25519XChachaPrivateKeyVersion) +func (km *x25519ECDHKWPrivateKeyManager) validateKey(key *ecdhpb.EcdhAeadPrivateKey) error { + err := keyset.ValidateKeyVersion(key.Version, x25519ECDHKWPrivateKeyVersion) if err != nil { - return fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: invalid key: %w", err) + return fmt.Errorf("x25519kw_ecdh_private_key_manager: invalid key: %w", err) } return validateKeyXChachaFormat(key.PublicKey.Params) @@ -186,16 +185,16 @@ func validateKeyXChachaFormat(params *ecdhpb.EcdhAeadParams) error { km, err := registry.GetKeyManager(params.EncParams.AeadEnc.TypeUrl) if err != nil { - return fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: GetKeyManager error: %w", err) + return fmt.Errorf("x25519kw_ecdh_private_key_manager: GetKeyManager error: %w", err) } _, err = km.NewKeyData(params.EncParams.AeadEnc.Value) if err != nil { - return fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: NewKeyData error: %w", err) + return fmt.Errorf("x25519kw_ecdh_private_key_manager: NewKeyData error: %w", err) } if params.KwParams.KeyType.String() != ecdhpb.KeyType_OKP.String() { - return fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: invalid key type %v", + return fmt.Errorf("x25519kw_ecdh_private_key_manager: invalid key type %v", params.KwParams.KeyType) } @@ -203,7 +202,7 @@ func validateKeyXChachaFormat(params *ecdhpb.EcdhAeadParams) error { // if it is set, then this is a primitive execution key, the curve is not needed since we do content encryption. if params.EncParams.CEK == nil && params.KwParams.CurveType.String() != commonpb.EllipticCurveType_CURVE25519.String() { - return fmt.Errorf("ecdh_x25519kw_xchachaaead_private_key_manager: invalid curve %v", + return fmt.Errorf("x25519kw_ecdh_private_key_manager: invalid curve %v", params.KwParams.CurveType) } diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_private_key_manager_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_private_key_manager_test.go similarity index 88% rename from pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_private_key_manager_test.go rename to pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_private_key_manager_test.go index bd379e2ef7..f23b4bc327 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_private_key_manager_test.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_private_key_manager_test.go @@ -23,19 +23,19 @@ import ( ) func TestECDHX25519XChachaPrivateKeyManager_Primitive(t *testing.T) { - km := newECDHX25519XChachaPrivateKeyManager() + km := newX25519ECDHKWPrivateKeyManager() t.Run("Test private key manager Primitive() with empty serialized key", func(t *testing.T) { p, err := km.Primitive([]byte("")) - require.EqualError(t, err, errInvalidECDHX25519XChachaPrivateKey.Error(), - "ecdhX25519XChachaPrivateKeyManager primitive from empty serialized key must fail") + require.EqualError(t, err, errInvalidx25519ECDHKWPrivateKey.Error(), + "x25519ECDHKWPrivateKeyManager primitive from empty serialized key must fail") require.Empty(t, p) }) t.Run("Test private key manager Primitive() with bad serialize key", func(t *testing.T) { p, err := km.Primitive([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHX25519XChachaPrivateKey.Error(), - "ecdhX25519XChachaPrivateKeyManager primitive from bad serialized key must fail") + require.EqualError(t, err, errInvalidx25519ECDHKWPrivateKey.Error(), + "x25519ECDHKWPrivateKeyManager primitive from bad serialized key must fail") require.Empty(t, p) }) @@ -114,7 +114,7 @@ func TestECDHX25519XChachaPrivateKeyManager_Primitive(t *testing.T) { Version: tt.version, KeyValue: x25519Pvt, PublicKey: &ecdhpb.EcdhAeadPublicKey{ - Version: ecdhX25519XChachaPrivateKeyVersion, + Version: x25519ECDHKWPrivateKeyVersion, Params: params, X: x25519Pub, }, @@ -137,24 +137,24 @@ func TestECDHX25519XChachaPrivateKeyManager_Primitive(t *testing.T) { } func TestECDHX25519XChachaPrivateKeyManager_DoesSupport(t *testing.T) { - km := newECDHX25519XChachaPrivateKeyManager() + km := newX25519ECDHKWPrivateKeyManager() require.False(t, km.DoesSupport("bad/url")) - require.True(t, km.DoesSupport(ecdhX25519XChachaPrivateKeyTypeURL)) + require.True(t, km.DoesSupport(x25519ECDHKWPrivateKeyTypeURL)) } func TestECDHX25519XChachaPrivateKeyManager_NewKey(t *testing.T) { - km := newECDHX25519XChachaPrivateKeyManager() + km := newX25519ECDHKWPrivateKeyManager() t.Run("Test private key manager NewKey() with nil key", func(t *testing.T) { k, err := km.NewKey(nil) - require.EqualError(t, err, errInvalidECDHX25519XChachaPrivateKeyFormat.Error()) + require.EqualError(t, err, errInvalidx25519ECDHKWPrivateKeyFormat.Error()) require.Empty(t, k) }) t.Run("Test private key manager NewKey() with bad serialize key", func(t *testing.T) { p, err := km.NewKey([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHX25519XChachaPrivateKeyFormat.Error(), - "ecdhX25519XChachaPrivateKeyManager NewKey() from bad serialized key must fail") + require.EqualError(t, err, errInvalidx25519ECDHKWPrivateKeyFormat.Error(), + "x25519ECDHKWPrivateKeyManager NewKey() from bad serialized key must fail") require.Empty(t, p) }) @@ -236,7 +236,7 @@ func TestECDHX25519XChachaPrivateKeyManager_NewKey(t *testing.T) { if strings.Contains(tt.tcName, "success") { require.NoError(t, err) require.NotEmpty(t, kd) - require.Equal(t, kd.TypeUrl, ecdhX25519XChachaPrivateKeyTypeURL) + require.Equal(t, kd.TypeUrl, x25519ECDHKWPrivateKeyTypeURL) require.Equal(t, kd.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PRIVATE) return } diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_public_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_public_key_manager.go new file mode 100644 index 0000000000..a8596650e0 --- /dev/null +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_public_key_manager.go @@ -0,0 +1,98 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package ecdh + +import ( + "errors" + "fmt" + + "github.com/golang/protobuf/proto" + "github.com/google/tink/go/core/registry" + "github.com/google/tink/go/keyset" + tinkpb "github.com/google/tink/go/proto/tink_go_proto" + + "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" + "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh/subtle" + ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" +) + +const ( + x25519ECDHKWPublicKeyVersion = 0 + x25519ECDHKWPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.X25519EcdhKwPublicKey" +) + +// common errors. +var errInvalidx25519ECDHKWPublicKey = errors.New("x25519kw_ecdh_public_key_manager: invalid key") + +// x25519ECDHKWPublicKeyManager is an implementation of KeyManager interface for X25519 key wrapping. +// It generates new ECDHPublicKey (X25519) keys and produces new instances of ECDHAEADCompositeEncrypt subtle. +type x25519ECDHKWPublicKeyManager struct{} + +// Assert that x25519ECDHKWPublicKeyManager implements the KeyManager interface. +var _ registry.KeyManager = (*x25519ECDHKWPublicKeyManager)(nil) + +// newX25519ECDHKWPublicKeyManager creates a new x25519ECDHKWPublicKeyManager. +func newX25519ECDHKWPublicKeyManager() *x25519ECDHKWPublicKeyManager { + return new(x25519ECDHKWPublicKeyManager) +} + +// Primitive creates an ECDHESXChachaPublicKey subtle for the given serialized ECDHESXChachaPublicKey proto. +func (km *x25519ECDHKWPublicKeyManager) Primitive(serializedKey []byte) (interface{}, error) { + if len(serializedKey) == 0 { + return nil, errInvalidx25519ECDHKWPublicKey + } + + ecdhPubKey := new(ecdhpb.EcdhAeadPublicKey) + + err := proto.Unmarshal(serializedKey, ecdhPubKey) + if err != nil { + return nil, errInvalidx25519ECDHKWPublicKey + } + + err = km.validateKey(ecdhPubKey) + if err != nil { + return nil, errInvalidx25519ECDHKWPublicKey + } + + rEnc, err := composite.NewRegisterCompositeAEADEncHelper(ecdhPubKey.Params.EncParams.AeadEnc) + if err != nil { + return nil, fmt.Errorf("x25519kw_ecdh_public_key_manager: NewRegisterCompositeAEADEncHelper "+ + "failed: %w", err) + } + + return subtle.NewECDHAEADCompositeEncrypt(rEnc, ecdhPubKey.Params.EncParams.CEK), nil +} + +// DoesSupport indicates if this key manager supports the given key type. +func (km *x25519ECDHKWPublicKeyManager) DoesSupport(typeURL string) bool { + return typeURL == x25519ECDHKWPublicKeyTypeURL +} + +// TypeURL returns the key type of keys managed by this key manager. +func (km *x25519ECDHKWPublicKeyManager) TypeURL() string { + return x25519ECDHKWPublicKeyTypeURL +} + +// NewKey is not implemented for public key manager. +func (km *x25519ECDHKWPublicKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { + return nil, errors.New("x25519kw_ecdh_public_key_manager: NewKey not implemented") +} + +// NewKeyData is not implemented for public key manager. +func (km *x25519ECDHKWPublicKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { + return nil, errors.New("x25519kw_ecdh_public_key_manager: NewKeyData not implemented") +} + +// validateKey validates the given EcdhAeadPublicKey. +func (km *x25519ECDHKWPublicKeyManager) validateKey(key *ecdhpb.EcdhAeadPublicKey) error { + err := keyset.ValidateKeyVersion(key.Version, x25519ECDHKWPublicKeyVersion) + if err != nil { + return fmt.Errorf("x25519kw_ecdh_public_key_manager: invalid key: %w", err) + } + + return validateKeyXChachaFormat(key.Params) +} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_public_key_manager_test.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_public_key_manager_test.go similarity index 82% rename from pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_public_key_manager_test.go rename to pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_public_key_manager_test.go index a83d467bf1..00c8b7b977 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_public_key_manager_test.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_public_key_manager_test.go @@ -23,19 +23,19 @@ import ( ) func TestECDHX25519XChachaPublicKeyManager_Primitive(t *testing.T) { - km := newECDHX25519XChachaPublicKeyManager() + km := newX25519ECDHKWPublicKeyManager() t.Run("Test public key manager Primitive() with empty serialized key", func(t *testing.T) { p, err := km.Primitive([]byte("")) - require.EqualError(t, err, errInvalidECDHX25519XChachaPublicKey.Error(), - "ecdhX25519XChachaPublicKeyManager primitive from empty serialized key must fail") + require.EqualError(t, err, errInvalidx25519ECDHKWPublicKey.Error(), + "x25519ECDHKWPublicKeyManager primitive from empty serialized key must fail") require.Empty(t, p) }) t.Run("Test public key manager Primitive() with bad serialize key", func(t *testing.T) { p, err := km.Primitive([]byte("bad.data")) - require.EqualError(t, err, errInvalidECDHX25519XChachaPublicKey.Error(), - "ecdhX25519XChachaPublicKeyManager primitive from bad serialized key must fail") + require.EqualError(t, err, errInvalidx25519ECDHKWPublicKey.Error(), + "x25519ECDHKWPublicKeyManager primitive from bad serialized key must fail") require.Empty(t, p) }) @@ -116,8 +116,8 @@ func TestECDHX25519XChachaPublicKeyManager_Primitive(t *testing.T) { p, err := km.Primitive(sPubKey) if strings.Contains(tt.tcName, "with bad content encryption key size") { - require.EqualError(t, err, errInvalidECDHX25519XChachaPublicKey.Error(), - "ecdhX25519XChachaPublicKeyManager primitive from serialized key with invalid serialized key") + require.EqualError(t, err, errInvalidx25519ECDHKWPublicKey.Error(), + "x25519ECDHKWPublicKeyManager primitive from serialized key with invalid serialized key") require.Empty(t, p) return @@ -136,23 +136,23 @@ func TestECDHX25519XChachaPublicKeyManager_Primitive(t *testing.T) { } func TestEcdhX25519XChachaPublicKeyManager_DoesSupport(t *testing.T) { - km := newECDHX25519XChachaPublicKeyManager() + km := newX25519ECDHKWPublicKeyManager() require.False(t, km.DoesSupport("bad/url")) - require.True(t, km.DoesSupport(ecdhX25519XChachaPublicKeyTypeURL)) + require.True(t, km.DoesSupport(x25519ECDHKWPublicKeyTypeURL)) } func TestEcdhX25519XChachaPublicKeyManager_NewKeyAndNewKeyData(t *testing.T) { - km := newECDHX25519XChachaPublicKeyManager() + km := newX25519ECDHKWPublicKeyManager() t.Run("Test public key manager NewKey()", func(t *testing.T) { k, err := km.NewKey(nil) - require.EqualError(t, err, "ecdh_x25519kw_xchachaaead_public_key_manager: NewKey not implemented") + require.EqualError(t, err, "x25519kw_ecdh_public_key_manager: NewKey not implemented") require.Empty(t, k) }) t.Run("Test private key manager NewKeyData()", func(t *testing.T) { p, err := km.NewKeyData(nil) - require.EqualError(t, err, "ecdh_x25519kw_xchachaaead_public_key_manager: NewKeyData not implemented") + require.EqualError(t, err, "x25519kw_ecdh_public_key_manager: NewKeyData not implemented") require.Empty(t, p) }) } diff --git a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_public_key_manager.go b/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_public_key_manager.go deleted file mode 100644 index c3ca07966c..0000000000 --- a/pkg/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_x25519kw_xchachaaead_public_key_manager.go +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package ecdh - -import ( - "errors" - "fmt" - - "github.com/golang/protobuf/proto" - "github.com/google/tink/go/core/registry" - "github.com/google/tink/go/keyset" - tinkpb "github.com/google/tink/go/proto/tink_go_proto" - - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite" - "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh/subtle" - ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" -) - -const ( - ecdhX25519XChachaPublicKeyVersion = 0 - ecdhX25519XChachaPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhX25519KwXChachaAeadPublicKey" // nolint:lll -) - -// common errors. -var errInvalidECDHX25519XChachaPublicKey = errors.New("ecdh_x25519kw_xchachaaead_public_key_manager: invalid key") - -// ecdhX25519XChachaPublicKeyManager is an implementation of KeyManager interface for X25519 key wrapping and -// XChacha20Poly1305 content encryption. -// It generates new ECDHPublicKey (X25519) keys and produces new instances of ECDHAEADCompositeEncrypt subtle. -type ecdhX25519XChachaPublicKeyManager struct{} - -// Assert that ecdhX25519XChachaPublicKeyManager implements the KeyManager interface. -var _ registry.KeyManager = (*ecdhX25519XChachaPublicKeyManager)(nil) - -// newECDHX25519XChachaPublicKeyManager creates a new ecdhX25519XChachaPublicKeyManager. -func newECDHX25519XChachaPublicKeyManager() *ecdhX25519XChachaPublicKeyManager { - return new(ecdhX25519XChachaPublicKeyManager) -} - -// Primitive creates an ECDHESXChachaPublicKey subtle for the given serialized ECDHESXChachaPublicKey proto. -func (km *ecdhX25519XChachaPublicKeyManager) Primitive(serializedKey []byte) (interface{}, error) { - if len(serializedKey) == 0 { - return nil, errInvalidECDHX25519XChachaPublicKey - } - - ecdhPubKey := new(ecdhpb.EcdhAeadPublicKey) - - err := proto.Unmarshal(serializedKey, ecdhPubKey) - if err != nil { - return nil, errInvalidECDHX25519XChachaPublicKey - } - - err = km.validateKey(ecdhPubKey) - if err != nil { - return nil, errInvalidECDHX25519XChachaPublicKey - } - - rEnc, err := composite.NewRegisterCompositeAEADEncHelper(ecdhPubKey.Params.EncParams.AeadEnc) - if err != nil { - return nil, fmt.Errorf("ecdh_x25519kw_xchachaaead_public_key_manager: NewRegisterCompositeAEADEncHelper "+ - "failed: %w", err) - } - - return subtle.NewECDHAEADCompositeEncrypt(rEnc, ecdhPubKey.Params.EncParams.CEK), nil -} - -// DoesSupport indicates if this key manager supports the given key type. -func (km *ecdhX25519XChachaPublicKeyManager) DoesSupport(typeURL string) bool { - return typeURL == ecdhX25519XChachaPublicKeyTypeURL -} - -// TypeURL returns the key type of keys managed by this key manager. -func (km *ecdhX25519XChachaPublicKeyManager) TypeURL() string { - return ecdhX25519XChachaPublicKeyTypeURL -} - -// NewKey is not implemented for public key manager. -func (km *ecdhX25519XChachaPublicKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { - return nil, errors.New("ecdh_x25519kw_xchachaaead_public_key_manager: NewKey not implemented") -} - -// NewKeyData is not implemented for public key manager. -func (km *ecdhX25519XChachaPublicKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { - return nil, errors.New("ecdh_x25519kw_xchachaaead_public_key_manager: NewKeyData not implemented") -} - -// validateKey validates the given EcdhAeadPublicKey. -func (km *ecdhX25519XChachaPublicKeyManager) validateKey(key *ecdhpb.EcdhAeadPublicKey) error { - err := keyset.ValidateKeyVersion(key.Version, ecdhX25519XChachaPublicKeyVersion) - if err != nil { - return fmt.Errorf("ecdh_x25519kw_xchachaaead_public_key_manager: invalid key: %w", err) - } - - return validateKeyXChachaFormat(key.Params) -} diff --git a/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export.go b/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export.go index 45cad9fddc..7236332b59 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export.go @@ -30,19 +30,15 @@ import ( // key (aka PublicKeyToHandle to be used as a valid Tink key) const ( - ecdhNISTPAESPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwAesAeadPublicKey" - ecdhNISTPXChachaPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwXChachaAeadPublicKey" // nolint:lll - ecdhX25519AESPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhX25519KwAesAeadPublicKey" - ecdhX25519XChachaPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhX25519KwXChachaAeadPublicKey" // nolint:lll + nistPECDHKWPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPublicKey" + x25519ECDHKWPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.X25519EcdhKwPublicKey" ) // PubKeyWriter will write the raw bytes of a Tink KeySet's primary public key. The raw bytes are a marshaled // composite.VerificationMethod type. // The keyset must have a keyURL value equal to either one of the public key URLs: -// - `ecdhNISTPAESPublicKeyTypeURL` -// - `ecdhX25519AESPublicKeyTypeURL` -// - `ecdhNISTPXChachaPublicKeyTypeURL` -// - `ecdhX25519XChachaPublicKeyTypeURL` +// - `nistPECDHKWPublicKeyTypeURL` +// - `x25519ECDHKWPublicKeyTypeURL` // constants of ecdh package. // Note: This writer should be used only for ECDH public key exports. Other export of public keys should be // called via localkms package. @@ -118,8 +114,7 @@ func protoToCompositeKey(keyData *tinkpb.KeyData) (*cryptoapi.PublicKey, error) ) switch keyData.TypeUrl { - case ecdhNISTPAESPublicKeyTypeURL, ecdhNISTPXChachaPublicKeyTypeURL, ecdhX25519AESPublicKeyTypeURL, - ecdhX25519XChachaPublicKeyTypeURL: + case nistPECDHKWPublicKeyTypeURL, x25519ECDHKWPublicKeyTypeURL: cKey, err = newECDHKey(keyData.Value) if err != nil { return nil, err @@ -248,7 +243,7 @@ func writePubKeyFromKeyHandle(handle *keyset.Handle) ([]byte, error) { // PublicKeyToKeysetHandle converts pubKey into a *keyset.Handle where pubKey could be either a sender or a recipient // key. The resulting handle cannot be directly used for primitive execution as the cek is not set. This function serves // as a helper to get a senderKH to be used as an option for ECDH execution (for ECDH-1PU/authcrypt). The keyset handle -// will be set with AES256-GCM AEAD key template for content encryption. +// will be set with AES256-GCM AEAD key template for content encryption with NIST P KW. func PublicKeyToKeysetHandle(pubKey *cryptoapi.PublicKey) (*keyset.Handle, error) { return publicKeyWithEncTemplateToKeysetHandle(pubKey, true) } @@ -256,7 +251,7 @@ func PublicKeyToKeysetHandle(pubKey *cryptoapi.PublicKey) (*keyset.Handle, error // PublicKeyToKeysetHandleXChacha converts pubKey into a *keyset.Handle where pubKey could be either a sender or a // recipient key. The resulting handle cannot be directly used for primitive execution as the cek is not set. This // as a helper to get a senderKH to be used as an option for ECDH execution (for ECDH-1PU/authcrypt). The keyset handle -// will be set with XChacha20Poly1305 AEAD key template for content encryption. +// will be set with XChacha20Poly1305 AEAD key template for content encryption with X25519 KW. func PublicKeyToKeysetHandleXChacha(pubKey *cryptoapi.PublicKey) (*keyset.Handle, error) { return publicKeyWithEncTemplateToKeysetHandle(pubKey, false) } @@ -274,13 +269,13 @@ func publicKeyWithEncTemplateToKeysetHandle(pubKey *cryptoapi.PublicKey, isAES b } encT := aead.AES256GCMKeyTemplate() + keyURL := nistPECDHKWPublicKeyTypeURL if !isAES { encT = aead.XChaCha20Poly1305KeyTemplate() + keyURL = x25519ECDHKWPublicKeyTypeURL } - keyURL := getKeyURL(isAES, kt) - protoKey := &ecdhpb.EcdhAeadPublicKey{ Version: 0, Params: &ecdhpb.EcdhAeadParams{ @@ -315,22 +310,6 @@ func publicKeyWithEncTemplateToKeysetHandle(pubKey *cryptoapi.PublicKey, isAES b return parsedHandle, nil } -func getKeyURL(aes bool, kt ecdhpb.KeyType) string { - if aes { - if kt == ecdhpb.KeyType_EC { - return ecdhNISTPAESPublicKeyTypeURL - } - - return ecdhX25519AESPublicKeyTypeURL - } - - if kt == ecdhpb.KeyType_EC { - return ecdhNISTPXChachaPublicKeyTypeURL - } - - return ecdhX25519XChachaPublicKeyTypeURL -} - func getCurveProto(c string) (commonpb.EllipticCurveType, error) { switch c { case "secp256r1", "NIST_P256", "P-256", "EllipticCurveType_NIST_P256": diff --git a/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export_import_test.go b/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export_import_test.go index 4707b2e72f..6dac0782bc 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export_import_test.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export_import_test.go @@ -8,6 +8,7 @@ package keyio import ( "bytes" + "crypto/elliptic" "encoding/json" "errors" "strings" @@ -31,36 +32,20 @@ func TestPubKeyExport(t *testing.T) { keyTemplate *tinkpb.KeyTemplate }{ { - tcName: "export then read AES256GCM with ECDH NIST P-256 public recipient key", - keyTemplate: ecdh.ECDH256KWAES256GCMKeyTemplate(), + tcName: "export then read ECDH KW NIST P-256 public recipient key", + keyTemplate: ecdh.NISTP256ECDHKWKeyTemplate(), }, { - tcName: "export then read AES256GCM with ECDH NIST P-384 public recipient key", - keyTemplate: ecdh.ECDH384KWAES256GCMKeyTemplate(), + tcName: "export then read ECDH KW NIST P-384 public recipient key", + keyTemplate: ecdh.NISTP384ECDHKWKeyTemplate(), }, { - tcName: "export then read AES256GCM with ECDH NIST P-521 public recipient key", - keyTemplate: ecdh.ECDH521KWAES256GCMKeyTemplate(), + tcName: "export then read ECDH KW NIST P-521 public recipient key", + keyTemplate: ecdh.NISTP521ECDHKWKeyTemplate(), }, { - tcName: "export then read XChacha20Poly1305 with ECDH NIST P-256 public recipient key", - keyTemplate: ecdh.ECDH256KWXChachaKeyTemplate(), - }, - { - tcName: "export then read XChacha20Poly1305 with ECDH NIST P-384 public recipient key", - keyTemplate: ecdh.ECDH384KWXChachaKeyTemplate(), - }, - { - tcName: "export then read XChacha20Poly1305 with ECDH NIST P-521 public recipient key", - keyTemplate: ecdh.ECDH521KWXChachaKeyTemplate(), - }, - { - tcName: "export then read AES256GCM with X25519 public recipient key", - keyTemplate: ecdh.X25519AES256GCMECDHKeyTemplate(), - }, - { - tcName: "export then read XChacha20Poly1305 with X25519 public recipient key", - keyTemplate: ecdh.X25519XChachaECDHKeyTemplate(), + tcName: "export then read ECDH KW X25519 public recipient key", + keyTemplate: ecdh.X25519ECDHKWKeyTemplate(), }, } @@ -167,7 +152,7 @@ func TestNegativeCases(t *testing.T) { require.NoError(t, err) _, err = protoToCompositeKey(&tinkpb.KeyData{ - TypeUrl: ecdhNISTPAESPublicKeyTypeURL, + TypeUrl: nistPECDHKWPublicKeyTypeURL, Value: mKey, KeyMaterialType: 0, }) @@ -175,7 +160,7 @@ func TestNegativeCases(t *testing.T) { }) t.Run("test WriteEncrypted() should fail since it's not supported by Writer", func(t *testing.T) { - kh, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + kh, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) require.NotEmpty(t, kh) @@ -220,7 +205,7 @@ func TestNegativeCases(t *testing.T) { Key: []*tinkpb.Keyset_Key{ { KeyData: &tinkpb.KeyData{ - TypeUrl: ecdhNISTPAESPublicKeyTypeURL, + TypeUrl: nistPECDHKWPublicKeyTypeURL, Value: mKey, KeyMaterialType: 0, }, @@ -248,6 +233,13 @@ func TestNegativeCases(t *testing.T) { require.EqualError(t, err, "publicKeyToKeysetHandle: failed to convert curve string to proto: "+ "unsupported curve") }) + + t.Run("PublicKeyToKeysetHandle using pubKey with bad keyType", func(t *testing.T) { + _, err := PublicKeyToKeysetHandle(&cryptoapi.PublicKey{ + Curve: elliptic.P256().Params().Name, + }) + require.EqualError(t, err, "publicKeyToKeysetHandle: failed to convert key type to proto: unsupported key type") + }) } type failWriter struct { diff --git a/pkg/crypto/tinkcrypto/unwrap_support.go b/pkg/crypto/tinkcrypto/unwrap_support.go index d6046f86b5..2ccea5f4e8 100644 --- a/pkg/crypto/tinkcrypto/unwrap_support.go +++ b/pkg/crypto/tinkcrypto/unwrap_support.go @@ -9,6 +9,7 @@ package tinkcrypto import ( "bytes" "crypto/ecdsa" + "crypto/elliptic" "errors" "fmt" "io" @@ -16,12 +17,13 @@ import ( "github.com/golang/protobuf/proto" hybrid "github.com/google/tink/go/hybrid/subtle" "github.com/google/tink/go/keyset" + commonpb "github.com/google/tink/go/proto/common_go_proto" tinkpb "github.com/google/tink/go/proto/tink_go_proto" ecdhpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto" ) -func extractPrivKey(kh *keyset.Handle) (*hybrid.ECPrivateKey, error) { +func extractPrivKey(kh *keyset.Handle) (interface{}, error) { buf := new(bytes.Buffer) w := &privKeyWriter{w: buf} nAEAD := &noopAEAD{} @@ -42,26 +44,43 @@ func extractPrivKey(kh *keyset.Handle) (*hybrid.ECPrivateKey, error) { return nil, errors.New("extractPrivKey: invalid private key") } - ecdhAESPrivateKeyTypeURL := "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwAesAeadPrivateKey" + ecdhNISTPAESPrivateKeyTypeURL := "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPrivateKey" + ecdhX25519XChachaPrivateKeyTypeURL := "type.hyperledger.org/hyperledger.aries.crypto.tink.X25519EcdhKwPrivateKey" primaryKey := ks.Key[0] - if primaryKey.KeyData.TypeUrl != ecdhAESPrivateKeyTypeURL { - return nil, fmt.Errorf("extractPrivKey: can't extract unsupported private key '%s'", primaryKey.KeyData.TypeUrl) - } + switch primaryKey.KeyData.TypeUrl { + case ecdhNISTPAESPrivateKeyTypeURL: + pbKey := new(ecdhpb.EcdhAeadPrivateKey) - pbKey := new(ecdhpb.EcdhAeadPrivateKey) + err = proto.Unmarshal(primaryKey.KeyData.Value, pbKey) + if err != nil { + return nil, errors.New("extractPrivKey: invalid key in keyset") + } - err = proto.Unmarshal(primaryKey.KeyData.Value, pbKey) - if err != nil { - return nil, errors.New("extractPrivKey: invalid key in keyset") - } + var c elliptic.Curve - c, err := hybrid.GetCurve(pbKey.PublicKey.Params.KwParams.CurveType.String()) - if err != nil { - return nil, fmt.Errorf("extractPrivKey: invalid key: %w", err) + c, err = hybrid.GetCurve(pbKey.PublicKey.Params.KwParams.CurveType.String()) + if err != nil { + return nil, fmt.Errorf("extractPrivKey: invalid key: %w", err) + } + + return hybrid.GetECPrivateKey(c, pbKey.KeyValue), nil + case ecdhX25519XChachaPrivateKeyTypeURL: + pbKey := new(ecdhpb.EcdhAeadPrivateKey) + + err = proto.Unmarshal(primaryKey.KeyData.Value, pbKey) + if err != nil { + return nil, errors.New("extractPrivKey: invalid key in keyset") + } + + if pbKey.PublicKey.Params.KwParams.CurveType.String() != commonpb.EllipticCurveType_CURVE25519.String() { + return nil, errors.New("extractPrivKey: invalid key curve") + } + + return pbKey.KeyValue, nil } - return hybrid.GetECPrivateKey(c, pbKey.KeyValue), nil + return nil, fmt.Errorf("extractPrivKey: can't extract unsupported private key '%s'", primaryKey.KeyData.TypeUrl) } func hybridECPrivToECDSAKey(hybridEcPriv *hybrid.ECPrivateKey) *ecdsa.PrivateKey { diff --git a/pkg/crypto/tinkcrypto/wrap_support.go b/pkg/crypto/tinkcrypto/wrap_support.go new file mode 100644 index 0000000000..38d09d5433 --- /dev/null +++ b/pkg/crypto/tinkcrypto/wrap_support.go @@ -0,0 +1,294 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package tinkcrypto + +import ( + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "encoding/binary" + "errors" + "fmt" + + hybrid "github.com/google/tink/go/hybrid/subtle" + josecipher "github.com/square/go-jose/v3/cipher" + "golang.org/x/crypto/chacha20poly1305" + + "github.com/hyperledger/aries-framework-go/pkg/internal/cryptoutil" +) + +type keyWrapper interface { + getCurve(curve string) (elliptic.Curve, error) + generateKey(curve elliptic.Curve) (interface{}, error) + createPrimitive(key []byte) (interface{}, error) + wrap(blockPrimitive interface{}, cek []byte) ([]byte, error) + unwrap(blockPrimitive interface{}, encryptedKey []byte) ([]byte, error) + deriveSender1Pu(kwAlg string, apu, apv []byte, ephemeralPriv, senderPrivKey, recPubKey interface{}, + keySize int) ([]byte, error) + deriveRecipient1Pu(kwAlg string, apu, apv []byte, ephemeralPub, senderPubKey, recPrivKey interface{}, + keySize int) ([]byte, error) +} + +type ecKWSupport struct{} + +func (w *ecKWSupport) getCurve(curve string) (elliptic.Curve, error) { + return hybrid.GetCurve(curve) +} + +func (w *ecKWSupport) generateKey(curve elliptic.Curve) (interface{}, error) { + return ecdsa.GenerateKey(curve, rand.Reader) +} + +func (w *ecKWSupport) createPrimitive(kek []byte) (interface{}, error) { + return aes.NewCipher(kek) +} + +func (w *ecKWSupport) wrap(block interface{}, cek []byte) ([]byte, error) { + blockCipher, ok := block.(cipher.Block) + if !ok { + return nil, errors.New("wrap support: EC wrap with invalid cipher block type") + } + + return josecipher.KeyWrap(blockCipher, cek) +} + +func (w *ecKWSupport) unwrap(block interface{}, encryptedKey []byte) ([]byte, error) { + blockCipher, ok := block.(cipher.Block) + if !ok { + return nil, errors.New("unwrap support: EC wrap with invalid cipher block type") + } + + return josecipher.KeyUnwrap(blockCipher, encryptedKey) +} + +func (w *ecKWSupport) deriveSender1Pu(alg string, apu, apv []byte, ephemeralPriv, senderPrivKey interface{}, + recPubKey interface{}, keySize int) ([]byte, error) { + ephemeralPrivEC, ok := ephemeralPriv.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("deriveSender1Pu: ephemeral key not ECDSA type") + } + + senderPrivKeyEC, ok := senderPrivKey.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("deriveSender1Pu: sender key not ECDSA type") + } + + recPubKeyEC, ok := recPubKey.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("deriveSender1Pu: recipient key not ECDSA type") + } + + if recPubKeyEC.Curve != ephemeralPrivEC.Curve || recPubKeyEC.Curve != senderPrivKeyEC.Curve { + return nil, errors.New("deriveSender1Pu: recipient, sender and ephemeral key are not on the same curve") + } + + ze := josecipher.DeriveECDHES(alg, apu, apv, ephemeralPrivEC, recPubKeyEC, keySize) + zs := josecipher.DeriveECDHES(alg, apu, apv, senderPrivKeyEC, recPubKeyEC, keySize) + + return derive1Pu(alg, ze, zs, apu, apv, keySize), nil +} + +func (w *ecKWSupport) deriveRecipient1Pu(alg string, apu, apv []byte, ephemeralPub, senderPubKey interface{}, + recPrivKey interface{}, keySize int) ([]byte, error) { + ephemeralPubEC, ok := ephemeralPub.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("deriveRecipient1Pu: ephemeral key not ECDSA type") + } + + senderPubKeyEC, ok := senderPubKey.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("deriveRecipient1Pu: sender key not ECDSA type") + } + + recPrivKeyEC, ok := recPrivKey.(*ecdsa.PrivateKey) + if !ok { + return nil, errors.New("deriveRecipient1Pu: recipient key not ECDSA type") + } + + if recPrivKeyEC.Curve != ephemeralPubEC.Curve || recPrivKeyEC.Curve != senderPubKeyEC.Curve { + return nil, errors.New("deriveRecipient1Pu: recipient, sender and ephemeral key are not on the same curve") + } + + // DeriveECDHES checks if keys are on the same curve + ze := josecipher.DeriveECDHES(alg, apu, apv, recPrivKeyEC, ephemeralPubEC, keySize) + zs := josecipher.DeriveECDHES(alg, apu, apv, recPrivKeyEC, senderPubKeyEC, keySize) + + return derive1Pu(alg, ze, zs, apu, apv, keySize), nil +} + +type okpKWSupport struct{} + +func (o *okpKWSupport) getCurve(curve string) (elliptic.Curve, error) { + return nil, errors.New("getCurve: not implemented for OKP KW support") +} + +func (o *okpKWSupport) generateKey(_ elliptic.Curve) (interface{}, error) { + newKey := make([]byte, cryptoutil.Curve25519KeySize) + + _, err := rand.Read(newKey) + if err != nil { + return nil, fmt.Errorf("generateKey: failed to create X25519 random key: %w", err) + } + + return newKey, nil +} + +func (o *okpKWSupport) createPrimitive(kek []byte) (interface{}, error) { + p, err := chacha20poly1305.NewX(kek) + if err != nil { + return nil, fmt.Errorf("createPrimitive: failed to create OKP primitive: %w", err) + } + + return p, nil +} + +func (o *okpKWSupport) wrap(aead interface{}, cek []byte) ([]byte, error) { + aeadPrimitive, ok := aead.(cipher.AEAD) + if !ok { + return nil, errors.New("wrap support: OKP wrap with invalid primitive type") + } + + nonceSize := aeadPrimitive.NonceSize() + nonce := make([]byte, nonceSize) + + _, err := rand.Read(nonce) + if err != nil { + return nil, fmt.Errorf("wrap support: failed to generate random nonce: %w", err) + } + + cipherText := aeadPrimitive.Seal(nil, nonce, cek, nil) + + return append(nonce, cipherText...), nil +} + +func (o *okpKWSupport) unwrap(aead interface{}, encryptedKey []byte) ([]byte, error) { + aeadPrimitive, ok := aead.(cipher.AEAD) + if !ok { + return nil, errors.New("unwrap support: OKP unwrap with invalid primitive type") + } + + if len(encryptedKey) < aeadPrimitive.NonceSize() { + return nil, errors.New("unwrap support: OKP unwrap invalid key") + } + + nonce := encryptedKey[:aeadPrimitive.NonceSize()] + + cek, err := aeadPrimitive.Open(nil, nonce, encryptedKey[aeadPrimitive.NonceSize():], nil) + if err != nil { + return nil, fmt.Errorf("unwrap support: OKP failed to unwrap key: %w", err) + } + + return cek, nil +} + +func (o *okpKWSupport) deriveSender1Pu(kwAlg string, apu, apv []byte, ephemeralPriv, senderPrivKey interface{}, + recPubKey interface{}, _ int) ([]byte, error) { + ephemeralPrivOKP, ok := ephemeralPriv.([]byte) + if !ok { + return nil, errors.New("deriveSender1Pu: ephemeral key not OKP type") + } + + ephemeralPrivOKPChacha := new([chacha20poly1305.KeySize]byte) + copy(ephemeralPrivOKPChacha[:], ephemeralPrivOKP) + + senderPrivKeyOKP, ok := senderPrivKey.([]byte) + if !ok { + return nil, errors.New("deriveSender1Pu: sender key not OKP type") + } + + senderPrivKeyOKPChacha := new([chacha20poly1305.KeySize]byte) + copy(senderPrivKeyOKPChacha[:], senderPrivKeyOKP) + + recPubKeyOKP, ok := recPubKey.([]byte) + if !ok { + return nil, errors.New("deriveSender1Pu: recipient key not OKP type") + } + + recPubKeyOKPChacha := new([chacha20poly1305.KeySize]byte) + copy(recPubKeyOKPChacha[:], recPubKeyOKP) + + ze, err := cryptoutil.Derive25519KEK([]byte(kwAlg), apu, apv, ephemeralPrivOKPChacha, recPubKeyOKPChacha) + if err != nil { + return nil, fmt.Errorf("deriveSender1Pu: derive25519KEK with ephemeral key failed: %w", err) + } + + zs, err := cryptoutil.Derive25519KEK([]byte(kwAlg), apu, apv, senderPrivKeyOKPChacha, recPubKeyOKPChacha) + if err != nil { + return nil, fmt.Errorf("deriveSender1Pu: derive25519KEK with sender key failed: %w", err) + } + + return derive1Pu(kwAlg, ze, zs, apu, apv, chacha20poly1305.KeySize), nil +} + +func (o *okpKWSupport) deriveRecipient1Pu(kwAlg string, apu, apv []byte, ephemeralPub, senderPubKey interface{}, + recPrivKey interface{}, _ int) ([]byte, error) { + ephemeralPubOKP, ok := ephemeralPub.([]byte) + if !ok { + return nil, errors.New("deriveRecipient1Pu: ephemeral key not OKP type") + } + + ephemeralPubOKPChacha := new([chacha20poly1305.KeySize]byte) + copy(ephemeralPubOKPChacha[:], ephemeralPubOKP) + + senderPubKeyOKP, ok := senderPubKey.([]byte) + if !ok { + return nil, errors.New("deriveRecipient1Pu: sender key not OKP type") + } + + senderPubKeyOKPChacha := new([chacha20poly1305.KeySize]byte) + copy(senderPubKeyOKPChacha[:], senderPubKeyOKP) + + recPrivKeyOKP, ok := recPrivKey.([]byte) + if !ok { + return nil, errors.New("deriveRecipient1Pu: recipient key not OKP type") + } + + recPrivKeyOKPChacha := new([chacha20poly1305.KeySize]byte) + copy(recPrivKeyOKPChacha[:], recPrivKeyOKP) + + ze, err := cryptoutil.Derive25519KEK([]byte(kwAlg), apu, apv, recPrivKeyOKPChacha, ephemeralPubOKPChacha) + if err != nil { + return nil, fmt.Errorf("deriveRecipient1Pu: derive25519KEK with ephemeral key failed: %w", err) + } + + zs, err := cryptoutil.Derive25519KEK([]byte(kwAlg), apu, apv, recPrivKeyOKPChacha, senderPubKeyOKPChacha) + if err != nil { + return nil, fmt.Errorf("deriveRecipient1Pu: derive25519KEK with sender key failed: %w", err) + } + + return derive1Pu(kwAlg, ze, zs, apu, apv, chacha20poly1305.KeySize), nil +} + +func derive1Pu(kwAlg string, ze, zs, apu, apv []byte, keySize int) []byte { + round1 := make([]byte, 4) + binary.BigEndian.PutUint32(round1, uint32(1)) + + // 1PU requires round one number (0001) to be prefixed to the Z concatenation + z := append(round1, ze...) + z = append(z, zs...) + + algID := cryptoutil.LengthPrefix([]byte(kwAlg)) + ptyUInfo := cryptoutil.LengthPrefix(apu) + ptyVInfo := cryptoutil.LengthPrefix(apv) + + supPubLen := 4 + supPubInfo := make([]byte, supPubLen) + + byteLen := 8 + binary.BigEndian.PutUint32(supPubInfo, uint32(keySize)*uint32(byteLen)) + + reader := josecipher.NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, []byte{}) + + kek := make([]byte, keySize) + + _, _ = reader.Read(kek) // nolint:errcheck // ConcatKDF's Read() never returns an error + + return kek +} diff --git a/pkg/crypto/tinkcrypto/wrap_support_test.go b/pkg/crypto/tinkcrypto/wrap_support_test.go new file mode 100644 index 0000000000..bd236452f9 --- /dev/null +++ b/pkg/crypto/tinkcrypto/wrap_support_test.go @@ -0,0 +1,139 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package tinkcrypto + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "testing" + + "github.com/stretchr/testify/require" + "golang.org/x/crypto/curve25519" +) + +func Test_ecKWSupportFailures(t *testing.T) { + ecKW := &ecKWSupport{} + + _, err := ecKW.wrap("badCipherBlockType", []byte("")) + require.EqualError(t, err, "wrap support: EC wrap with invalid cipher block type") + + _, err = ecKW.unwrap("badCipherBlockType", []byte("")) + require.EqualError(t, err, "unwrap support: EC wrap with invalid cipher block type") + + _, err = ecKW.deriveSender1Pu("", nil, nil, "badEphemeralPrivKeyType", nil, nil, 0) + require.EqualError(t, err, "deriveSender1Pu: ephemeral key not ECDSA type") + + _, err = ecKW.deriveSender1Pu("", nil, nil, &ecdsa.PrivateKey{}, "badSenderPrivKeyType", nil, 0) + require.EqualError(t, err, "deriveSender1Pu: sender key not ECDSA type") + + _, err = ecKW.deriveSender1Pu("", nil, nil, &ecdsa.PrivateKey{}, &ecdsa.PrivateKey{}, "badSenderPrivKeyType", 0) + require.EqualError(t, err, "deriveSender1Pu: recipient key not ECDSA type") + + _, err = ecKW.deriveSender1Pu("", nil, nil, &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{Curve: elliptic.P256()}, + }, &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{Curve: elliptic.P521()}, + }, &ecdsa.PublicKey{Curve: elliptic.P521()}, 0) + require.EqualError(t, err, "deriveSender1Pu: recipient, sender and ephemeral key are not on the same curve") + + _, err = ecKW.deriveSender1Pu("", nil, nil, &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{Curve: elliptic.P521()}, + }, &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{Curve: elliptic.P256()}, + }, &ecdsa.PublicKey{Curve: elliptic.P521()}, 0) + require.EqualError(t, err, "deriveSender1Pu: recipient, sender and ephemeral key are not on the same curve") + + _, err = ecKW.deriveRecipient1Pu("", nil, nil, "badEphemeralPrivKeyType", nil, nil, 0) + require.EqualError(t, err, "deriveRecipient1Pu: ephemeral key not ECDSA type") + + _, err = ecKW.deriveRecipient1Pu("", nil, nil, &ecdsa.PublicKey{}, "badSenderPrivKeyType", nil, 0) + require.EqualError(t, err, "deriveRecipient1Pu: sender key not ECDSA type") + + _, err = ecKW.deriveRecipient1Pu("", nil, nil, &ecdsa.PublicKey{}, &ecdsa.PublicKey{}, "badSenderPrivKeyType", 0) + require.EqualError(t, err, "deriveRecipient1Pu: recipient key not ECDSA type") + + _, err = ecKW.deriveRecipient1Pu("", nil, nil, &ecdsa.PublicKey{Curve: elliptic.P521()}, + &ecdsa.PublicKey{Curve: elliptic.P521()}, &ecdsa.PrivateKey{PublicKey: ecdsa.PublicKey{Curve: elliptic.P256()}}, 0) + require.EqualError(t, err, "deriveRecipient1Pu: recipient, sender and ephemeral key are not on the same curve") + + _, err = ecKW.deriveRecipient1Pu("", nil, nil, &ecdsa.PublicKey{Curve: elliptic.P521()}, + &ecdsa.PublicKey{Curve: elliptic.P256()}, &ecdsa.PrivateKey{PublicKey: ecdsa.PublicKey{Curve: elliptic.P521()}}, 0) + require.EqualError(t, err, "deriveRecipient1Pu: recipient, sender and ephemeral key are not on the same curve") +} + +func Test_okpKWSupportFailures(t *testing.T) { + okpKW := &okpKWSupport{} + + _, err := okpKW.getCurve("") + require.EqualError(t, err, "getCurve: not implemented for OKP KW support") + + _, err = okpKW.createPrimitive([]byte("kekWithBadSize")) + require.EqualError(t, err, "createPrimitive: failed to create OKP primitive: chacha20poly1305: bad key length") + + _, err = okpKW.wrap("badCipherBlockType", []byte("")) + require.EqualError(t, err, "wrap support: OKP wrap with invalid primitive type") + + _, err = okpKW.unwrap("badCipherBlockType", []byte("")) + require.EqualError(t, err, "unwrap support: OKP unwrap with invalid primitive type") + + kek, err := okpKW.generateKey(nil) + require.NoError(t, err) + + kekBytes, ok := kek.([]byte) + require.True(t, ok) + + XC20PPrimitive, err := okpKW.createPrimitive(kekBytes) + require.NoError(t, err) + + _, err = okpKW.unwrap(XC20PPrimitive, []byte("")) + require.EqualError(t, err, "unwrap support: OKP unwrap invalid key") + + _, err = okpKW.unwrap(XC20PPrimitive, []byte("badEncryptedKeyLargerThankNonceSize")) + require.EqualError(t, err, "unwrap support: OKP failed to unwrap key: chacha20poly1305: message authentication failed") + + _, err = okpKW.deriveSender1Pu("", nil, nil, "badEphemeralPrivKeyType", nil, nil, 0) + require.EqualError(t, err, "deriveSender1Pu: ephemeral key not OKP type") + + _, err = okpKW.deriveSender1Pu("", nil, nil, []byte{}, "badSenderPrivKeyType", nil, 0) + require.EqualError(t, err, "deriveSender1Pu: sender key not OKP type") + + _, err = okpKW.deriveSender1Pu("", nil, nil, []byte{}, []byte{}, "badSenderPrivKeyType", 0) + require.EqualError(t, err, "deriveSender1Pu: recipient key not OKP type") + + _, err = okpKW.deriveSender1Pu("", nil, nil, []byte{}, []byte{}, []byte{}, 0) + require.EqualError(t, err, "deriveSender1Pu: derive25519KEK with ephemeral key failed: bad input point: "+ + "low order point") + + derivedKEK, err := curve25519.X25519(kekBytes, curve25519.Basepoint) + require.NoError(t, err) + + // lowOrderPoint from golang.org/x/crypto/curve25519. Causes ED25519 key derivation to fail. + // https://github.com/golang/crypto/blob/f4817d981/curve25519/vectors_test.go#L10 + lowOrderPoint := []byte{ + 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + } + + _, err = okpKW.deriveSender1Pu("", nil, nil, derivedKEK, kekBytes, lowOrderPoint, 0) + require.EqualError(t, err, "deriveSender1Pu: derive25519KEK with ephemeral key failed: bad input point: "+ + "low order point") + // can't reproduce key derivation error with sender key because recipient public key as lowOrderPoint fails for + // ephemeral key derivation. ie sender key derivation failure only fails if ephemeral key derivation fails. + + _, err = okpKW.deriveRecipient1Pu("", nil, nil, "badEphemeralPrivKeyType", nil, nil, 0) + require.EqualError(t, err, "deriveRecipient1Pu: ephemeral key not OKP type") + + _, err = okpKW.deriveRecipient1Pu("", nil, nil, []byte{}, "badSenderPrivKeyType", nil, 0) + require.EqualError(t, err, "deriveRecipient1Pu: sender key not OKP type") + + _, err = okpKW.deriveRecipient1Pu("", nil, nil, []byte{}, []byte{}, "badSenderPrivKeyType", 0) + require.EqualError(t, err, "deriveRecipient1Pu: recipient key not OKP type") + + _, err = okpKW.deriveRecipient1Pu("", nil, nil, []byte{}, []byte{}, []byte{}, 0) + require.EqualError(t, err, "deriveRecipient1Pu: derive25519KEK with ephemeral key failed: bad input point:"+ + " low order point") +} diff --git a/pkg/crypto/webkms/remotecrypto_test.go b/pkg/crypto/webkms/remotecrypto_test.go index d12f78c0d4..fff87da6f7 100644 --- a/pkg/crypto/webkms/remotecrypto_test.go +++ b/pkg/crypto/webkms/remotecrypto_test.go @@ -658,13 +658,13 @@ func verifyMACPOSTHandle(reqBody []byte, macKH *keyset.Handle) error { func TestWrapUnWrapKey(t *testing.T) { senderKID := "11111" - recipientKH, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) recipentPubKey, err := exportPubKey(recipientKH) require.NoError(t, err) - senderKH, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + senderKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -778,13 +778,13 @@ func TestWrapUnWrapKey(t *testing.T) { } func TestRemoteCryptoWithHeadersFunc(t *testing.T) { - recipientKH, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + recipientKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) recipentPubKey, err := exportPubKey(recipientKH) require.NoError(t, err) - senderKH, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + senderKH, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/crypto/wrapkey_opts.go b/pkg/crypto/wrapkey_opts.go index a90f3d8415..481d6e0502 100644 --- a/pkg/crypto/wrapkey_opts.go +++ b/pkg/crypto/wrapkey_opts.go @@ -7,7 +7,8 @@ SPDX-License-Identifier: Apache-2.0 package crypto type wrapKeyOpts struct { - senderKey interface{} + senderKey interface{} + useXC20PKW bool } // NewOpt creates a new empty wrap key option. @@ -24,6 +25,11 @@ func (pk *wrapKeyOpts) SenderKey() interface{} { return pk.senderKey } +// UseXC20PKW instructs to use XC20P key wrapping as apposed to the default A256KW. +func (pk *wrapKeyOpts) UseXC20PKW() bool { + return pk.useXC20PKW +} + // WrapKeyOpts are the crypto.Wrap key options. type WrapKeyOpts func(opts *wrapKeyOpts) @@ -39,3 +45,13 @@ func WithSender(senderKey interface{}) WrapKeyOpts { opts.senderKey = senderKey } } + +// WithXC20PKW options is a flag option for crypto wrapping. When used, key wrapping will use XChacha20Poly1305 +// encryption as key wrapping. The absence of this option (default) uses AES256-GCM encryption as key wrapping. The KDF +// used in the crypto wrapping function is selected based on the type of recipient key argument of KeyWrap(), it is +// independent of this option. +func WithXC20PKW() WrapKeyOpts { + return func(opts *wrapKeyOpts) { + opts.useXC20PKW = true + } +} diff --git a/pkg/doc/jose/decrypter.go b/pkg/doc/jose/decrypter.go index d6c5990aff..ae334c2e50 100644 --- a/pkg/doc/jose/decrypter.go +++ b/pkg/doc/jose/decrypter.go @@ -48,7 +48,7 @@ func NewJWEDecrypt(store storage.Store, c cryptoapi.Crypto, k kms.KeyManager) *J } func getECDHDecPrimitive(cek []byte) (api.CompositeDecrypt, error) { - kt := ecdh.AES256GCMKeyTemplateWithCEK(cek) + kt := ecdh.NISTPECDHAES256GCMKeyTemplateWithCEK(cek) kh, err := keyset.NewHandle(kt) if err != nil { diff --git a/pkg/doc/jose/encrypt_test.go b/pkg/doc/jose/encrypt_test.go index 0bf4e5e72f..b3700f774c 100644 --- a/pkg/doc/jose/encrypt_test.go +++ b/pkg/doc/jose/encrypt_test.go @@ -39,7 +39,7 @@ func TestBadSenderKeyType(t *testing.T) { c, err := tinkcrypto.New() require.NoError(t, err) - // create a keyset.Handle that doesn't + // create a keyset.Handle that fails JWE/ECDH primitive execution (must come from an ECDH key template). aeadKT := aead.AES256GCMKeyTemplate() aeadKH, err := keyset.NewHandle(aeadKT) require.NoError(t, err) @@ -55,9 +55,10 @@ func TestBadSenderKeyType(t *testing.T) { } _, err = jweEncrypter.Encrypt([]byte{}) - require.EqualError(t, err, "jweencrypt: failed to wrap cek: wrapCEKForRecipient 1 failed: wrapKey: failed "+ - "to retrieve sender key: ksToPrivateECDSAKey: failed to extract sender key: extractPrivKey: can't extract "+ - "unsupported private key 'type.googleapis.com/google.crypto.tink.AesGcmKey'") + require.EqualError(t, err, "jweencrypt: failed to wrap cek: wrapCEKForRecipient 1 failed: wrapKey: "+ + "deriveKEKAndWrap: error ECDH-1PU kek derivation: derive1PUKEK: EC key derivation error derive1PUWithECKey: "+ + "failed to retrieve sender key: ksToPrivateECDSAKey: failed to extract sender key: extractPrivKey: can't "+ + "extract unsupported private key 'type.googleapis.com/google.crypto.tink.AesGcmKey'") } func TestMergeSingleRecipientsHeadersFailureWithUnsetCurve(t *testing.T) { @@ -146,7 +147,7 @@ func createRecipients(t *testing.T, numberOfEntities int) ([]*cryptoapi.PublicKe func createAndMarshalEntityKey(t *testing.T) ([]byte, *keyset.Handle) { t.Helper() - tmpl := ecdh.ECDH256KWAES256GCMKeyTemplate() + tmpl := ecdh.NISTP256ECDHKWKeyTemplate() kh, err := keyset.NewHandle(tmpl) require.NoError(t, err) diff --git a/pkg/doc/jose/encrypter.go b/pkg/doc/jose/encrypter.go index d6128c8c58..8535fa7435 100644 --- a/pkg/doc/jose/encrypter.go +++ b/pkg/doc/jose/encrypter.go @@ -93,7 +93,7 @@ func NewJWEEncrypt(encAlg EncAlg, encType, senderKID string, senderKH *keyset.Ha } func getECDHEncPrimitive(cek []byte) (api.CompositeEncrypt, error) { - kt := ecdh.AES256GCMKeyTemplateWithCEK(cek) + kt := ecdh.NISTPECDHAES256GCMKeyTemplateWithCEK(cek) kh, err := keyset.NewHandle(kt) if err != nil { diff --git a/pkg/doc/jose/encrypter_decrypter_test.go b/pkg/doc/jose/encrypter_decrypter_test.go index 7f2c6cff4d..1673deaeb9 100644 --- a/pkg/doc/jose/encrypter_decrypter_test.go +++ b/pkg/doc/jose/encrypter_decrypter_test.go @@ -404,7 +404,7 @@ func createRecipients(t *testing.T, nbOfEntities int) ([]*cryptoapi.PublicKey, m func createAndMarshalEntityKey(t *testing.T) ([]byte, *keyset.Handle, string) { t.Helper() - tmpl := ecdh.ECDH256KWAES256GCMKeyTemplate() + tmpl := ecdh.NISTP256ECDHKWKeyTemplate() kh, err := keyset.NewHandle(tmpl) require.NoError(t, err) diff --git a/pkg/internal/cryptoutil/utils.go b/pkg/internal/cryptoutil/utils.go index c6110a12d6..e913193745 100644 --- a/pkg/internal/cryptoutil/utils.go +++ b/pkg/internal/cryptoutil/utils.go @@ -144,7 +144,7 @@ func IsMessagingKeysValid(kpb *MessagingKeys) bool { // Derive25519KEK is a utility function that will derive an ephemeral // symmetric key (kek) using fromPrivKey and toPubKey. -func Derive25519KEK(alg, apu []byte, fromPrivKey, toPubKey *[chacha.KeySize]byte) ([]byte, error) { +func Derive25519KEK(alg, apu, apv []byte, fromPrivKey, toPubKey *[chacha.KeySize]byte) ([]byte, error) { if fromPrivKey == nil || toPubKey == nil { return nil, ErrInvalidKey } @@ -176,8 +176,8 @@ func Derive25519KEK(alg, apu []byte, fromPrivKey, toPubKey *[chacha.KeySize]byte // length prefix apu apuInfo := LengthPrefix(apu) - // length prefix apv (empty) - apvInfo := LengthPrefix(nil) + // length prefix apv + apvInfo := LengthPrefix(apv) // get a Concat KDF stream for z, encryption algorithm, api, supPubInfo and empty supPrivInfo using sha256 reader := josecipher.NewConcatKDF(crypto.SHA256, z, algInfo, apuInfo, apvInfo, supPubInfo, []byte{}) diff --git a/pkg/internal/cryptoutil/utils_test.go b/pkg/internal/cryptoutil/utils_test.go index 19ab54a036..634d992841 100644 --- a/pkg/internal/cryptoutil/utils_test.go +++ b/pkg/internal/cryptoutil/utils_test.go @@ -73,7 +73,7 @@ func TestIsKeyPairValid(t *testing.T) { } func TestDeriveKEK_Util(t *testing.T) { - kek, err := Derive25519KEK(nil, nil, nil, nil) + kek, err := Derive25519KEK(nil, nil, nil, nil, nil) require.EqualError(t, err, ErrInvalidKey.Error()) require.Empty(t, kek) @@ -82,7 +82,7 @@ func TestDeriveKEK_Util(t *testing.T) { chachaKey := new([chacha.KeySize]byte) copy(chachaKey[:], validChachaKey) - kek, err = Derive25519KEK(nil, nil, chachaKey, nil) + kek, err = Derive25519KEK(nil, nil, nil, chachaKey, nil) require.EqualError(t, err, ErrInvalidKey.Error()) require.Empty(t, kek) @@ -91,7 +91,7 @@ func TestDeriveKEK_Util(t *testing.T) { chachaKey2 := new([chacha.KeySize]byte) copy(chachaKey2[:], validChachaKey2) - kek, err = Derive25519KEK(nil, nil, chachaKey, chachaKey2) + kek, err = Derive25519KEK(nil, nil, nil, chachaKey, chachaKey2) require.NoError(t, err) require.NotEmpty(t, kek) @@ -104,7 +104,7 @@ func TestDeriveKEK_Util(t *testing.T) { chachaKey2 = new([chacha.KeySize]byte) copy(chachaKey2[:], lowOrderPoint) // test error from curve25519.X25519() call in Derive25519KEK() - _, err = Derive25519KEK(nil, nil, chachaKey, chachaKey2) + _, err = Derive25519KEK(nil, nil, nil, chachaKey, chachaKey2) require.Error(t, err) } diff --git a/pkg/kms/localkms/localkms.go b/pkg/kms/localkms/localkms.go index 69de57f911..b1af521912 100644 --- a/pkg/kms/localkms/localkms.go +++ b/pkg/kms/localkms/localkms.go @@ -200,11 +200,11 @@ func getKeyTemplate(keyType kms.KeyType) (*tinkpb.KeyTemplate, error) { case kms.HMACSHA256Tag256Type: return mac.HMACSHA256Tag256KeyTemplate(), nil case kms.ECDH256KWAES256GCMType: - return ecdh.ECDH256KWAES256GCMKeyTemplate(), nil + return ecdh.NISTP256ECDHKWKeyTemplate(), nil case kms.ECDH384KWAES256GCMType: - return ecdh.ECDH384KWAES256GCMKeyTemplate(), nil + return ecdh.NISTP384ECDHKWKeyTemplate(), nil case kms.ECDH521KWAES256GCMType: - return ecdh.ECDH521KWAES256GCMKeyTemplate(), nil + return ecdh.NISTP521ECDHKWKeyTemplate(), nil default: return nil, fmt.Errorf("getKeyTemplate: key type '%s' unrecognized", keyType) } diff --git a/pkg/kms/localkms/pubkey_writer.go b/pkg/kms/localkms/pubkey_writer.go index 01349cdde7..8bf9a7b189 100644 --- a/pkg/kms/localkms/pubkey_writer.go +++ b/pkg/kms/localkms/pubkey_writer.go @@ -27,7 +27,7 @@ import ( const ( ecdsaVerifierTypeURL = "type.googleapis.com/google.crypto.tink.EcdsaPublicKey" ed25519VerifierTypeURL = "type.googleapis.com/google.crypto.tink.Ed25519PublicKey" - ecdhAESPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwAesAeadPublicKey" + ecdhAESPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPublicKey" ) // PubKeyWriter will write the raw bytes of a Tink KeySet's primary public key diff --git a/pkg/storage/edv/encryptedformatter_test.go b/pkg/storage/edv/encryptedformatter_test.go index 9c47415064..673d8f75ee 100644 --- a/pkg/storage/edv/encryptedformatter_test.go +++ b/pkg/storage/edv/encryptedformatter_test.go @@ -196,7 +196,7 @@ func createEncrypterAndDecrypter(t *testing.T) (*jose.JWEEncrypt, *jose.JWEDecry cryptoSvc, err := tinkcrypto.New() require.NoError(t, err) - keyHandle, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + keyHandle, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) kmsSvc := &mockkms.KeyManager{ diff --git a/pkg/storage/formattedstore/formattedstore_test.go b/pkg/storage/formattedstore/formattedstore_test.go index 5102e6a7cf..0741077505 100644 --- a/pkg/storage/formattedstore/formattedstore_test.go +++ b/pkg/storage/formattedstore/formattedstore_test.go @@ -699,7 +699,7 @@ func createEncrypterAndDecrypter(t *testing.T) (*jose.JWEEncrypt, *jose.JWEDecry cryptoSvc, err := tinkcrypto.New() require.NoError(t, err) - keyHandle, err := keyset.NewHandle(ecdh.ECDH256KWAES256GCMKeyTemplate()) + keyHandle, err := keyset.NewHandle(ecdh.NISTP256ECDHKWKeyTemplate()) require.NoError(t, err) kmsSvc := &mockkms.KeyManager{