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..d92112d1db 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(newX25519ECDHKWPublicKeyManager()) 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(newX25519ECDHKWPrivateKeyManager()) 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..d47278c36d 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, - }, - { - 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, + tmplFunc: NISTP521ECDHKWKeyTemplate, }, { 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..7711465dcb 100644 --- a/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export.go +++ b/pkg/crypto/tinkcrypto/primitive/composite/keyio/composite_key_export.go @@ -30,10 +30,10 @@ import ( // key (aka PublicKeyToHandle to be used as a valid Tink key) const ( - ecdhNISTPAESPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.EcdhNistPKwAesAeadPublicKey" + ecdhNISTPAESPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPublicKey" 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 + ecdhX25519XChachaPublicKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.X25519EcdhKwPublicKey" // nolint:lll ) // PubKeyWriter will write the raw bytes of a Tink KeySet's primary public key. The raw bytes are a marshaled 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..a610d18085 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 @@ -31,36 +31,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(), }, } @@ -175,7 +159,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) 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{