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

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