Skip to content

Commit

Permalink
feat: first change for ECDH-1PU crypto primtive
Browse files Browse the repository at this point in the history
First change to introduce ECDH-1PU primitive:
Includes new key/primitive types, key managers, protobufs, first change of (incomplete) key wrapping logic.
Includes introduction of composite_common proto file for sharing the comment key type for ECDH-ES and ECHD-1PU.

Follow up changes will include primitive factories, key templates and 1PU implementation

part of hyperledger-archives#1806

Signed-off-by: Baha Shaaban <[email protected]>
  • Loading branch information
Baha Shaaban committed Jun 8, 2020
1 parent a10d75a commit 5a388c4
Show file tree
Hide file tree
Showing 43 changed files with 3,021 additions and 211 deletions.
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/tink v1.3.0 h1:CMg2wQ+VP5QUDwqV89+WpKuxv3I+pBrJ4/ziUS/kIEs=
github.com/google/tink v1.4.0-rc2.0.20200525085439-8bdaed4f41ed h1:uR4ckoAt+nUap2lX2rk61vD4Bq7Qlc++xwxnL6i9dto=
github.com/google/tink v1.4.0-rc2.0.20200525085439-8bdaed4f41ed/go.mod h1:eu7D8x3z2rMO7fyvHVhMx8yoFH+vH8EZR1uO3hjEIhQ=
github.com/google/tink/go v1.4.0-rc2 h1:QU7tW2FbEM4VjagwhxXFYuZXWLyfST2Z0EMLCCrMEmk=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package subtle
package composite

// package subtle provides the core crypto primitives to be used by composite primitives. It is intended for internal
// use only.
// package composite provides the core crypto composite primitives such as ECDH-ES and ECDH-1PU to be used by JWE
// crypto. It is intended for internal use only.

// EncryptedData represents the Encryption's output data as a result of ECDHESEncrypt.Encrypt(pt, aad) call
// The user of the primitive must unmarshal the result and build their own ECDH-ES compliant message (ie JWE msg)
Expand Down
107 changes: 107 additions & 0 deletions pkg/crypto/tinkcrypto/primitive/composite/ecdh1pu/ecdh1pu.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

// Package ecdh1pu provides implementations of payload encryption using ECDH-1PU KW key wrapping with AEAD primitives.
//
// The functionality of ecdh1pu Encryption is represented as a pair of
// primitives (interfaces):
//
// * ECDH1PUEncrypt for encryption of data and aad for a given list of recipients keys
//
// * ECDH1PUDecrypt for decryption of data for a certain recipient key and returning decrypted plaintext
//
//
// Example:
//
// package main
//
// import (
// "bytes"
//
// "github.com/google/tink/go/keyset"
//
// "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh1pu/subtle"
// "github.com/aries-framework-go/pkg/crypto/tinkcrypto/composite/ecdh1pu"
// )
//
// func main() {
// // create recipient side keyset handle
// recKH, err := keyset.NewHandle(ecdh1pu.ECDH1PU256KWAES256GCMKeyTemplate())
// if err != nil {
// //handle error
// }
//
// // extract recipient public keyset handle and key
// recPubKH, err := recKH.Public()
// if err != nil {
// //handle error
// }
//
// buf := new(bytes.Buffer)
// pubKeyWriter := ecdh1pu.NewWriter(buf)
// err = recPubKH.WriteWithNoSecrets(pubKeyWriter)
// if err != nil {
// //handle error
// }
//
// ecPubKey := new(subtle.ECPublicKey)
// err := json.Unmarshal(buf.Bytes(), ecPubKey)
//
// // now create sender keyset handle with recipient public key (ecPubKey)
// sKH, err := keyset.NewHandle(ECDH1PU256KWAES256GCMKeyTemplateWithRecipients(
// []subtle.ECPublicKey{*ecPubKey}))
// if err != nil {
// // handle error
// }
//
// // for more recipient keys pass in a list: []subtle.ECPublicKey{*ecPubKey1, *ecPubKey2, *ecPubKey3, etc.})
// // at least 1 recipient is required.
//
// // extract sender public keyset handle to encrypt
// senderPubKH, err := sKH.Public()
// if err != nil {
// //handle error
// }
//
// e := ecdh1pu.NewECDH1PUEncrypt(senderPubKH)
//
// ct, err = e.Encrypt([]byte("secret message"), []byte("some aad"))
// if err != nil {
// // handle error
// }
//
// // get a handle on the decryption key material for a recipient
// // this is usually reloading the recipient's keyset handle (ie: `recKH` above) from a kms
// refRecKH , err := keyset.NewHandle( .....reference/rebuild `recKH` here...);
// d := ecdh1pu.NewECDH1PUDecrypt(refRecKH)
//
// pt, err := d.Decrypt(ct)
// if err != nil {
// // handle error
// }
// }
package ecdh1pu

