github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/composite/ecdh/ecdh_nistpkw_private_key_manager.go (about)

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