forked from hyperledger-archives/aries-framework-go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: second change for ECDH-1PU crypto primitive
Second chant to introduce ECDH-1PU Tink crypto primitive for Authcrypt (JWE) implementations: Includes new key/primitive key types, key managers and first core primitive logic with (incomplete, to be done in a followup change) 1PU key wrapping. Followup changes will include primitive factories, public key export/import logic, key templates and core 1PU logic. part of hyperledger-archives#1806 Signed-off-by: Baha Shaaban <[email protected]>
- Loading branch information
Baha Shaaban
committed
Jun 9, 2020
1 parent
393965c
commit 3f12331
Showing
14 changed files
with
2,148 additions
and
0 deletions.
There are no files selected for viewing
107 changes: 107 additions & 0 deletions
107
pkg/crypto/tinkcrypto/primitive/composite/ecdh1pu/ecdh1pu.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} | ||
} |
191 changes: 191 additions & 0 deletions
191
pkg/crypto/tinkcrypto/primitive/composite/ecdh1pu/ecdh1pu_aes_aead_private_key_manager.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.