Skip to content
This repository has been archived by the owner on Mar 27, 2024. It is now read-only.

Commit

Permalink
feat: Add Default implementation for JWE Anoncrypt
Browse files Browse the repository at this point in the history
This change introduces a new Tink key template that supports
encrypting a plaintext into a JWE protected by the (recipient)
public key of the template and also supports decrypting the protected
JWE using the (recipient's) private key of the template.

closes #1469
closes #1472
closes #1470

Signed-off-by: Baha Shaaban <[email protected]>
  • Loading branch information
Baha Shaaban committed Mar 31, 2020
1 parent b14f446 commit 516c2ad
Show file tree
Hide file tree
Showing 19 changed files with 1,626 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ run:
issues-exit-code: 1
tests: true
build-tags: [""]
skip-dirs: [""]
skip-dirs: ["proto"]

output:
format: colored-line-number
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package ecdhes

import (
"fmt"

"github.com/golang/protobuf/proto"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/keyset"
"github.com/google/tink/go/subtle/hybrid"
tinkpb "github.com/google/tink/proto/tink_go_proto"

"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/jwe/subtle/ecdhes"
ecdhespb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdhes_aead_go_proto"
)

const (
ecdhesPrivateKeyVersion = 0
ecdhesPrivateKeyTypeURL = "type.googleapis.com/google.crypto.tink.EcdhesAeadPrivateKey"
)

// common errors
var errInvalidECDHESPrivateKey = fmt.Errorf("ecdhes_private_key_manager: invalid key")
var errInvalidECDHESPrivateKeyFormat = fmt.Errorf("ecdhes_private_key_manager: invalid key format")

// ecdhesPrivateKeyManager is an implementation of PrivateKeyManager interface.
// It generates new ECDHESPrivateKey keys and produces new instances of ECDHESPrivateKey subtle.
type ecdhesPrivateKeyManager struct{}

// Assert that ecdhesPrivateKeyManager implements the PrivateKeyManager interface.
var _ registry.PrivateKeyManager = (*ecdhesPrivateKeyManager)(nil)

// newECDHESPrivateKeyManager creates a new aesGcmKeyManager.
func newECDHESPrivateKeyManager() *ecdhesPrivateKeyManager {
return new(ecdhesPrivateKeyManager)
}

// Primitive creates an ECDHESPrivateKey subtle for the given serialized ECDHESPrivateKey proto.
func (km *ecdhesPrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) {
if len(serializedKey) == 0 {
return nil, errInvalidECDHESPrivateKey
}

key := new(ecdhespb.EcdhesAeadPrivateKey)

err := proto.Unmarshal(serializedKey, key)
if err != nil {
return nil, errInvalidECDHESPrivateKey
}

err = km.validateKey(key)
if err != nil {
return nil, errInvalidECDHESPrivateKey
}

curve, err := hybrid.GetCurve(key.PublicKey.Params.KemParams.CurveType.String())
if err != nil {
return nil, err
}

pvt := hybrid.GetECPrivateKey(curve, key.KeyValue)

rDem, err := newRegisterECDHESEncHelper(key.PublicKey.Params.DemParams.AeadDem)
if err != nil {
return nil, err
}

ptFormat := key.PublicKey.Params.EcPointFormat.String()

return ecdhes.NewECDHESDecrypt(pvt, ptFormat, rDem)
}

// NewKey creates a new key according to the specification of ECDHESPrivateKey format.
func (km *ecdhesPrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
if len(serializedKeyFormat) == 0 {
return nil, errInvalidECDHESPrivateKeyFormat
}

keyFormat := new(ecdhespb.EcdhesAeadKeyFormat)

err := proto.Unmarshal(serializedKeyFormat, keyFormat)
if err != nil {
return nil, errInvalidECDHESPrivateKeyFormat
}

err = km.validateKeyFormat(keyFormat)
if err != nil {
return nil, errInvalidECDHESPrivateKeyFormat
}

curve, err := hybrid.GetCurve(keyFormat.Params.KemParams.CurveType.String())
if err != nil {
return nil, err
}

pvt, err := hybrid.GenerateECDHKeyPair(curve)
if err != nil {
return nil, err
}

return &ecdhespb.EcdhesAeadPrivateKey{
Version: ecdhesPrivateKeyVersion,
KeyValue: pvt.D.Bytes(),
PublicKey: &ecdhespb.EcdhesAeadPublicKey{
Version: ecdhesPrivateKeyVersion,
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 *ecdhesPrivateKeyManager) 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, err
}

return &tinkpb.KeyData{
TypeUrl: ecdhesPrivateKeyTypeURL,
Value: serializedKey,
KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE,
}, nil
}

func (km *ecdhesPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) {
privKey := new(ecdhespb.EcdhesAeadPrivateKey)

err := proto.Unmarshal(serializedPrivKey, privKey)
if err != nil {
return nil, errInvalidECDHESPrivateKey
}

serializedPubKey, err := proto.Marshal(privKey.PublicKey)
if err != nil {
return nil, errInvalidECDHESPrivateKey
}

return &tinkpb.KeyData{
TypeUrl: ecdhesPublicKeyTypeURL,
Value: serializedPubKey,
KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC,
}, nil
}

// DoesSupport indicates if this key manager supports the given key type.
func (km *ecdhesPrivateKeyManager) DoesSupport(typeURL string) bool {
return typeURL == ecdhesPrivateKeyTypeURL
}

// TypeURL returns the key type of keys managed by this key manager.
func (km *ecdhesPrivateKeyManager) TypeURL() string {
return ecdhesPrivateKeyTypeURL
}

// validateKey validates the given ECDHESPrivateKey.
func (km *ecdhesPrivateKeyManager) validateKey(key *ecdhespb.EcdhesAeadPrivateKey) error {
err := keyset.ValidateKeyVersion(key.Version, ecdhesPrivateKeyVersion)
if err != nil {
return fmt.Errorf("ecdhes_private_key_manager: invalid key: %s", err)
}

return checkECDHESParams(key.PublicKey.Params)
}

// validateKeyFormat validates the given ECDSAKeyFormat.
func (km *ecdhesPrivateKeyManager) validateKeyFormat(format *ecdhespb.EcdhesAeadKeyFormat) error {
return checkECDHESParams(format.Params)
}

func checkECDHESParams(params *ecdhespb.EcdhesAeadParams) error {
_, err := hybrid.GetCurve(params.KemParams.CurveType.String())
if err != nil {
return err
}

km, err := registry.GetKeyManager(params.DemParams.AeadDem.TypeUrl)
if err != nil {
return err
}

_, err = km.NewKeyData(params.DemParams.AeadDem.Value)
if err != nil {
return err
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package ecdhes

import (
"fmt"
"math/big"

"github.com/golang/protobuf/proto"
"github.com/google/tink/go/core/registry"
"github.com/google/tink/go/keyset"
"github.com/google/tink/go/subtle/hybrid"
tinkpb "github.com/google/tink/proto/tink_go_proto"

sbutleecdhes "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/jwe/subtle/ecdhes"
ecdhespb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdhes_aead_go_proto"
)

const (
ecdhesPublicKeyVersion = 0
ecdhesPublicKeyTypeURL = "type.googleapis.com/google.crypto.tink.EcdhesAeadPublicKey"
)

// common errors
var errInvalidECDHESPublicKey = fmt.Errorf("ecdhes_public_key_manager: invalid key")

// ecdhesPublicKeyManager is an implementation of KeyManager interface.
// It generates new ECDHESPublicKey keys and produces new instances of ECDHESPublicKey subtle.
type ecdhesPublicKeyManager struct{}

// Assert that ecdhesPublicKeyManager implements the KeyManager interface.
var _ registry.KeyManager = (*ecdhesPublicKeyManager)(nil)

// newECDHESPublicKeyManager creates a new aesGcmKeyManager.
func newECDHESPublicKeyManager() *ecdhesPublicKeyManager {
return new(ecdhesPublicKeyManager)
}

// Primitive creates an ECDHESPublicKey subtle for the given serialized ECDHESPublicKey proto.
func (km *ecdhesPublicKeyManager) Primitive(serializedKey []byte) (interface{}, error) {
if len(serializedKey) == 0 {
return nil, errInvalidECDHESPublicKey
}

key := new(ecdhespb.EcdhesAeadPublicKey)

err := proto.Unmarshal(serializedKey, key)
if err != nil {
return nil, errInvalidECDHESPublicKey
}

err = km.validateKey(key)
if err != nil {
return nil, errInvalidECDHESPublicKey
}

curve, err := hybrid.GetCurve(key.Params.KemParams.CurveType.String())
if err != nil {
return nil, err
}

pub := hybrid.ECPublicKey{
Curve: curve,
Point: hybrid.ECPoint{
X: new(big.Int).SetBytes(key.X),
Y: new(big.Int).SetBytes(key.Y),
},
}

rDem, err := newRegisterECDHESEncHelper(key.Params.DemParams.AeadDem)
if err != nil {
return nil, err
}

ptFormat := key.Params.EcPointFormat.String()

// TODO add support for multiple 'recipient' keys somehow.
// 1 key template is for 1 recipient only. A possible solution would be to update Encrypt() interface to take
// a list of recipients public keys.
return sbutleecdhes.NewECDHESEncrypt(&pub, ptFormat, rDem)
}

// DoesSupport indicates if this key manager supports the given key type.
func (km *ecdhesPublicKeyManager) DoesSupport(typeURL string) bool {
return typeURL == ecdhesPublicKeyTypeURL
}

// TypeURL returns the key type of keys managed by this key manager.
func (km *ecdhesPublicKeyManager) TypeURL() string {
return ecdhesPublicKeyTypeURL
}

// NewKey is not implemented for public key manager.
func (km *ecdhesPublicKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
return nil, fmt.Errorf("ecdhes_public_key_manager: NewKey not implemented")
}

// NewKeyData is not implemented for public key manager.
func (km *ecdhesPublicKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) {
return nil, fmt.Errorf("ecdhes_public_key_manager: NewKeyData not implemented")
}

// validateKey validates the given ECDHESPublicKey.
func (km *ecdhesPublicKeyManager) validateKey(key *ecdhespb.EcdhesAeadPublicKey) error {
err := keyset.ValidateKeyVersion(key.Version, ecdhesPublicKeyVersion)
if err != nil {
return fmt.Errorf("ecdhes_public_key_manager: invalid key: %s", err)
}

return checkECDHESParams(key.Params)
}
Loading

0 comments on commit 516c2ad

Please sign in to comment.