import (
"fmt"

"github.com/google/tink/go/core/registry"
)

// TODO - find a better way to setup tink than init.
// nolint: gochecknoinits
func init() {
// TODO - avoid the tink registry singleton (if possible).
err := registry.RegisterKeyManager(newECDH1PUPrivateKeyManager())
if err != nil {
panic(fmt.Sprintf("ecdh1pu.init() failed: %v", err))
}

err = registry.RegisterKeyManager(newECDH1PUPublicKeyManager())
if err != nil {
panic(fmt.Sprintf("ecdh1pu.init() failed: %v", err))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package ecdh1pu

import (
"crypto/elliptic"
"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/ecdh1pu/subtle"
commonpb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/common_composite_go_proto"
ecdh1pupb "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/proto/ecdh1pu_aead_go_proto"
)

const (
ecdh1puAESPrivateKeyVersion = 0
ecdh1puAESPrivateKeyTypeURL = "type.hyperledger.org/hyperledger.aries.crypto.tink.Ecdh1puAesAeadPrivateKey"
)

// common errors
var errInvalidECDH1PUAESPrivateKey = fmt.Errorf("ecdh1pu_aes_private_key_manager: invalid key")
var errInvalidECDH1PUAESPrivateKeyFormat = fmt.Errorf("ecdh1pu_aes_private_key_manager: invalid key format")

// ecdh1puAESPrivateKeyManager is an implementation of PrivateKeyManager interface.
// It generates new ECDHESPrivateKey (AES) keys and produces new instances of ECDH1PUAEADCompositeDecrypt subtle.
type ecdh1puAESPrivateKeyManager struct{}

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

// newECDH1PUPrivateKeyManager creates a new ecdh1puAESPrivateKeyManager.
func newECDH1PUPrivateKeyManager() *ecdh1puAESPrivateKeyManager {
return new(ecdh1puAESPrivateKeyManager)
}

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

key := new(ecdh1pupb.Ecdh1PuAeadPrivateKey)

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

curve, err := km.validateKey(key)
if err != nil {
return nil, errInvalidECDH1PUAESPrivateKey
}

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

rEnc, err := newRegisterECDH1PUAEADEncHelper(key.PublicKey.Params.EncParams.AeadEnc)
if err != nil {
return nil, err
}

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

return subtle.NewECDH1PUAEADCompositeDecrypt(pvt, ptFormat, rEnc, commonpb.KeyType_EC), nil
}

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

keyFormat := new(ecdh1pupb.Ecdh1PuAeadKeyFormat)

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

curve, err := validateKeyFormat(keyFormat.Params)
if err != nil {
return nil, errInvalidECDH1PUAESPrivateKeyFormat
}

keyFormat.Params.KwParams.KeyType = commonpb.KeyType_EC

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

return &ecdh1pupb.Ecdh1PuAeadPrivateKey{
Version: ecdh1puAESPrivateKeyVersion,
KeyValue: pvt.D.Bytes(),
PublicKey: &ecdh1pupb.Ecdh1PuAeadPublicKey{
Version: ecdh1puAESPrivateKeyVersion,
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 *ecdh1puAESPrivateKeyManager) 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: ecdh1puAESPrivateKeyTypeURL,
Value: serializedKey,
KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE,
}, nil
}

// PublicKeyData returns the enclosed public key data of serializedPrivKey
func (km *ecdh1puAESPrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) {
privKey := new(ecdh1pupb.Ecdh1PuAeadPrivateKey)

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

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

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

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

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

// validateKey validates the given ECDH1PUPrivateKey and returns the KW curve.
func (km *ecdh1puAESPrivateKeyManager) validateKey(key *ecdh1pupb.Ecdh1PuAeadPrivateKey) (elliptic.Curve, error) {
err := keyset.ValidateKeyVersion(key.Version, ecdh1puAESPrivateKeyVersion)
if err != nil {
return nil, fmt.Errorf("ecdh1pu_private_key_manager: invalid key: %s", err)
}

return validateKeyFormat(key.PublicKey.Params)
}

// validateKeyFormat validates the given ECDHESKeyFormat and returns the KW Curve.
func validateKeyFormat(params *ecdh1pupb.Ecdh1PuAeadParams) (elliptic.Curve, error) {
c, err := hybrid.GetCurve(params.KwParams.CurveType.String())
if err != nil {
return nil, err
}

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

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

return c, nil
}
Loading

0 comments on commit 5a388c4

Please sign in to comment.