From a352bb44d51b00664a48205d6ad829ad3e5c2822 Mon Sep 17 00:00:00 2001 From: Filip Burlacu Date: Fri, 8 Nov 2019 14:03:17 -0500 Subject: [PATCH] feat: Packager now holds multiple packers, indexed by `Typ` field. Packager can select Packer for decryption based on the Typ field of the input message. Fixes #273 Signed-off-by: Filip Burlacu --- pkg/didcomm/common/transport/envelope.go | 14 + pkg/didcomm/common/transport/packager.go | 38 +++ pkg/didcomm/dispatcher/api.go | 4 +- pkg/didcomm/dispatcher/outbound.go | 6 +- pkg/didcomm/dispatcher/outbound_test.go | 16 +- pkg/didcomm/envelope/api.go | 50 --- pkg/didcomm/envelope/package_test.go | 207 ------------ pkg/didcomm/envelope/packager.go | 68 ---- pkg/didcomm/packager/package_test.go | 294 ++++++++++++++++++ pkg/didcomm/packager/packager.go | 154 +++++++++ .../{envelope/packer.go => packer/api.go} | 12 +- pkg/didcomm/packer/jwe/authcrypt/authcrypt.go | 30 +- .../packer/jwe/authcrypt/authcrypt_test.go | 89 ++++-- pkg/didcomm/packer/jwe/authcrypt/common.go | 2 + .../packer/jwe/authcrypt/decrypt_jwk.go | 20 +- .../packer/jwe/authcrypt/decrypt_jwk_test.go | 24 +- .../packer/jwe/authcrypt/encrypt_jwk.go | 22 +- .../packer/jwe/authcrypt/encrypt_jwk_test.go | 20 +- pkg/didcomm/packer/jwe/authcrypt/pack.go | 56 ++-- pkg/didcomm/packer/jwe/authcrypt/unpack.go | 38 +-- .../packer/legacy/authcrypt/authcrypt.go | 16 +- .../packer/legacy/authcrypt/authcrypt_test.go | 89 ++++-- pkg/didcomm/packer/legacy/authcrypt/pack.go | 2 +- pkg/didcomm/packer/legacy/authcrypt/unpack.go | 2 +- pkg/didcomm/transport/http/inbound.go | 4 +- pkg/didcomm/transport/http/inbound_test.go | 14 +- pkg/didcomm/transport/transport_interface.go | 4 +- pkg/framework/aries/api/protocol.go | 5 +- pkg/framework/aries/default.go | 26 +- pkg/framework/aries/framework.go | 48 ++- pkg/framework/aries/framework_test.go | 44 ++- pkg/framework/context/context.go | 33 +- pkg/framework/context/context_test.go | 29 +- .../mock/didcomm/envelope/mock_packager.go | 27 -- pkg/internal/mock/didcomm/mock_authcrypt.go | 10 +- .../mock/didcomm/packager/mock_packager.go | 29 ++ pkg/internal/mock/kms/mock_kms.go | 4 +- pkg/internal/mock/provider/mock_provider.go | 14 +- 38 files changed, 972 insertions(+), 592 deletions(-) create mode 100644 pkg/didcomm/common/transport/envelope.go create mode 100644 pkg/didcomm/common/transport/packager.go delete mode 100644 pkg/didcomm/envelope/api.go delete mode 100644 pkg/didcomm/envelope/package_test.go delete mode 100644 pkg/didcomm/envelope/packager.go create mode 100644 pkg/didcomm/packager/package_test.go create mode 100644 pkg/didcomm/packager/packager.go rename pkg/didcomm/{envelope/packer.go => packer/api.go} (82%) delete mode 100644 pkg/internal/mock/didcomm/envelope/mock_packager.go create mode 100644 pkg/internal/mock/didcomm/packager/mock_packager.go diff --git a/pkg/didcomm/common/transport/envelope.go b/pkg/didcomm/common/transport/envelope.go new file mode 100644 index 0000000000..c910c7a0f8 --- /dev/null +++ b/pkg/didcomm/common/transport/envelope.go @@ -0,0 +1,14 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package transport + +// Envelope contain msg, FromVerKey and ToVerKeys +type Envelope struct { + Message []byte + FromVerKey string + ToVerKeys []string +} diff --git a/pkg/didcomm/common/transport/packager.go b/pkg/didcomm/common/transport/packager.go new file mode 100644 index 0000000000..028b295fb1 --- /dev/null +++ b/pkg/didcomm/common/transport/packager.go @@ -0,0 +1,38 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package transport + +// Packager manages the handling, building and parsing of DIDComm raw messages in JSON envelopes. +// +// These envelopes are used as wire-level wrappers of messages sent in Aries agent-agent communication. +type Packager interface { + // PackMessage Pack a message for one or more recipients. + // + // Args: + // + // envelope: The message to pack + // + // Returns: + // + // []byte: The packed message + // + // error: error + PackMessage(envelope *Envelope) ([]byte, error) + + // UnpackMessage Unpack a message. + // + // Args: + // + // encMessage: The encrypted message + // + // Returns: + // + // envelope: unpack message + // + // error: error + UnpackMessage(encMessage []byte) (*Envelope, error) +} diff --git a/pkg/didcomm/dispatcher/api.go b/pkg/didcomm/dispatcher/api.go index 4587b4563f..5d5671bbc8 100644 --- a/pkg/didcomm/dispatcher/api.go +++ b/pkg/didcomm/dispatcher/api.go @@ -8,7 +8,7 @@ package dispatcher import ( "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + transport2 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" ) @@ -26,7 +26,7 @@ type Outbound interface { // Provider interface for outbound ctx type Provider interface { - Packager() envelope.Packager + Packager() transport2.Packager OutboundTransports() []transport.OutboundTransport } diff --git a/pkg/didcomm/dispatcher/outbound.go b/pkg/didcomm/dispatcher/outbound.go index cb4d11f795..d37d433e0e 100644 --- a/pkg/didcomm/dispatcher/outbound.go +++ b/pkg/didcomm/dispatcher/outbound.go @@ -11,14 +11,14 @@ import ( "fmt" "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + transport2 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" ) // OutboundDispatcher dispatch msgs to destination type OutboundDispatcher struct { outboundTransports []transport.OutboundTransport - packager envelope.Packager + packager transport2.Packager } // NewOutbound return new dispatcher outbound instance @@ -39,7 +39,7 @@ func (o *OutboundDispatcher) Send(msg interface{}, senderVerKey string, des *ser } packedMsg, err := o.packager.PackMessage( - &envelope.Envelope{Message: bytes, FromVerKey: senderVerKey, ToVerKeys: des.RecipientKeys}) + &transport2.Envelope{Message: bytes, FromVerKey: senderVerKey, ToVerKeys: des.RecipientKeys}) if err != nil { return fmt.Errorf("failed to pack msg: %w", err) } diff --git a/pkg/didcomm/dispatcher/outbound_test.go b/pkg/didcomm/dispatcher/outbound_test.go index 2b5dc40eba..1af0d0f3a9 100644 --- a/pkg/didcomm/dispatcher/outbound_test.go +++ b/pkg/didcomm/dispatcher/outbound_test.go @@ -13,21 +13,21 @@ import ( "github.com/stretchr/testify/require" "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + transport2 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" mockdidcomm "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm" - mockpackager "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/envelope" + mockpackager "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/packager" ) func TestOutboundDispatcher_Send(t *testing.T) { t.Run("test success", func(t *testing.T) { - o := NewOutbound(&provider{packagerValue: &mockpackager.BasePackager{}, + o := NewOutbound(&provider{packagerValue: &mockpackager.Packager{}, outboundTransportsValue: []transport.OutboundTransport{&mockdidcomm.MockOutboundTransport{AcceptValue: true}}}) require.NoError(t, o.Send("data", "", &service.Destination{ServiceEndpoint: "url"})) }) t.Run("test no outbound transport found", func(t *testing.T) { - o := NewOutbound(&provider{packagerValue: &mockpackager.BasePackager{}, + o := NewOutbound(&provider{packagerValue: &mockpackager.Packager{}, outboundTransportsValue: []transport.OutboundTransport{&mockdidcomm.MockOutboundTransport{AcceptValue: false}}}) err := o.Send("data", "", &service.Destination{ServiceEndpoint: "url"}) require.Error(t, err) @@ -35,7 +35,7 @@ func TestOutboundDispatcher_Send(t *testing.T) { }) t.Run("test pack msg failure", func(t *testing.T) { - o := NewOutbound(&provider{packagerValue: &mockpackager.BasePackager{PackErr: fmt.Errorf("pack error")}, + o := NewOutbound(&provider{packagerValue: &mockpackager.Packager{PackErr: fmt.Errorf("pack error")}, outboundTransportsValue: []transport.OutboundTransport{&mockdidcomm.MockOutboundTransport{AcceptValue: true}}}) err := o.Send("data", "", &service.Destination{ServiceEndpoint: "url"}) require.Error(t, err) @@ -43,7 +43,7 @@ func TestOutboundDispatcher_Send(t *testing.T) { }) t.Run("test outbound send failure", func(t *testing.T) { - o := NewOutbound(&provider{packagerValue: &mockpackager.BasePackager{}, + o := NewOutbound(&provider{packagerValue: &mockpackager.Packager{}, outboundTransportsValue: []transport.OutboundTransport{ &mockdidcomm.MockOutboundTransport{AcceptValue: true, SendErr: fmt.Errorf("send error")}}}) err := o.Send("data", "", &service.Destination{ServiceEndpoint: "url"}) @@ -53,11 +53,11 @@ func TestOutboundDispatcher_Send(t *testing.T) { } type provider struct { - packagerValue envelope.Packager + packagerValue transport2.Packager outboundTransportsValue []transport.OutboundTransport } -func (p *provider) Packager() envelope.Packager { +func (p *provider) Packager() transport2.Packager { return p.packagerValue } diff --git a/pkg/didcomm/envelope/api.go b/pkg/didcomm/envelope/api.go deleted file mode 100644 index 8f61fa2280..0000000000 --- a/pkg/didcomm/envelope/api.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package envelope - -// Package envelope manages the handling of DIDComm raw messages in JWE compliant envelopes. -// The aim of this package is build these envelopes and parse them. They are mainly used as -// wire-level wrappers of 'payloads' used in DID Exchange flows. - -// PackagerCreator method to create new outbound dispatcher service -type PackagerCreator func(prov PackerProvider) (Packager, error) - -// Packager provide methods to pack and unpack msg -type Packager interface { - // PackMessage Pack a message for one or more recipients. - // - // Args: - // - // envelope: The message to pack - // - // Returns: - // - // []byte: The packed message - // - // error: error - PackMessage(envelope *Envelope) ([]byte, error) - - // UnpackMessage Unpack a message. - // - // Args: - // - // encMessage: The encrypted message - // - // Returns: - // - // envelope: unpack message - // - // error: error - UnpackMessage(encMessage []byte) (*Envelope, error) -} - -// Envelope contain msg, FromVerKey and ToVerKeys -type Envelope struct { - Message []byte - FromVerKey string - ToVerKeys []string -} diff --git a/pkg/didcomm/envelope/package_test.go b/pkg/didcomm/envelope/package_test.go deleted file mode 100644 index 040af56cb7..0000000000 --- a/pkg/didcomm/envelope/package_test.go +++ /dev/null @@ -1,207 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package envelope_test - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer/jwe/authcrypt" - "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm" - mockstorage "github.com/hyperledger/aries-framework-go/pkg/internal/mock/storage" - "github.com/hyperledger/aries-framework-go/pkg/kms" - "github.com/hyperledger/aries-framework-go/pkg/storage" -) - -func TestBaseKMSInPackager_UnpackMessage(t *testing.T) { - t.Run("test failed to unmarshal encMessage", func(t *testing.T) { - w, err := kms.New(newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ - Store: make(map[string][]byte), - }})) - require.NoError(t, err) - - mockedProviders := &mockProvider{nil, w, nil} - testPacker, err := authcrypt.New(mockedProviders, authcrypt.XC20P) - require.NoError(t, err) - - mockedProviders.packer = testPacker - packager, err := envelope.New(mockedProviders) - require.NoError(t, err) - _, err = packager.UnpackMessage(nil) - require.Error(t, err) - require.EqualError(t, err, "failed from decrypt: failed to decrypt message: unexpected end of JSON input") - }) - - t.Run("test key not found", func(t *testing.T) { - wp := newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ - Store: make(map[string][]byte), - }}) - w, err := kms.New(wp) - require.NoError(t, err) - - mockedProviders := &mockProvider{nil, w, nil} - testPacker, err := authcrypt.New(mockedProviders, authcrypt.XC20P) - require.NoError(t, err) - - // use a real testPacker with a mocked KMS to validate pack/unpack - mockedProviders.packer = testPacker - packager, err := envelope.New(mockedProviders) - require.NoError(t, err) - - // fromKey is stored in the KMS - _, base58FromVerKey, err := w.CreateKeySet() - require.NoError(t, err) - - // toVerKey is stored in the KMS as well - base58ToEncKey, base58ToVerKey, err := w.CreateKeySet() - require.NoError(t, err) - - // PackMessage should pass with both value from and to verification keys - packMsg, err := packager.PackMessage(&envelope.Envelope{Message: []byte("msg1"), - FromVerKey: base58FromVerKey, - ToVerKeys: []string{base58ToVerKey}}) - require.NoError(t, err) - - // mock KMS without ToVerKey and ToEncKey then try UnpackMessage - delete(wp.storage.Store.Store, base58ToVerKey) - delete(wp.storage.Store.Store, base58ToEncKey) - // It should fail since Recipient keys are not found in the KMS - _, err = packager.UnpackMessage(packMsg) - require.Error(t, err) - require.EqualError(t, err, "failed from decrypt: failed to decrypt message: key not found") - }) - - t.Run("test Pack/Unpack fails", func(t *testing.T) { - w, err := kms.New(newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ - Store: make(map[string][]byte), - }})) - require.NoError(t, err) - - decryptValue := func(envelope []byte) ([]byte, error) { - return nil, fmt.Errorf("decrypt error") - } - - mockedProviders := &mockProvider{nil, w, nil} - - // use a mocked packer with a mocked KMS to validate pack/unpack - e := func(payload []byte, senderPubKey []byte, recipientsKeys [][]byte) (bytes []byte, e error) { - crypter, e := authcrypt.New(mockedProviders, authcrypt.XC20P) - require.NoError(t, e) - return crypter.Pack(payload, senderPubKey, recipientsKeys) - } - mockPacker := &didcomm.MockAuthCrypt{DecryptValue: decryptValue, - EncryptValue: e} - - mockedProviders.packer = mockPacker - - packager, err := envelope.New(mockedProviders) - require.NoError(t, err) - - _, base58FromVerKey, err := w.CreateKeySet() - require.NoError(t, err) - - _, base58ToVerKey, err := w.CreateKeySet() - require.NoError(t, err) - - // try pack with nil envelope - should fail - packMsg, err := packager.PackMessage(nil) - require.EqualError(t, err, "envelope argument is nil") - require.Empty(t, packMsg) - - // now try to pack with non empty envelope - should pass - packMsg, err = packager.PackMessage(&envelope.Envelope{Message: []byte("msg1"), - FromVerKey: base58FromVerKey, - ToVerKeys: []string{base58ToVerKey}}) - require.NoError(t, err) - require.NotEmpty(t, packMsg) - - // now try unpack - should fail since we mocked the packer's Unpack value to return "decrypt error" - // see 'decryptValue' above - _, err = packager.UnpackMessage(packMsg) - require.Error(t, err) - require.EqualError(t, err, "failed from decrypt: decrypt error") - - // now mock encrypt failure to test PackMessage with non empty envelope - e = func(payload []byte, senderPubKey []byte, recipientsKeys [][]byte) (bytes []byte, e error) { - return nil, fmt.Errorf("encrypt error") - } - mockPacker = &didcomm.MockAuthCrypt{EncryptValue: e} - mockedProviders.packer = mockPacker - packager, err = envelope.New(mockedProviders) - require.NoError(t, err) - packMsg, err = packager.PackMessage(&envelope.Envelope{Message: []byte("msg1"), - FromVerKey: base58FromVerKey, - ToVerKeys: []string{base58ToVerKey}}) - require.Error(t, err) - require.Empty(t, packMsg) - require.EqualError(t, err, "failed from encrypt: encrypt error") - }) - - t.Run("test Pack/Unpack success", func(t *testing.T) { - // create a mock KMS with storage as a map - w, err := kms.New(newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ - Store: map[string][]byte{}}})) - require.NoError(t, err) - mockedProviders := &mockProvider{nil, w, nil} - - // create a real testPacker (no mocking here) - testPacker, err := authcrypt.New(mockedProviders, authcrypt.XC20P) - require.NoError(t, err) - mockedProviders.packer = testPacker - - // now create a new packager with the above provider context - packager, err := envelope.New(mockedProviders) - require.NoError(t, err) - - _, base58FromVerKey, err := w.CreateKeySet() - require.NoError(t, err) - - _, base58ToVerKey, err := w.CreateKeySet() - require.NoError(t, err) - - // pack an non empty envelope - should pass - packMsg, err := packager.PackMessage(&envelope.Envelope{Message: []byte("msg1"), - FromVerKey: base58FromVerKey, - ToVerKeys: []string{base58ToVerKey}}) - require.NoError(t, err) - - // unpack the packed message above - should pass and match the same payload (msg1) - unpackedMsg, err := packager.UnpackMessage(packMsg) - require.NoError(t, err) - require.Equal(t, unpackedMsg.Message, []byte("msg1")) - }) -} - -func newMockKMSProvider(storagePvdr *mockstorage.MockStoreProvider) *mockProvider { - return &mockProvider{storagePvdr, nil, nil} -} - -// mockProvider mocks provider for KMS -type mockProvider struct { - storage *mockstorage.MockStoreProvider - kms kms.KeyManager - packer envelope.Packer -} - -func (m *mockProvider) Packer() envelope.Packer { - return m.packer -} - -func (m *mockProvider) KMS() kms.KeyManager { - return m.kms -} - -func (m *mockProvider) StorageProvider() storage.Provider { - return m.storage -} - -func (m *mockProvider) InboundTransportEndpoint() string { - return "sample-endpoint.com" -} diff --git a/pkg/didcomm/envelope/packager.go b/pkg/didcomm/envelope/packager.go deleted file mode 100644 index 45dfa79b17..0000000000 --- a/pkg/didcomm/envelope/packager.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package envelope - -import ( - "errors" - "fmt" - - "github.com/btcsuite/btcutil/base58" -) - -// PackerProvider contains dependencies for the base packager and is typically created by using aries.Context() -type PackerProvider interface { - Packer() Packer -} - -// BasePackager is the basic implementation of Packager -type BasePackager struct { - packer Packer -} - -// New return new instance of KMS implementation -func New(ctx PackerProvider) (*BasePackager, error) { - crypter := ctx.Packer() - - return &BasePackager{packer: crypter}, nil -} - -// PackMessage Pack a message for one or more recipients. -func (p *BasePackager) PackMessage(envelope *Envelope) ([]byte, error) { - if envelope == nil { - return nil, errors.New("envelope argument is nil") - } - - var recipients [][]byte - - for _, verKey := range envelope.ToVerKeys { - // TODO It is possible to have different key schemes in an interop situation - // there is no guarantee that each recipient is using the same key types - // for now this package uses Ed25519 signing keys. Other key schemes should have their own - // packer implementations. - // decode base58 ver key - verKeyBytes := base58.Decode(verKey) - // create 32 byte key - recipients = append(recipients, verKeyBytes) - } - // encrypt message - bytes, err := p.packer.Pack(envelope.Message, base58.Decode(envelope.FromVerKey), recipients) - if err != nil { - return nil, fmt.Errorf("failed from encrypt: %w", err) - } - - return bytes, nil -} - -// UnpackMessage Unpack a message. -func (p *BasePackager) UnpackMessage(encMessage []byte) (*Envelope, error) { - bytes, err := p.packer.Unpack(encMessage) - if err != nil { - return nil, fmt.Errorf("failed from decrypt: %w", err) - } - // TODO extract fromVerKey and toVerKey from packer.Unpack() call above and set them here - return &Envelope{Message: bytes}, nil -} diff --git a/pkg/didcomm/packager/package_test.go b/pkg/didcomm/packager/package_test.go new file mode 100644 index 0000000000..0203a0ada6 --- /dev/null +++ b/pkg/didcomm/packager/package_test.go @@ -0,0 +1,294 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package packager_test + +import ( + "encoding/base64" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" + . "github.com/hyperledger/aries-framework-go/pkg/didcomm/packager" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" + jwe "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer/jwe/authcrypt" + legacy "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer/legacy/authcrypt" + "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm" + mockstorage "github.com/hyperledger/aries-framework-go/pkg/internal/mock/storage" + "github.com/hyperledger/aries-framework-go/pkg/kms" + "github.com/hyperledger/aries-framework-go/pkg/storage" +) + +func TestBaseKMSInPackager_UnpackMessage(t *testing.T) { + t.Run("test failed to unmarshal encMessage", func(t *testing.T) { + w, err := kms.New(newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ + Store: make(map[string][]byte), + }})) + require.NoError(t, err) + + mockedProviders := &mockProvider{ + storage: nil, + kms: w, + outboundPacker: nil, + packers: nil, + } + testPacker, err := jwe.New(mockedProviders, jwe.XC20P) + require.NoError(t, err) + + mockedProviders.outboundPacker = testPacker + packager, err := New(mockedProviders) + require.NoError(t, err) + _, err = packager.UnpackMessage(nil) + require.Error(t, err) + require.Contains(t, err.Error(), "unexpected end of JSON input") + }) + + t.Run("test bad encoding type", func(t *testing.T) { + w, err := kms.New(newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ + Store: make(map[string][]byte), + }})) + require.NoError(t, err) + + mockedProviders := &mockProvider{ + storage: nil, + kms: w, + outboundPacker: nil, + packers: nil, + } + testPacker, err := jwe.New(mockedProviders, jwe.XC20P) + require.NoError(t, err) + + mockedProviders.outboundPacker = testPacker + packager, err := New(mockedProviders) + require.NoError(t, err) + + msg := []byte(`{"protected":"` + base64.RawURLEncoding.EncodeToString([]byte(`{"typ":"badtype"}`)) + `"}`) + + _, err = packager.UnpackMessage(msg) + require.Error(t, err) + require.Contains(t, err.Error(), "message Type not recognized") + + msg = []byte(`{"protected":"` + "## NOT B64 ##" + `"}`) + + _, err = packager.UnpackMessage(msg) + require.Error(t, err) + require.Contains(t, err.Error(), "illegal base64 data") + + msg = []byte(`{"protected":"` + base64.RawURLEncoding.EncodeToString([]byte(`## NOT JSON ##`)) + `"}`) + + _, err = packager.UnpackMessage(msg) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid character") + }) + + t.Run("test key not found", func(t *testing.T) { + wp := newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ + Store: make(map[string][]byte), + }}) + w, err := kms.New(wp) + require.NoError(t, err) + + mockedProviders := &mockProvider{ + storage: nil, + kms: w, + outboundPacker: nil, + packers: nil, + } + testPacker, err := jwe.New(mockedProviders, jwe.XC20P) + require.NoError(t, err) + + // use a real testPacker with a mocked KMS to validate pack/unpack + mockedProviders.outboundPacker = testPacker + packager, err := New(mockedProviders) + require.NoError(t, err) + + // fromKey is stored in the KMS + _, base58FromVerKey, err := w.CreateKeySet() + require.NoError(t, err) + + // toVerKey is stored in the KMS as well + base58ToEncKey, base58ToVerKey, err := w.CreateKeySet() + require.NoError(t, err) + + // PackMessage should pass with both value from and to verification keys + packMsg, err := packager.PackMessage(&transport.Envelope{Message: []byte("msg1"), + FromVerKey: base58FromVerKey, + ToVerKeys: []string{base58ToVerKey}}) + require.NoError(t, err) + + // mock KMS without ToVerKey and ToEncKey then try UnpackMessage + delete(wp.storage.Store.Store, base58ToVerKey) + delete(wp.storage.Store.Store, base58ToEncKey) + // It should fail since Recipient keys are not found in the KMS + _, err = packager.UnpackMessage(packMsg) + require.Error(t, err) + require.Contains(t, err.Error(), "key not found") + }) + + t.Run("test Pack/Unpack fails", func(t *testing.T) { + w, err := kms.New(newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ + Store: make(map[string][]byte), + }})) + require.NoError(t, err) + + decryptValue := func(envelope []byte) ([]byte, error) { + return nil, fmt.Errorf("unpack error") + } + + mockedProviders := &mockProvider{ + storage: nil, + kms: w, + outboundPacker: nil, + packers: nil, + } + + // use a mocked packager with a mocked KMS to validate pack/unpack + e := func(payload []byte, senderPubKey []byte, recipientsKeys [][]byte) (bytes []byte, e error) { + packer, e := jwe.New(mockedProviders, jwe.XC20P) + require.NoError(t, e) + return packer.Pack(payload, senderPubKey, recipientsKeys) + } + mockPacker := &didcomm.MockAuthCrypt{DecryptValue: decryptValue, + EncryptValue: e, Type: "prs.hyperledger.aries-auth-message"} + + mockedProviders.outboundPacker = mockPacker + + packager, err := New(mockedProviders) + require.NoError(t, err) + + _, base58FromVerKey, err := w.CreateKeySet() + require.NoError(t, err) + + _, base58ToVerKey, err := w.CreateKeySet() + require.NoError(t, err) + + // try pack with nil envelope - should fail + packMsg, err := packager.PackMessage(nil) + require.EqualError(t, err, "envelope argument is nil") + require.Empty(t, packMsg) + + // now try to pack with non empty envelope - should pass + packMsg, err = packager.PackMessage(&transport.Envelope{Message: []byte("msg1"), + FromVerKey: base58FromVerKey, + ToVerKeys: []string{base58ToVerKey}}) + require.NoError(t, err) + require.NotEmpty(t, packMsg) + + // now try unpack - should fail since we mocked the packager's Unpack value to return "decrypt error" + // see 'decryptValue' above + _, err = packager.UnpackMessage(packMsg) + require.Error(t, err) + require.EqualError(t, err, "unpack: unpack error") + + // now mock pack failure to test PackMessage with non empty envelope + e = func(payload []byte, senderPubKey []byte, recipientsKeys [][]byte) (bytes []byte, e error) { + return nil, fmt.Errorf("pack error") + } + mockPacker = &didcomm.MockAuthCrypt{EncryptValue: e} + mockedProviders.outboundPacker = mockPacker + packager, err = New(mockedProviders) + require.NoError(t, err) + packMsg, err = packager.PackMessage(&transport.Envelope{Message: []byte("msg1"), + FromVerKey: base58FromVerKey, + ToVerKeys: []string{base58ToVerKey}}) + require.Error(t, err) + require.Empty(t, packMsg) + require.EqualError(t, err, "pack: pack error") + }) + + t.Run("test Pack/Unpack success", func(t *testing.T) { + // create a mock KMS with storage as a map + w, err := kms.New(newMockKMSProvider(&mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{ + Store: map[string][]byte{}}})) + require.NoError(t, err) + mockedProviders := &mockProvider{ + storage: nil, + kms: w, + outboundPacker: nil, + packers: nil, + } + + // create a real testPacker (no mocking here) + testPacker, err := jwe.New(mockedProviders, jwe.XC20P) + require.NoError(t, err) + mockedProviders.outboundPacker = testPacker + + legacyPacker := legacy.New(mockedProviders) + mockedProviders.packers = []packer.Packer{testPacker, legacyPacker} + + // now create a new packager with the above provider context + packager, err := New(mockedProviders) + require.NoError(t, err) + + _, base58FromVerKey, err := w.CreateKeySet() + require.NoError(t, err) + + _, base58ToVerKey, err := w.CreateKeySet() + require.NoError(t, err) + + // pack an non empty envelope - should pass + packMsg, err := packager.PackMessage(&transport.Envelope{Message: []byte("msg1"), + FromVerKey: base58FromVerKey, + ToVerKeys: []string{base58ToVerKey}}) + require.NoError(t, err) + + // unpack the packed message above - should pass and match the same payload (msg1) + unpackedMsg, err := packager.UnpackMessage(packMsg) + require.NoError(t, err) + require.Equal(t, unpackedMsg.Message, []byte("msg1")) + + // pack with legacy, unpack using a packager that has JWE as default but supports legacy + + mockedProviders.outboundPacker = legacyPacker + + packager2, err := New(mockedProviders) + require.NoError(t, err) + + packMsg, err = packager2.PackMessage(&transport.Envelope{Message: []byte("msg2"), + FromVerKey: base58FromVerKey, + ToVerKeys: []string{base58ToVerKey}}) + require.NoError(t, err) + + // unpack the packed message above - should pass and match the same payload (msg2) + unpackedMsg, err = packager.UnpackMessage(packMsg) + require.NoError(t, err) + require.Equal(t, unpackedMsg.Message, []byte("msg2")) + }) +} + +func newMockKMSProvider(storagePvdr *mockstorage.MockStoreProvider) *mockProvider { + return &mockProvider{storagePvdr, nil, nil, nil} +} + +// mockProvider mocks provider for KMS +type mockProvider struct { + storage *mockstorage.MockStoreProvider + kms kms.KeyManager + packers []packer.Packer + outboundPacker packer.Packer +} + +func (m *mockProvider) InboundPackers() []packer.Packer { + return m.packers +} + +func (m *mockProvider) KMS() kms.KeyManager { + return m.kms +} + +func (m *mockProvider) StorageProvider() storage.Provider { + return m.storage +} + +func (m *mockProvider) InboundTransportEndpoint() string { + return "sample-endpoint.com" +} + +func (m *mockProvider) Packer() packer.Packer { + return m.outboundPacker +} diff --git a/pkg/didcomm/packager/packager.go b/pkg/didcomm/packager/packager.go new file mode 100644 index 0000000000..dd74786b33 --- /dev/null +++ b/pkg/didcomm/packager/packager.go @@ -0,0 +1,154 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package packager + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + + "github.com/btcsuite/btcutil/base58" + + "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" +) + +// Provider contains dependencies for the base packager and is typically created by using aries.Context() +type Provider interface { + InboundPackers() []packer.Packer + Packer() packer.Packer +} + +// Creator method to create new packager service +type Creator func(prov Provider) (transport.Packager, error) + +// Packager is the basic implementation of Packager +type Packager struct { + packer packer.Packer + inboundPackers map[string]packer.Packer +} + +// PackerCreator holds a creator function for a Packer and the name of the Packer's encoding method. +type PackerCreator struct { + PackerName string + Creator packer.Creator +} + +// New return new instance of KMS implementation +func New(ctx Provider) (*Packager, error) { + basePackager := Packager{ + packer: nil, + inboundPackers: map[string]packer.Packer{}, + } + + for _, packerType := range ctx.InboundPackers() { + basePackager.addPacker(packerType) + } + + basePackager.packer = ctx.Packer() + if basePackager.packer == nil { + return nil, fmt.Errorf("need outbound packer to initialize packager") + } + + basePackager.addPacker(basePackager.packer) + + return &basePackager, nil +} + +func (bp *Packager) addPacker(pack packer.Packer) { + if bp.inboundPackers[pack.EncodingType()] == nil { + bp.inboundPackers[pack.EncodingType()] = pack + } +} + +// PackMessage Pack a message for one or more recipients. +func (bp *Packager) PackMessage(messageEnvelope *transport.Envelope) ([]byte, error) { + if messageEnvelope == nil { + return nil, errors.New("envelope argument is nil") + } + + var recipients [][]byte + + for _, verKey := range messageEnvelope.ToVerKeys { + // TODO It is possible to have different key schemes in an interop situation + // there is no guarantee that each recipient is using the same key types + // for now this package uses Ed25519 signing keys. Other key schemes should have their own + // envelope implementations. + // decode base58 ver key + verKeyBytes := base58.Decode(verKey) + // create 32 byte key + recipients = append(recipients, verKeyBytes) + } + // pack message + bytes, err := bp.packer.Pack(messageEnvelope.Message, base58.Decode(messageEnvelope.FromVerKey), recipients) + if err != nil { + return nil, fmt.Errorf("pack: %w", err) + } + + return bytes, nil +} + +type envelopeStub struct { + Protected string `json:"protected,omitempty"` +} + +type headerStub struct { + Type string `json:"typ,omitempty"` +} + +func getEncodingType(encMessage []byte) (string, error) { + env := &envelopeStub{} + + err := json.Unmarshal(encMessage, env) + if err != nil { + return "", fmt.Errorf("parse envelope: %w", err) + } + + var protBytes []byte + + protBytes1, err1 := base64.URLEncoding.DecodeString(env.Protected) + protBytes2, err2 := base64.RawURLEncoding.DecodeString(env.Protected) + + switch { + case err1 == nil: + protBytes = protBytes1 + case err2 == nil: + protBytes = protBytes2 + default: + return "", fmt.Errorf("decode header: %w", err1) + } + + prot := &headerStub{} + + err = json.Unmarshal(protBytes, prot) + if err != nil { + return "", fmt.Errorf("parse header: %w", err) + } + + return prot.Type, nil +} + +// UnpackMessage Unpack a message. +func (bp *Packager) UnpackMessage(encMessage []byte) (*transport.Envelope, error) { + encType, err := getEncodingType(encMessage) + if err != nil { + return nil, fmt.Errorf("getEncodingType: %w", err) + } + + p, ok := bp.inboundPackers[encType] + if !ok { + return nil, fmt.Errorf("message Type not recognized") + } + + bytes, err := p.Unpack(encMessage) + if err != nil { + return nil, fmt.Errorf("unpack: %w", err) + } + // TODO extract fromVerKey and toVerKey from packer.Unpack() call above and set them here + return &transport.Envelope{Message: bytes}, nil +} diff --git a/pkg/didcomm/envelope/packer.go b/pkg/didcomm/packer/api.go similarity index 82% rename from pkg/didcomm/envelope/packer.go rename to pkg/didcomm/packer/api.go index b7401d6218..963623327e 100644 --- a/pkg/didcomm/envelope/packer.go +++ b/pkg/didcomm/packer/api.go @@ -4,21 +4,20 @@ Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package envelope +package packer import "github.com/hyperledger/aries-framework-go/pkg/kms" -// KMSProvider interface for Packer ctx -type KMSProvider interface { +// Provider interface for Packer ctx +type Provider interface { KMS() kms.KeyManager } // Creator method to create new Packer service -type Creator func(prov KMSProvider) (Packer, error) +type Creator func(prov Provider) (Packer, error) // Packer is an Aries envelope packer/unpacker to support // secure DIDComm exchange of envelopes between Aries agents -// TODO create a higher-level packer that switches implementations based on the algorithm - Issue #273 type Packer interface { // Pack a payload in an Aries compliant format using the sender keypair // and a list of recipients public keys @@ -35,4 +34,7 @@ type Packer interface { // error if decryption failed // TODO add key type of recipients keys to be validated by the implementation - Issue #272 Unpack(envelope []byte) ([]byte, error) + + // Encoding returns the type of the encoding, as found in the header `Typ` field + EncodingType() string } diff --git a/pkg/didcomm/packer/jwe/authcrypt/authcrypt.go b/pkg/didcomm/packer/jwe/authcrypt/authcrypt.go index db92941591..307784ef7e 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/authcrypt.go +++ b/pkg/didcomm/packer/jwe/authcrypt/authcrypt.go @@ -12,7 +12,7 @@ import ( chacha "golang.org/x/crypto/chacha20poly1305" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" "github.com/hyperledger/aries-framework-go/pkg/kms" ) @@ -22,11 +22,14 @@ import ( // ContentEncryption represents a content encryption algorithm. type ContentEncryption string -// C20P Chacha20Poly1305 algorithm -const C20P = ContentEncryption("C20P") // Chacha20 encryption + Poly1305 authenticator cipher (96 bits nonce) - -// XC20P XChacha20Poly1305 algorithm -const XC20P = ContentEncryption("XC20P") // XChacha20 encryption + Poly1305 authenticator cipher (192 bits nonce) +const ( + // C20P Chacha20Poly1305 algorithm + C20P = ContentEncryption("C20P") // Chacha20 encryption + Poly1305 authenticator cipher (96 bits nonce) + // XC20P XChacha20Poly1305 algorithm + XC20P = ContentEncryption("XC20P") // XChacha20 encryption + Poly1305 authenticator cipher (192 bits nonce) + // encodingType is the `typ` string identifier in a message that identifies the format as being JWE + encodingType string = "prs.hyperledger.aries-auth-message" +) // randReader is a cryptographically secure random number generator. // TODO: document usage for tests or find another mechanism. @@ -36,7 +39,9 @@ var randReader = rand.Reader // errUnsupportedAlg is used when a bad encryption algorithm is used var errUnsupportedAlg = errors.New("algorithm not supported") -// Packer represents an Authcrypt Encrypter (Decrypter) that outputs/reads JWE envelopes +// TODO #475 pull alg and nonceSize into separate crypter, add crypter reference to Packer + +// Packer represents an Authcrypt Packer/Unpacker that outputs/reads JWE envelopes type Packer struct { alg ContentEncryption nonceSize int @@ -93,12 +98,12 @@ type jwk struct { X string `json:"x,omitempty"` } -// New will create an encrypter instance to 'AuthCrypt' payloads for the given sender and recipients arguments +// New will create an Packer instance to 'AuthCrypt' payloads for the given sender and recipients arguments // and the encryption alg argument. Possible algorithms supported are: // C20P (chacha20-poly1305 ietf) // XC20P (xchacha20-poly1305 ietf) -// The returned crypter contains all the information required to encrypt payloads. -func New(ctx envelope.KMSProvider, alg ContentEncryption) (*Packer, error) { +// The returned Packer contains all the information required to pack and unpack payloads. +func New(ctx packer.Provider, alg ContentEncryption) (*Packer, error) { k := ctx.KMS() var nonceSize int @@ -118,3 +123,8 @@ func New(ctx envelope.KMSProvider, alg ContentEncryption) (*Packer, error) { kms: k, }, nil } + +// EncodingType returns the type of the encoding, as in the `Typ` field of the envelope header +func (p *Packer) EncodingType() string { + return encodingType +} diff --git a/pkg/didcomm/packer/jwe/authcrypt/authcrypt_test.go b/pkg/didcomm/packer/jwe/authcrypt/authcrypt_test.go index 55fffb62ca..6a3e83e5a9 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/authcrypt_test.go +++ b/pkg/didcomm/packer/jwe/authcrypt/authcrypt_test.go @@ -21,6 +21,41 @@ import ( mockkms "github.com/hyperledger/aries-framework-go/pkg/internal/mock/kms" ) +func TestEncodingType(t *testing.T) { + // create temporary signing keys for tests + sigPubKey, sigPrivKey, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + // convert signing keys to encryption keys + encPubKey, err := cryptoutil.PublicEd25519toCurve25519(sigPubKey) + require.NoError(t, err) + + encPrivKey, err := cryptoutil.SecretEd25519toCurve25519(sigPrivKey) + require.NoError(t, err) + + require.NoError(t, err) + + kp := &cryptoutil.MessagingKeys{ + SigKeyPair: &cryptoutil.SigKeyPair{ + KeyPair: cryptoutil.KeyPair{Pub: sigPubKey, Priv: sigPrivKey}, + Alg: cryptoutil.EdDSA, + }, + EncKeyPair: &cryptoutil.EncKeyPair{ + KeyPair: cryptoutil.KeyPair{Pub: encPubKey, Priv: encPrivKey}, + Alg: cryptoutil.Curve25519, + }, + } + + kmsProvider, err := mockkms.NewMockProvider(kp) + require.NoError(t, err) + + packer, e := New(kmsProvider, XC20P) + require.NoError(t, e) + require.NotEmpty(t, packer) + + require.Equal(t, encodingType, packer.EncodingType()) +} + func TestEncrypt(t *testing.T) { // create temporary signing keys for tests sigPubKey, sigPrivKey, err := ed25519.GenerateKey(rand.Reader) @@ -149,24 +184,24 @@ func TestEncrypt(t *testing.T) { Priv: nil, } - t.Run("Error test case: Create a new AuthCrypter with bad encryption algorithm", func(t *testing.T) { + t.Run("Error test case: Create a new AuthCrypt PackerValue with bad encryption algorithm", func(t *testing.T) { _, e := New(senderKMSProvider, "BAD") require.Error(t, e) require.EqualError(t, e, errUnsupportedAlg.Error()) }) - t.Run("Error test case: Create a new AuthCrypter and use an empty keys for encryption", func(t *testing.T) { + t.Run("Error test case: Create a new AuthCrypt PackerValue and use an empty keys for encryption", func(t *testing.T) { packer, e := New(senderKMSProvider, XC20P) require.NoError(t, e) require.NotEmpty(t, packer) badKey.Pub = []byte{} enc, e := packer.Pack([]byte("lorem ipsum dolor sit amet"), badKey.Pub, [][]byte{rec1.SigKeyPair.Pub, rec2.SigKeyPair.Pub, rec3.SigKeyPair.Pub}) - require.EqualError(t, e, "failed to encrypt message: empty sender key") + require.EqualError(t, e, "failed to pack message: empty sender key") require.Empty(t, enc) }) - t.Run("Error test case: Create a new AuthCrypter and use a bad key for encryption", func(t *testing.T) { + t.Run("Error test case: Create a new AuthCrypt PackerValue and use a bad key for encryption", func(t *testing.T) { packer, e := New(senderKMSProvider, XC20P) require.NoError(t, e) require.NotEmpty(t, packer) @@ -184,17 +219,17 @@ func TestEncrypt(t *testing.T) { // test bad recipient 1 public key size enc, e = packer.Pack([]byte("lorem ipsum dolor sit amet"), sender.SigKeyPair.Pub, [][]byte{[]byte("badkeysize"), rec2.SigKeyPair.Pub, rec3.SigKeyPair.Pub}) - require.EqualError(t, e, "failed to encrypt message: invalid key - for recipient 1") + require.EqualError(t, e, "failed to pack message: invalid key - for recipient 1") require.Empty(t, enc) // test bad recipient 2 public key size enc, e = packer.Pack([]byte("lorem ipsum dolor sit amet"), sender.SigKeyPair.Pub, [][]byte{rec1.SigKeyPair.Pub, []byte("badkeysize"), rec3.SigKeyPair.Pub}) - require.EqualError(t, e, "failed to encrypt message: invalid key - for recipient 2") + require.EqualError(t, e, "failed to pack message: invalid key - for recipient 2") require.Empty(t, enc) // test bad recipient 3 publick key size enc, e = packer.Pack([]byte("lorem ipsum dolor sit amet"), sender.SigKeyPair.Pub, [][]byte{rec1.SigKeyPair.Pub, rec2.SigKeyPair.Pub, []byte("badkeysize")}) - require.EqualError(t, e, "failed to encrypt message: invalid key - for recipient 3") + require.EqualError(t, e, "failed to pack message: invalid key - for recipient 3") require.Empty(t, enc) // test invalid recipient 1 key @@ -202,20 +237,20 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) enc, e = packer.Pack([]byte("lorem ipsum dolor sit amet"), sender.SigKeyPair.Pub, [][]byte{k, rec2.SigKeyPair.Pub, rec3.SigKeyPair.Pub}) - require.EqualError(t, e, "failed to encrypt message: error converting public key") + require.EqualError(t, e, "failed to pack message: error converting public key") require.Empty(t, enc) }) - t.Run("Error test case: Create a new AuthCrypter and use an empty recipient keys list for encryption", func(t *testing.T) { //nolint:lll + t.Run("Error test case: Create a new AuthCrypt PackerValue and use an empty recipient keys list for encryption", func(t *testing.T) { //nolint:lll packer, e := New(senderKMSProvider, "XC20P") require.NoError(t, e) require.NotEmpty(t, packer) enc, e := packer.Pack([]byte("lorem ipsum dolor sit amet"), sender.SigKeyPair.Pub, [][]byte{}) - require.EqualError(t, e, "failed to encrypt message: empty recipients") + require.EqualError(t, e, "failed to pack message: empty recipients") require.Empty(t, enc) }) - t.Run("Success test case: Create a valid AuthCrypter for ChachaPoly1305 encryption (alg: C20P)", func(t *testing.T) { + t.Run("Success test case: Create a valid PackerValue for ChachaPoly1305 encryption (alg: C20P)", func(t *testing.T) { packer, e := New(allKMSProvider, C20P) require.NoError(t, e) require.NotEmpty(t, packer) @@ -229,7 +264,7 @@ func TestEncrypt(t *testing.T) { t.Logf("Encryption with C20P: %s", m) }) - t.Run("Success test case: Create a valid AuthCrypter for XChachaPoly1305 encryption (alg: XC20P)", func(t *testing.T) { + t.Run("Success test case: Create a valid PackerValue for XChachaPoly1305 encryption (alg: XC20P)", func(t *testing.T) { packer, e := New(allKMSProvider, XC20P) require.NoError(t, e) require.NotEmpty(t, packer) @@ -242,7 +277,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) t.Logf("Encryption with XC20P: %s", m) - t.Run("Error test Case: use a valid AuthCrypter but scramble the nonce size", func(t *testing.T) { + t.Run("Error test Case: use a valid AuthCrypt PackerValue but scramble the nonce size", func(t *testing.T) { packer.nonceSize = 0 _, err = packer.Pack([]byte("lorem ipsum dolor sit amet"), sender.SigKeyPair.Pub, [][]byte{rec1.SigKeyPair.Pub, rec2.SigKeyPair.Pub, rec3.SigKeyPair.Pub}) @@ -250,7 +285,7 @@ func TestEncrypt(t *testing.T) { }) }) - t.Run("Success test case: Decrypting a message (with the same crypter)", func(t *testing.T) { + t.Run("Success test case: Decrypting a message (with the same packer)", func(t *testing.T) { // not a real life scenario, the kms is using both sender and rec1 key pairs // allKMSProvider is used here for testing purposes only packer, e := New(allKMSProvider, XC20P) @@ -274,7 +309,7 @@ func TestEncrypt(t *testing.T) { require.EqualValues(t, dec, pld) }) - t.Run("Success test case: Decrypting a message with two Packer instances to simulate two agents", func(t *testing.T) { //nolint:lll + t.Run("Success test case: Decrypting a message with two PackerValue instances to simulate two agents", func(t *testing.T) { //nolint:lll // encrypt with sender packer, e := New(allKMSProvider, XC20P) require.NoError(t, e) @@ -360,7 +395,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad nonce format dec, e := packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt message: illegal base64 data at input byte 12") + require.EqualError(t, e, "unpack: illegal base64 data at input byte 12") require.Empty(t, dec) jwe.CipherText = validJwe.CipherText @@ -370,7 +405,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad nonce format dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt message: illegal base64 data at input byte 5") + require.EqualError(t, e, "unpack: illegal base64 data at input byte 5") require.Empty(t, dec) jwe.IV = validJwe.IV @@ -380,7 +415,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag format dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt message: illegal base64 data at input byte 6") + require.EqualError(t, e, "unpack: illegal base64 data at input byte 6") require.Empty(t, dec) jwe.Tag = validJwe.Tag @@ -390,7 +425,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt sender key: bad SPK format") + require.EqualError(t, e, "unpack: sender key: bad SPK format") require.Empty(t, dec) jwe.Recipients[0].Header.SPK = validJwe.Recipients[0].Header.SPK @@ -400,7 +435,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt shared key: illegal base64 data at input byte 6") + require.EqualError(t, e, "unpack: decrypt shared key: illegal base64 data at input byte 6") require.Empty(t, dec) jwe.Recipients[0].Header.Tag = validJwe.Recipients[0].Header.Tag @@ -410,7 +445,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt shared key: illegal base64 data at input byte 5") + require.EqualError(t, e, "unpack: decrypt shared key: illegal base64 data at input byte 5") require.Empty(t, dec) jwe.Recipients[0].Header.IV = validJwe.Recipients[0].Header.IV @@ -420,7 +455,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt shared key: bad nonce size") + require.EqualError(t, e, "unpack: decrypt shared key: bad nonce size") require.Empty(t, dec) jwe.Recipients[0].Header.IV = validJwe.Recipients[0].Header.IV @@ -430,7 +465,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt shared key: illegal base64 data at input byte 6") + require.EqualError(t, e, "unpack: decrypt shared key: illegal base64 data at input byte 6") require.Empty(t, dec) jwe.Recipients[0].Header.APU = validJwe.Recipients[0].Header.APU @@ -440,7 +475,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, fmt.Sprintf("failed to decrypt message: %s", cryptoutil.ErrKeyNotFound.Error())) + require.EqualError(t, e, fmt.Sprintf("unpack: %s", cryptoutil.ErrKeyNotFound.Error())) require.Empty(t, dec) jwe.Recipients[0].Header.KID = validJwe.Recipients[0].Header.KID @@ -450,7 +485,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt shared key: illegal base64 data at input byte 15") + require.EqualError(t, e, "unpack: decrypt shared key: illegal base64 data at input byte 15") require.Empty(t, dec) jwe.Recipients[0].EncryptedKey = validJwe.Recipients[0].EncryptedKey @@ -460,7 +495,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt shared key: chacha20poly1305: message authentication failed") + require.EqualError(t, e, "unpack: decrypt shared key: chacha20poly1305: message authentication failed") require.Empty(t, dec) jwe.Recipients[0].EncryptedKey = validJwe.Recipients[0].EncryptedKey @@ -481,7 +516,7 @@ func TestEncrypt(t *testing.T) { require.NoError(t, e) // decrypt with bad tag dec, e = packer.Unpack(enc) - require.EqualError(t, e, "failed to decrypt shared key: chacha20poly1305: message authentication failed") + require.EqualError(t, e, "unpack: decrypt shared key: chacha20poly1305: message authentication failed") require.Empty(t, dec) jwe.Recipients[0].Header.IV = validJwe.Recipients[0].Header.IV }) diff --git a/pkg/didcomm/packer/jwe/authcrypt/common.go b/pkg/didcomm/packer/jwe/authcrypt/common.go index 4863d83424..ee3054fd5b 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/common.go +++ b/pkg/didcomm/packer/jwe/authcrypt/common.go @@ -13,6 +13,8 @@ import ( chacha "golang.org/x/crypto/chacha20poly1305" ) +// TODO #475 pull cipher into separate crypter + // createCipher will create and return a new Chacha20Poly1305 cipher for the given nonceSize and symmetric key func createCipher(nonceSize int, symKey []byte) (cipher.AEAD, error) { switch nonceSize { diff --git a/pkg/didcomm/packer/jwe/authcrypt/decrypt_jwk.go b/pkg/didcomm/packer/jwe/authcrypt/decrypt_jwk.go index 7d6399c03f..f1931f8758 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/decrypt_jwk.go +++ b/pkg/didcomm/packer/jwe/authcrypt/decrypt_jwk.go @@ -18,7 +18,7 @@ import ( // decryptSPK will decrypt a recipient's encrypted SPK (in the case of this package, it is represented as // the sender's public key as a jwk). It uses the recipent's private/public keypair for decryption // the returned decrypted value is the sender's public key -func (c *Packer) decryptSPK(recipientPubKey *[chacha.KeySize]byte, spk string) ([]byte, error) { +func (p *Packer) decryptSPK(recipientPubKey *[chacha.KeySize]byte, spk string) ([]byte, error) { jwe := strings.Split(spk, ".") if len(jwe) != 5 { return nil, fmt.Errorf("bad SPK format") @@ -60,31 +60,31 @@ func (c *Packer) decryptSPK(recipientPubKey *[chacha.KeySize]byte, spk string) ( return nil, err } - sharedKey, err := c.decryptJWKSharedKey(cipherKEK, headersJSON, recipientPubKey[:]) + sharedKey, err := p.decryptJWKSharedKey(cipherKEK, headersJSON, recipientPubKey[:]) if err != nil { return nil, err } // now that we have sharedKey, let's decrypt the sender JWK (cipherJWK) - return c.decryptSenderJWK(nonce, sharedKey, []byte(headersEncoded), cipherJWK, tag) + return p.decryptSenderJWK(nonce, sharedKey, []byte(headersEncoded), cipherJWK, tag) } // decryptJWKSharedKey will decrypt the cek using recPrivKey for decryption and rebuild the cipher text, nonce // kek from headersJSON, the result is the sharedKey to be used for decrypting the sender JWK -func (c *Packer) decryptJWKSharedKey(cipherKEK []byte, headersJSON *recipientSPKJWEHeaders, recPubKey []byte) ([]byte, error) { //nolint:lll +func (p *Packer) decryptJWKSharedKey(cipherKEK []byte, headersJSON *recipientSPKJWEHeaders, recPubKey []byte) ([]byte, error) { //nolint:lll epk, err := base64.RawURLEncoding.DecodeString(headersJSON.EPK.X) if err != nil { return nil, err } - kek, err := c.kms.DeriveKEK([]byte(c.alg+"KW"), nil, recPubKey, epk) + kek, err := p.kms.DeriveKEK([]byte(p.alg+"KW"), nil, recPubKey, epk) if err != nil { return nil, err } // create a cipher for the given nonceSize and generated kek above // to decrypt the symmetric shared key (by decrypting cipherKEK) - crypter, err := createCipher(c.nonceSize, kek) + cipher, err := createCipher(p.nonceSize, kek) if err != nil { return nil, err } @@ -103,7 +103,7 @@ func (c *Packer) decryptJWKSharedKey(cipherKEK []byte, headersJSON *recipientSPK // assemble kek for decryption cipherKEK = append(cipherKEK, kekTag...) - symKey, err := crypter.Open(nil, kekNonce, cipherKEK, nil) + symKey, err := cipher.Open(nil, kekNonce, cipherKEK, nil) if err != nil { return nil, err } @@ -113,9 +113,9 @@ func (c *Packer) decryptJWKSharedKey(cipherKEK []byte, headersJSON *recipientSPK // decryptSenderJWK will decrypt and extract the sender key from cipherJwk, tag and nonce using symKey for decryption // and headersEncoded as AAD for the aead (chacha20poly1305) cipher -func (c *Packer) decryptSenderJWK(nonce, symKey, headersEncoded, cipherJWK, tag []byte) ([]byte, error) { +func (p *Packer) decryptSenderJWK(nonce, symKey, headersEncoded, cipherJWK, tag []byte) ([]byte, error) { // now that we have symKey, let's decrypt the sender JWK (cipherJWK) - jwkCrypter, err := createCipher(c.nonceSize, symKey) + jwkCipher, err := createCipher(p.nonceSize, symKey) if err != nil { return nil, err } @@ -123,7 +123,7 @@ func (c *Packer) decryptSenderJWK(nonce, symKey, headersEncoded, cipherJWK, tag // assemble cipher JWK for decryption cipherTxt := append(cipherJWK, tag...) - senderJWKJSONEncoded, err := jwkCrypter.Open(nil, nonce, cipherTxt, headersEncoded) + senderJWKJSONEncoded, err := jwkCipher.Open(nil, nonce, cipherTxt, headersEncoded) if err != nil { return nil, err } diff --git a/pkg/didcomm/packer/jwe/authcrypt/decrypt_jwk_test.go b/pkg/didcomm/packer/jwe/authcrypt/decrypt_jwk_test.go index df8b6c530a..531a2f5f40 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/decrypt_jwk_test.go +++ b/pkg/didcomm/packer/jwe/authcrypt/decrypt_jwk_test.go @@ -21,26 +21,26 @@ func TestNilDecryptSenderJwk(t *testing.T) { mockKMSProvider, err := mockkms.NewMockProvider() require.NoError(t, err) - crypter, err := New(mockKMSProvider, XC20P) + packer, err := New(mockKMSProvider, XC20P) require.NoError(t, err) - spk, err := crypter.decryptSPK(nil, "!-.t.t.t.t") + spk, err := packer.decryptSPK(nil, "!-.t.t.t.t") require.Error(t, err) require.Empty(t, spk) - spk, err = crypter.decryptSPK(nil, "eyJ0eXAiOiJqb3NlIiwiY3R5IjoiandrK2pzb24iLCJhbGciOiJFQ0RILUVTK1hDMjBQS1ciLCJlbmMiOiJYQzIwUCIsIml2IjoiNWhwNEVrWGtqSHR0SFlmY1IySXQ4d2dnZndjanNQaWwiLCJ0YWciOiJuMjg1OGplTXhZVE0tYzRZc2J0ZlBRIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJ3OW1EZ1FENnJVdWkyLVMyRjV6SVNqZXBua1FOZWEwMGtvTnRBOUhEeUIwIn19.!-.t.t.t") + spk, err = packer.decryptSPK(nil, "eyJ0eXAiOiJqb3NlIiwiY3R5IjoiandrK2pzb24iLCJhbGciOiJFQ0RILUVTK1hDMjBQS1ciLCJlbmMiOiJYQzIwUCIsIml2IjoiNWhwNEVrWGtqSHR0SFlmY1IySXQ4d2dnZndjanNQaWwiLCJ0YWciOiJuMjg1OGplTXhZVE0tYzRZc2J0ZlBRIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJ3OW1EZ1FENnJVdWkyLVMyRjV6SVNqZXBua1FOZWEwMGtvTnRBOUhEeUIwIn19.!-.t.t.t") require.Error(t, err) require.Empty(t, spk) - spk, err = crypter.decryptSPK(nil, "eyJ0eXAiOiJqb3NlIiwiY3R5IjoiandrK2pzb24iLCJhbGciOiJFQ0RILUVTK1hDMjBQS1ciLCJlbmMiOiJYQzIwUCIsIml2IjoiNWhwNEVrWGtqSHR0SFlmY1IySXQ4d2dnZndjanNQaWwiLCJ0YWciOiJuMjg1OGplTXhZVE0tYzRZc2J0ZlBRIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJ3OW1EZ1FENnJVdWkyLVMyRjV6SVNqZXBua1FOZWEwMGtvTnRBOUhEeUIwIn19.U-AXyneFJ5x4QayrZ3GcuDCg1yHYHC9Kn1s8gtd7O4c.!-.t.t") + spk, err = packer.decryptSPK(nil, "eyJ0eXAiOiJqb3NlIiwiY3R5IjoiandrK2pzb24iLCJhbGciOiJFQ0RILUVTK1hDMjBQS1ciLCJlbmMiOiJYQzIwUCIsIml2IjoiNWhwNEVrWGtqSHR0SFlmY1IySXQ4d2dnZndjanNQaWwiLCJ0YWciOiJuMjg1OGplTXhZVE0tYzRZc2J0ZlBRIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJ3OW1EZ1FENnJVdWkyLVMyRjV6SVNqZXBua1FOZWEwMGtvTnRBOUhEeUIwIn19.U-AXyneFJ5x4QayrZ3GcuDCg1yHYHC9Kn1s8gtd7O4c.!-.t.t") require.Error(t, err) require.Empty(t, spk) - spk, err = crypter.decryptSPK(nil, "eyJ0eXAiOiJqb3NlIiwiY3R5IjoiandrK2pzb24iLCJhbGciOiJFQ0RILUVTK1hDMjBQS1ciLCJlbmMiOiJYQzIwUCIsIml2IjoiNWhwNEVrWGtqSHR0SFlmY1IySXQ4d2dnZndjanNQaWwiLCJ0YWciOiJuMjg1OGplTXhZVE0tYzRZc2J0ZlBRIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJ3OW1EZ1FENnJVdWkyLVMyRjV6SVNqZXBua1FOZWEwMGtvTnRBOUhEeUIwIn19.U-AXyneFJ5x4QayrZ3GcuDCg1yHYHC9Kn1s8gtd7O4c.aigDJrko05dw-9Hk4LQbfOCCG9Dzskw6.!-.t") + spk, err = packer.decryptSPK(nil, "eyJ0eXAiOiJqb3NlIiwiY3R5IjoiandrK2pzb24iLCJhbGciOiJFQ0RILUVTK1hDMjBQS1ciLCJlbmMiOiJYQzIwUCIsIml2IjoiNWhwNEVrWGtqSHR0SFlmY1IySXQ4d2dnZndjanNQaWwiLCJ0YWciOiJuMjg1OGplTXhZVE0tYzRZc2J0ZlBRIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJ3OW1EZ1FENnJVdWkyLVMyRjV6SVNqZXBua1FOZWEwMGtvTnRBOUhEeUIwIn19.U-AXyneFJ5x4QayrZ3GcuDCg1yHYHC9Kn1s8gtd7O4c.aigDJrko05dw-9Hk4LQbfOCCG9Dzskw6.!-.t") require.Error(t, err) require.Empty(t, spk) - spk, err = crypter.decryptSPK(nil, "eyJ0eXAiOiJqb3NlIiwiY3R5IjoiandrK2pzb24iLCJhbGciOiJFQ0RILUVTK1hDMjBQS1ciLCJlbmMiOiJYQzIwUCIsIml2IjoiNWhwNEVrWGtqSHR0SFlmY1IySXQ4d2dnZndjanNQaWwiLCJ0YWciOiJuMjg1OGplTXhZVE0tYzRZc2J0ZlBRIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJ3OW1EZ1FENnJVdWkyLVMyRjV6SVNqZXBua1FOZWEwMGtvTnRBOUhEeUIwIn19.U-AXyneFJ5x4QayrZ3GcuDCg1yHYHC9Kn1s8gtd7O4c.aigDJrko05dw-9Hk4LQbfOCCG9Dzskw6.tY10QY9fXvqV_vfhzBKkqw.!-") + spk, err = packer.decryptSPK(nil, "eyJ0eXAiOiJqb3NlIiwiY3R5IjoiandrK2pzb24iLCJhbGciOiJFQ0RILUVTK1hDMjBQS1ciLCJlbmMiOiJYQzIwUCIsIml2IjoiNWhwNEVrWGtqSHR0SFlmY1IySXQ4d2dnZndjanNQaWwiLCJ0YWciOiJuMjg1OGplTXhZVE0tYzRZc2J0ZlBRIiwiZXBrIjp7Imt0eSI6Ik9LUCIsImNydiI6IlgyNTUxOSIsIngiOiJ3OW1EZ1FENnJVdWkyLVMyRjV6SVNqZXBua1FOZWEwMGtvTnRBOUhEeUIwIn19.U-AXyneFJ5x4QayrZ3GcuDCg1yHYHC9Kn1s8gtd7O4c.aigDJrko05dw-9Hk4LQbfOCCG9Dzskw6.tY10QY9fXvqV_vfhzBKkqw.!-") require.Error(t, err) require.Empty(t, spk) @@ -48,25 +48,25 @@ func TestNilDecryptSenderJwk(t *testing.T) { X: "test", }} someKey := new([chacha.KeySize]byte) - spk, err = crypter.decryptJWKSharedKey([]byte(""), headersJSON, someKey[:]) + spk, err = packer.decryptJWKSharedKey([]byte(""), headersJSON, someKey[:]) require.Error(t, err) require.Empty(t, spk) headersJSON.EPK.X = "!-" - spk, err = crypter.decryptJWKSharedKey([]byte(""), headersJSON, someKey[:]) + spk, err = packer.decryptJWKSharedKey([]byte(""), headersJSON, someKey[:]) require.Error(t, err) require.Empty(t, spk) headersJSON.EPK.X = "test" headersJSON.Tag = "!-" - spk, err = crypter.decryptJWKSharedKey([]byte(""), headersJSON, someKey[:]) + spk, err = packer.decryptJWKSharedKey([]byte(""), headersJSON, someKey[:]) require.Error(t, err) require.Empty(t, spk) headersJSON.Tag = "test" headersJSON.IV = "!-" - spk, err = crypter.decryptJWKSharedKey([]byte(""), headersJSON, someKey[:]) + spk, err = packer.decryptJWKSharedKey([]byte(""), headersJSON, someKey[:]) require.Error(t, err) require.Empty(t, spk) @@ -80,11 +80,11 @@ func TestNilDecryptSenderJwk(t *testing.T) { nonce, err := base64.RawURLEncoding.DecodeString(headersJSON.IV) require.NoError(t, err) - spk, err = crypter.decryptSenderJWK(nonce, nil, nil, nil, nil) + spk, err = packer.decryptSenderJWK(nonce, nil, nil, nil, nil) require.Error(t, err) require.Empty(t, spk) - spk, err = crypter.decryptSenderJWK(nonce, someKey[:], nil, nil, nil) + spk, err = packer.decryptSenderJWK(nonce, someKey[:], nil, nil, nil) require.Error(t, err) require.Empty(t, spk) } diff --git a/pkg/didcomm/packer/jwe/authcrypt/encrypt_jwk.go b/pkg/didcomm/packer/jwe/authcrypt/encrypt_jwk.go index 33ba24b331..6b3b9bfae5 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/encrypt_jwk.go +++ b/pkg/didcomm/packer/jwe/authcrypt/encrypt_jwk.go @@ -19,7 +19,7 @@ import ( // generateSPK will encrypt a msg (in the case of this package, it will be // the sender's public key) using the recipient's pubKey, the output will be // a compact JWE wrapping a JWK containing the (encrypted) sender's public key -func (c *Packer) generateSPK(recipientPubKey, senderPubKey *[chacha.KeySize]byte) (string, error) { +func (p *Packer) generateSPK(recipientPubKey, senderPubKey *[chacha.KeySize]byte) (string, error) { if recipientPubKey == nil { return "", cryptoutil.ErrInvalidKey } @@ -31,7 +31,7 @@ func (c *Packer) generateSPK(recipientPubKey, senderPubKey *[chacha.KeySize]byte } // derive an ephemeral key for the recipient and an ephemeral secret key (esk) - kek, err := cryptoutil.Derive25519KEK([]byte(c.alg+"KW"), nil, esk, recipientPubKey) + kek, err := cryptoutil.Derive25519KEK([]byte(p.alg+"KW"), nil, esk, recipientPubKey) if err != nil { return "", err } @@ -44,12 +44,12 @@ func (c *Packer) generateSPK(recipientPubKey, senderPubKey *[chacha.KeySize]byte return "", err } - kCipherEncoded, kTagEncoded, kNonceEncoded, err := c.encryptCEK(kek, cek[:]) + kCipherEncoded, kTagEncoded, kNonceEncoded, err := p.encryptCEK(kek, cek[:]) if err != nil { return "", err } - headersEncoded, err := c.buildJWKHeaders(epk, kNonceEncoded, kTagEncoded) + headersEncoded, err := p.buildJWKHeaders(epk, kNonceEncoded, kTagEncoded) if err != nil { return "", err } @@ -66,15 +66,15 @@ func (c *Packer) generateSPK(recipientPubKey, senderPubKey *[chacha.KeySize]byte return "", err } - return c.encryptSenderJWK(kCipherEncoded, headersEncoded, senderJWKJSON, cek[:]) + return p.encryptSenderJWK(kCipherEncoded, headersEncoded, senderJWKJSON, cek[:]) } -func (c *Packer) buildJWKHeaders(epk *[32]byte, kNonceEncoded, kTagEncoded string) (string, error) { +func (p *Packer) buildJWKHeaders(epk *[32]byte, kNonceEncoded, kTagEncoded string) (string, error) { headers := recipientSPKJWEHeaders{ Typ: "jose", CTY: "jwk+json", - Alg: "ECDH-ES+" + string(c.alg) + "KW", - Enc: string(c.alg), + Alg: "ECDH-ES+" + string(p.alg) + "KW", + Enc: string(p.alg), EPK: jwk{ Kty: "OKP", // OPK not 0PK Crv: "X25519", @@ -92,9 +92,9 @@ func (c *Packer) buildJWKHeaders(epk *[32]byte, kNonceEncoded, kTagEncoded strin return base64.RawURLEncoding.EncodeToString(headersJSON), nil } -func (c *Packer) encryptSenderJWK(encKey, headers string, senderJWKJSON, cek []byte) (string, error) { +func (p *Packer) encryptSenderJWK(encKey, headers string, senderJWKJSON, cek []byte) (string, error) { // create a new nonce - nonce := make([]byte, c.nonceSize) + nonce := make([]byte, p.nonceSize) _, err := randReader.Read(nonce) if err != nil { @@ -102,7 +102,7 @@ func (c *Packer) encryptSenderJWK(encKey, headers string, senderJWKJSON, cek []b } // create a cipher for the given nonceSize and cek - cipher, err := createCipher(c.nonceSize, cek) + cipher, err := createCipher(p.nonceSize, cek) if err != nil { return "", err } diff --git a/pkg/didcomm/packer/jwe/authcrypt/encrypt_jwk_test.go b/pkg/didcomm/packer/jwe/authcrypt/encrypt_jwk_test.go index 8d7627e431..8fefcd5361 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/encrypt_jwk_test.go +++ b/pkg/didcomm/packer/jwe/authcrypt/encrypt_jwk_test.go @@ -21,20 +21,20 @@ func TestNilEncryptSenderJwk(t *testing.T) { mockKMSProvider, err := mockKMS.NewMockProvider() require.NoError(t, err) - crypter, err := New(mockKMSProvider, XC20P) + packer, err := New(mockKMSProvider, XC20P) require.NoError(t, err) - spk, err := crypter.generateSPK(nil, nil) + spk, err := packer.generateSPK(nil, nil) require.Error(t, err) require.Empty(t, spk) - s, l, m, err := crypter.encryptCEK(nil, nil) + s, l, m, err := packer.encryptCEK(nil, nil) require.Error(t, err) require.Empty(t, s) require.Empty(t, l) require.Empty(t, m) - s, err = crypter.encryptSenderJWK("", "", nil, nil) + s, err = packer.encryptSenderJWK("", "", nil, nil) require.Error(t, err) require.Empty(t, s) @@ -43,30 +43,30 @@ func TestNilEncryptSenderJwk(t *testing.T) { defer resetRandReader() - s, err = crypter.encryptSenderJWK("", "", nil, nil) + s, err = packer.encryptSenderJWK("", "", nil, nil) require.Error(t, err) require.Empty(t, s) someKey := new([chacha.KeySize]byte) - spk, err = crypter.generateSPK(someKey, nil) + spk, err = packer.generateSPK(someKey, nil) require.Error(t, err) require.Empty(t, spk) - spk, err = crypter.generateSPK(someKey, someKey) + spk, err = packer.generateSPK(someKey, someKey) require.Error(t, err) require.Empty(t, spk) - r, err := crypter.encodeRecipient(someKey, someKey, someKey) + r, err := packer.encodeRecipient(someKey, someKey, someKey) require.Error(t, err) require.Empty(t, r) - s, l, m, err = crypter.encryptCEK(someKey[:], someKey[:]) + s, l, m, err = packer.encryptCEK(someKey[:], someKey[:]) require.Error(t, err) require.Empty(t, s) require.Empty(t, l) require.Empty(t, m) - pld, err := crypter.Pack([]byte(""), someKey[:], [][]byte{someKey[:]}) + pld, err := packer.Pack([]byte(""), someKey[:], [][]byte{someKey[:]}) require.Error(t, err) require.Empty(t, pld) } diff --git a/pkg/didcomm/packer/jwe/authcrypt/pack.go b/pkg/didcomm/packer/jwe/authcrypt/pack.go index 9471390640..bf15e8ca98 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/pack.go +++ b/pkg/didcomm/packer/jwe/authcrypt/pack.go @@ -25,25 +25,25 @@ import ( // Using (X)Chacha20 encryption algorithm and Poly1305 authenticator // It will encrypt by fetching the sender's encryption key corresponding to senderVerKey and converting the list // of recipientsVerKeys into a list of encryption keys -func (c *Packer) Pack(payload, senderVerKey []byte, recipientsVerKeys [][]byte) ([]byte, error) { //nolint:funlen - senderPubKey, err := c.getSenderPubEncKey(senderVerKey) +func (p *Packer) Pack(payload, senderVerKey []byte, recipientsVerKeys [][]byte) ([]byte, error) { //nolint:funlen + senderPubKey, err := p.getSenderPubEncKey(senderVerKey) if err != nil { return nil, err } headers := jweHeaders{ - Typ: "prs.hyperledger.aries-auth-message", - Alg: "ECDH-SS+" + string(c.alg) + "KW", - Enc: string(c.alg), + Typ: encodingType, + Alg: "ECDH-SS+" + string(p.alg) + "KW", + Enc: string(p.alg), } if len(recipientsVerKeys) == 0 { - return nil, fmt.Errorf("failed to encrypt message: empty recipients") + return nil, fmt.Errorf("failed to pack message: empty recipients") } - chachaRecipients, err := c.convertRecipients(recipientsVerKeys) + chachaRecipients, err := p.convertRecipients(recipientsVerKeys) if err != nil { - return nil, fmt.Errorf("failed to encrypt message: %w", err) + return nil, fmt.Errorf("failed to pack message: %w", err) } aad := buildAAD(chachaRecipients) @@ -59,7 +59,7 @@ func (c *Packer) Pack(payload, senderVerKey []byte, recipientsVerKeys [][]byte) pldAAD := encHeaders + "." + aadEncoded // generate a new nonce for this encryption - nonce := make([]byte, c.nonceSize) + nonce := make([]byte, p.nonceSize) _, err = randReader.Read(nonce) if err != nil { @@ -76,7 +76,7 @@ func (c *Packer) Pack(payload, senderVerKey []byte, recipientsVerKeys [][]byte) } // create a cipher for the given nonceSize and generated cek above - cipher, err := createCipher(c.nonceSize, cek[:]) + cipher, err := createCipher(p.nonceSize, cek[:]) if err != nil { return nil, err } @@ -89,12 +89,12 @@ func (c *Packer) Pack(payload, senderVerKey []byte, recipientsVerKeys [][]byte) cipherTextEncoded := extractCipherText(symOutput) // now build, encode recipients and include the encrypted cek (with a recipient's ephemeral key) - encRec, err := c.encodeRecipients(cek, chachaRecipients, senderPubKey) + encRec, err := p.encodeRecipients(cek, chachaRecipients, senderPubKey) if err != nil { return nil, err } - jwe, err := c.buildJWE(encHeaders, encRec, aadEncoded, nonceEncoded, tagEncoded, cipherTextEncoded) + jwe, err := p.buildJWE(encHeaders, encRec, aadEncoded, nonceEncoded, tagEncoded, cipherTextEncoded) if err != nil { return nil, err } @@ -102,12 +102,12 @@ func (c *Packer) Pack(payload, senderVerKey []byte, recipientsVerKeys [][]byte) return jwe, nil } -func (c *Packer) getSenderPubEncKey(senderVerKey []byte) (*[chacha.KeySize]byte, error) { +func (p *Packer) getSenderPubEncKey(senderVerKey []byte) (*[chacha.KeySize]byte, error) { if len(senderVerKey) == 0 { - return nil, fmt.Errorf("failed to encrypt message: empty sender key") + return nil, fmt.Errorf("failed to pack message: empty sender key") } - senderKey, err := c.kms.GetEncryptionKey(senderVerKey) + senderKey, err := p.kms.GetEncryptionKey(senderVerKey) if err != nil { return nil, err } @@ -120,7 +120,7 @@ func (c *Packer) getSenderPubEncKey(senderVerKey []byte) (*[chacha.KeySize]byte, // convertRecipients is a utility function that converts keys from signature keys ([][]byte type) // into encryption keys ([]*[chacha.KeySize]byte type) -func (c *Packer) convertRecipients(recipients [][]byte) ([]*[chacha.KeySize]byte, error) { +func (p *Packer) convertRecipients(recipients [][]byte) ([]*[chacha.KeySize]byte, error) { var chachaRecipients []*[chacha.KeySize]byte for i, rVer := range recipients { @@ -163,7 +163,7 @@ func extractCipherText(symOutput []byte) string { // buildJWE builds the JSON object representing the JWE output of the encryption // and returns its marshaled []byte representation -func (c *Packer) buildJWE(headers string, recipients []Recipient, aad, iv, tag, cipherText string) ([]byte, error) { //nolint:lll +func (p *Packer) buildJWE(headers string, recipients []Recipient, aad, iv, tag, cipherText string) ([]byte, error) { //nolint:lll jwe := Envelope{ Protected: headers, Recipients: recipients, @@ -204,11 +204,11 @@ func hashAAD(keys []string) []byte { // encodeRecipients is a utility function that will encrypt the cek (content encryption key) for each recipient // and return a list of encoded recipient keys in a JWE compliant format ([]Recipient) -func (c *Packer) encodeRecipients(cek *[chacha.KeySize]byte, recipients []*[chacha.KeySize]byte, senderPubKey *[chacha.KeySize]byte) ([]Recipient, error) { //nolint:lll +func (p *Packer) encodeRecipients(cek *[chacha.KeySize]byte, recipients []*[chacha.KeySize]byte, senderPubKey *[chacha.KeySize]byte) ([]Recipient, error) { //nolint:lll var encodedRecipients []Recipient for _, e := range recipients { - rec, err := c.encodeRecipient(cek, e, senderPubKey) + rec, err := p.encodeRecipient(cek, e, senderPubKey) if err != nil { return nil, err } @@ -222,7 +222,7 @@ func (c *Packer) encodeRecipients(cek *[chacha.KeySize]byte, recipients []*[chac // encodeRecipient will encrypt the cek (content encryption key) with a recipientKey // by generating a new ephemeral key to be used by the recipient to later decrypt it // it returns a JWE compliant Recipient -func (c *Packer) encodeRecipient(cek, recipientPubKey, senderPubKey *[chacha.KeySize]byte) (*Recipient, error) { //nolint:lll +func (p *Packer) encodeRecipient(cek, recipientPubKey, senderPubKey *[chacha.KeySize]byte) (*Recipient, error) { //nolint:lll // generate a random APU value (Agreement PartyUInfo: https://tools.ietf.org/html/rfc7518#section-4.6.1.2) apu := make([]byte, 64) @@ -232,26 +232,26 @@ func (c *Packer) encodeRecipient(cek, recipientPubKey, senderPubKey *[chacha.Key } // derive an ephemeral key for the sender and recipient - kek, err := c.kms.DeriveKEK([]byte(c.alg), apu, senderPubKey[:], recipientPubKey[:]) + kek, err := p.kms.DeriveKEK([]byte(p.alg), apu, senderPubKey[:], recipientPubKey[:]) if err != nil { return nil, err } - sharedKeyCipher, tag, nonce, err := c.encryptCEK(kek, cek[:]) + sharedKeyCipher, tag, nonce, err := p.encryptCEK(kek, cek[:]) if err != nil { return nil, err } - spk, err := c.generateSPK(recipientPubKey, senderPubKey) + spk, err := p.generateSPK(recipientPubKey, senderPubKey) if err != nil { return nil, err } - return c.buildRecipient(sharedKeyCipher, apu, spk, nonce, tag, recipientPubKey) + return p.buildRecipient(sharedKeyCipher, apu, spk, nonce, tag, recipientPubKey) } // buildRecipient will build a proper JSON formatted and JWE compliant Recipient -func (c *Packer) buildRecipient(key string, apu []byte, spkEncoded, nonceEncoded, tagEncoded string, recipientKey *[chacha.KeySize]byte) (*Recipient, error) { //nolint:lll +func (p *Packer) buildRecipient(key string, apu []byte, spkEncoded, nonceEncoded, tagEncoded string, recipientKey *[chacha.KeySize]byte) (*Recipient, error) { //nolint:lll recipientHeaders := RecipientHeaders{ APU: base64.RawURLEncoding.EncodeToString(apu), IV: nonceEncoded, @@ -274,14 +274,14 @@ func (c *Packer) buildRecipient(key string, apu []byte, spkEncoded, nonceEncoded // resulting tag of the encryption // generated nonce used by the encryption // error in case of failure -func (c *Packer) encryptCEK(kek, cek []byte) (string, string, string, error) { - cipher, err := createCipher(c.nonceSize, kek) +func (p *Packer) encryptCEK(kek, cek []byte) (string, string, string, error) { + cipher, err := createCipher(p.nonceSize, kek) if err != nil { return "", "", "", err } // create a new nonce - nonce := make([]byte, c.nonceSize) + nonce := make([]byte, p.nonceSize) _, err = randReader.Read(nonce) if err != nil { diff --git a/pkg/didcomm/packer/jwe/authcrypt/unpack.go b/pkg/didcomm/packer/jwe/authcrypt/unpack.go index b4dd8f71c0..8f6998a2d9 100644 --- a/pkg/didcomm/packer/jwe/authcrypt/unpack.go +++ b/pkg/didcomm/packer/jwe/authcrypt/unpack.go @@ -22,22 +22,22 @@ import ( // encrypted CEK. // The current recipient is the one with the sender's encrypted key that successfully // decrypts with recipientKeyPair.Priv Key. -func (c *Packer) Unpack(envelope []byte) ([]byte, error) { +func (p *Packer) Unpack(envelope []byte) ([]byte, error) { jwe := &Envelope{} err := json.Unmarshal(envelope, jwe) if err != nil { - return nil, fmt.Errorf("failed to decrypt message: %w", err) + return nil, fmt.Errorf("unpack: %w", err) } - recipientPubKey, recipient, err := c.findRecipient(jwe.Recipients) + recipientPubKey, recipient, err := p.findRecipient(jwe.Recipients) if err != nil { - return nil, fmt.Errorf("failed to decrypt message: %w", err) + return nil, fmt.Errorf("unpack: %w", err) } - senderKey, err := c.decryptSPK(recipientPubKey, recipient.Header.SPK) + senderKey, err := p.decryptSPK(recipientPubKey, recipient.Header.SPK) if err != nil { - return nil, fmt.Errorf("failed to decrypt sender key: %w", err) + return nil, fmt.Errorf("unpack: sender key: %w", err) } // senderKey must not be empty to proceed @@ -45,24 +45,24 @@ func (c *Packer) Unpack(envelope []byte) ([]byte, error) { senderPubKey := new([chacha.KeySize]byte) copy(senderPubKey[:], senderKey) - sharedKey, er := c.decryptCEK(recipientPubKey, senderPubKey, recipient) + sharedKey, er := p.decryptCEK(recipientPubKey, senderPubKey, recipient) if er != nil { - return nil, fmt.Errorf("failed to decrypt shared key: %w", er) + return nil, fmt.Errorf("unpack: decrypt shared key: %w", er) } - symOutput, er := c.decryptPayload(sharedKey, jwe) + symOutput, er := p.decryptPayload(sharedKey, jwe) if er != nil { - return nil, fmt.Errorf("failed to decrypt message: %w", er) + return nil, fmt.Errorf("unpack: %w", er) } return symOutput, nil } - return nil, errors.New("failed to decrypt message - invalid sender key in envelope") + return nil, errors.New("unpack: invalid sender key in envelope") } -func (c *Packer) decryptPayload(cek []byte, jwe *Envelope) ([]byte, error) { - cipher, err := createCipher(c.nonceSize, cek) +func (p *Packer) decryptPayload(cek []byte, jwe *Envelope) ([]byte, error) { + cipher, err := createCipher(p.nonceSize, cek) if err != nil { return nil, err } @@ -90,13 +90,13 @@ func (c *Packer) decryptPayload(cek []byte, jwe *Envelope) ([]byte, error) { } // findRecipient will loop through jweRecipients and returns the first matching key from the kms -func (c *Packer) findRecipient(jweRecipients []Recipient) (*[chacha.KeySize]byte, *Recipient, error) { +func (p *Packer) findRecipient(jweRecipients []Recipient) (*[chacha.KeySize]byte, *Recipient, error) { var recipientsKeys []string for _, recipient := range jweRecipients { recipientsKeys = append(recipientsKeys, recipient.Header.KID) } - i, err := c.kms.FindVerKey(recipientsKeys) + i, err := p.kms.FindVerKey(recipientsKeys) if err != nil { return nil, nil, err } @@ -108,7 +108,7 @@ func (c *Packer) findRecipient(jweRecipients []Recipient) (*[chacha.KeySize]byte } // decryptCEK will decrypt the CEK found in recipient using recipientKp's private key and senderPubKey -func (c *Packer) decryptCEK(recipientPubKey, senderPubKey *[chacha.KeySize]byte, recipient *Recipient) ([]byte, error) { //nolint:lll +func (p *Packer) decryptCEK(recipientPubKey, senderPubKey *[chacha.KeySize]byte, recipient *Recipient) ([]byte, error) { //nolint:lll apu, err := base64.RawURLEncoding.DecodeString(recipient.Header.APU) if err != nil { return nil, err @@ -119,7 +119,7 @@ func (c *Packer) decryptCEK(recipientPubKey, senderPubKey *[chacha.KeySize]byte, return nil, err } - if len(nonce) != c.nonceSize { + if len(nonce) != p.nonceSize { return nil, errors.New("bad nonce size") } @@ -134,13 +134,13 @@ func (c *Packer) decryptCEK(recipientPubKey, senderPubKey *[chacha.KeySize]byte, } // derive an ephemeral key for the recipient - kek, err := c.kms.DeriveKEK([]byte(c.alg), apu, recipientPubKey[:], senderPubKey[:]) + kek, err := p.kms.DeriveKEK([]byte(p.alg), apu, recipientPubKey[:], senderPubKey[:]) if err != nil { return nil, err } // create a new (chacha20poly1305) cipher with this new key to decrypt the cek - cipher, err := createCipher(c.nonceSize, kek) + cipher, err := createCipher(p.nonceSize, kek) if err != nil { return nil, err } diff --git a/pkg/didcomm/packer/legacy/authcrypt/authcrypt.go b/pkg/didcomm/packer/legacy/authcrypt/authcrypt.go index e5492811f6..0e22d6b09e 100644 --- a/pkg/didcomm/packer/legacy/authcrypt/authcrypt.go +++ b/pkg/didcomm/packer/legacy/authcrypt/authcrypt.go @@ -10,19 +10,22 @@ import ( "crypto/rand" "io" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" "github.com/hyperledger/aries-framework-go/pkg/kms" ) -// Packer represents an Authcrypt Encrypter (Decrypter) that outputs/reads legacy Aries envelopes +// Packer represents an Authcrypt Pack/Unpacker that outputs/reads legacy Aries envelopes type Packer struct { randSource io.Reader kms kms.KeyManager } +// encodingType is the `typ` string identifier in a message that identifies the format as being legacy +const encodingType string = "JWM/1.0" + // New will create a Packer that encrypts messages using the legacy Aries format -// Note: legacy crypter does not support XChacha20Poly1035 (XC20P), only Chacha20Poly1035 (C20P) -func New(ctx envelope.KMSProvider) *Packer { +// Note: legacy Packer does not support XChacha20Poly1035 (XC20P), only Chacha20Poly1035 (C20P) +func New(ctx packer.Provider) *Packer { k := ctx.KMS() return &Packer{ @@ -59,3 +62,8 @@ type recipientHeader struct { Sender string `json:"sender,omitempty"` IV string `json:"iv,omitempty"` } + +// EncodingType returns the type of the encoding, as in the `Typ` field of the envelope header +func (p *Packer) EncodingType() string { + return encodingType +} diff --git a/pkg/didcomm/packer/legacy/authcrypt/authcrypt_test.go b/pkg/didcomm/packer/legacy/authcrypt/authcrypt_test.go index 917f1a5604..2745745a07 100644 --- a/pkg/didcomm/packer/legacy/authcrypt/authcrypt_test.go +++ b/pkg/didcomm/packer/legacy/authcrypt/authcrypt_test.go @@ -18,6 +18,7 @@ import ( "github.com/btcsuite/btcutil/base58" "github.com/stretchr/testify/require" + "golang.org/x/crypto/ed25519" "github.com/hyperledger/aries-framework-go/pkg/internal/cryptoutil" mockkms "github.com/hyperledger/aries-framework-go/pkg/internal/mock/kms" @@ -134,12 +135,46 @@ func newWithKMS(k kms.KeyManager) *Packer { }) } +func TestEncodingType(t *testing.T) { + // create temporary signing keys for tests + sigPubKey, sigPrivKey, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + // convert signing keys to encryption keys + encPubKey, err := cryptoutil.PublicEd25519toCurve25519(sigPubKey) + require.NoError(t, err) + + encPrivKey, err := cryptoutil.SecretEd25519toCurve25519(sigPrivKey) + require.NoError(t, err) + + require.NoError(t, err) + + kp := &cryptoutil.MessagingKeys{ + SigKeyPair: &cryptoutil.SigKeyPair{ + KeyPair: cryptoutil.KeyPair{Pub: sigPubKey, Priv: sigPrivKey}, + Alg: cryptoutil.EdDSA, + }, + EncKeyPair: &cryptoutil.EncKeyPair{ + KeyPair: cryptoutil.KeyPair{Pub: encPubKey, Priv: encPrivKey}, + Alg: cryptoutil.Curve25519, + }, + } + + kmsProvider, err := mockkms.NewMockProvider(kp) + require.NoError(t, err) + + packer := New(kmsProvider) + require.NotEmpty(t, packer) + + require.Equal(t, encodingType, packer.EncodingType()) +} + func TestEncrypt(t *testing.T) { testingKMS, _ := newKMS(t) _, senderKey, e := testingKMS.CreateKeySet() require.NoError(t, e) - t.Run("Failure: encrypt without any recipients", func(t *testing.T) { + t.Run("Failure: pack without any recipients", func(t *testing.T) { packer := newWithKMS(testingKMS) require.NotEmpty(t, packer) @@ -147,7 +182,7 @@ func TestEncrypt(t *testing.T) { require.EqualError(t, err, "empty recipients keys, must have at least one recipient") }) - t.Run("Failure: encrypt with an invalid recipient key", func(t *testing.T) { + t.Run("Failure: pack with an invalid recipient key", func(t *testing.T) { packer := newWithKMS(testingKMS) require.NotEmpty(t, packer) @@ -160,7 +195,7 @@ func TestEncrypt(t *testing.T) { _, recipientKey, e := testingKMS.CreateKeySet() require.NoError(t, e) - t.Run("Failure: encrypt with an invalid-size sender key", func(t *testing.T) { + t.Run("Failure: pack with an invalid-size sender key", func(t *testing.T) { packer := newWithKMS(testingKMS) require.NotEmpty(t, packer) @@ -315,7 +350,7 @@ func TestEncryptComponents(t *testing.T) { require.EqualError(t, err, "mock Reader has failed intentionally") }) - t.Run("Success: 4 reads necessary for encrypt", func(t *testing.T) { + t.Run("Success: 4 reads necessary for pack", func(t *testing.T) { failRand := newFailReader(4, rand.Reader) packer.randSource = failRand @@ -345,7 +380,7 @@ func TestDecrypt(t *testing.T) { _, recKey, err := testingKMS.CreateKeySet() require.NoError(t, err) - t.Run("Success: encrypt then decrypt, same crypter", func(t *testing.T) { + t.Run("Success: pack then unpack, same packer", func(t *testing.T) { packer := newWithKMS(testingKMS) require.NoError(t, err) @@ -359,7 +394,7 @@ func TestDecrypt(t *testing.T) { require.ElementsMatch(t, msgIn, msgOut) }) - t.Run("Success: encrypt and decrypt, different crypters, including fail recipient who wasn't sent the message", func(t *testing.T) { // nolint: lll + t.Run("Success: pack and unpack, different packers, including fail recipient who wasn't sent the message", func(t *testing.T) { // nolint: lll rec1KMS, _ := newKMS(t) _, rec1Key, err := rec1KMS.CreateKeySet() require.NoError(t, err) @@ -393,7 +428,7 @@ func TestDecrypt(t *testing.T) { require.Contains(t, err.Error(), "no key accessible") }) - t.Run("Test decrypting python envelope", func(t *testing.T) { + t.Run("Test unpacking python envelope", func(t *testing.T) { env := `{"protected": "eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMCIsICJhbGciOiAiQXV0aGNyeXB0IiwgInJlY2lwaWVudHMiOiBbeyJlbmNyeXB0ZWRfa2V5IjogIkVhTVl4b3RKYjg4Vmt2ZmxNN1htajdFUzdvVVVSOEJSWWZ1akJGS1FGT3Y4Q2o3c0F2RndVWE5QdWVWanZ0SkEiLCAiaGVhZGVyIjogeyJraWQiOiAiRjdtTnRGMmZyTHVSdTJjTUVqWEJuV2RZY1RaQVhOUDlqRWtwclh4aWFaaTEiLCAic2VuZGVyIjogInJna1lWLUlxTWxlQUNkdE1qYXE4YnpwQXBKLXlRbjdWdzRIUnFZODNJVFozNzJkc0Y5RzV6bTVKMGhyNDVuSzBnS2JUYzRRYk5VZ1NreUExUlpZbEl6WHBwanN5eGdZUkU5ek9IbUFDcF9ldWZzejZ4YUxFOVRxN01KVT0iLCAiaXYiOiAiQ04wZWd4TFM2R19oUThDVXBjZkdZWmxzNjFtMm9YUVQifX1dfQ==", "iv": "Y4osZIg1IWaa1kFb", "ciphertext": "m9otQmcqYHOxZh4XfLbdCNouqnuPz7lGtcL5ga_1PZcPZDrhnGWPyLW2rPN2lRTftyYGPPT3tOlu4GFecZIz4zXI9kdz", "tag": "CoV9tCdrFnBbVe2h-pYyhQ=="}` // nolint: lll msg := "Yvgu yrf vy jgbuffi tvjc hgsj fhlusfm hsuf tiw fun s kb si kfuh bssnc" @@ -412,7 +447,7 @@ func TestDecrypt(t *testing.T) { require.ElementsMatch(t, []byte(msg), msgOut) }) - t.Run("Test decrypting python envelope with multiple recipients", func(t *testing.T) { + t.Run("Test unpacking python envelope with multiple recipients", func(t *testing.T) { env := `{"protected": "eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMCIsICJhbGciOiAiQXV0aGNyeXB0IiwgInJlY2lwaWVudHMiOiBbeyJlbmNyeXB0ZWRfa2V5IjogImd4X3NySTljSEtNTEJnaktNOTlybUx3alFZUjJxVTdMOXc0QWo3Z1lTbDJvUTRubE5WN2tZSmJ0bVFlaWVueE8iLCAiaGVhZGVyIjogeyJraWQiOiAiQ2ZGUmluZDh0eGYxOHJmVHl1aE1pZ2t4UVBhbVNUb3hVM2prdW5ldjR5dnUiLCAic2VuZGVyIjogImFWRW03ak5Kajg2Zm9NM0VYaXZjYWpOWlFnN3pGUm0wTnk5ZzdZTzFueUpvblI2bmNVaV9EZWZzWVBHa25KcG1ZbFhuRDIzVU5nLXNBN1lWUnh5WW15aFZBSm5XNWZwdjBuNE5jaFdBTjl5S3pIMTd3NjZQLVV2WjVDcz0iLCAiaXYiOiAieVB0NGhHZVpObWFLN0hMMGtoWjhreFJzQjc3c3BOX2UifX0sIHsiZW5jcnlwdGVkX2tleSI6ICJ3a3RrWjY3VDR4R2NjTW1GZnRIRmNEV2FZMVQxRFQ3YURhMHBPeUpqTHU2REU2UGVKMUhuVXlRWXlOZ2VPR3ExIiwgImhlYWRlciI6IHsia2lkIjogIko1c2hTVlo2QW9DWHFxWWROR2tVdjFDTWZRYWVLRnNGRU4zaFdwNVBLVEN3IiwgInNlbmRlciI6ICJWdEQtakZfZFNDbmVxOUtTcVB0SUtHbHdHb0FzVHB0UkhzMTRYaWhNR0U4LUh4SjU5aVhtSnVLellxTjM2b19ZOWxfYmRFT1pRSjN0R2tRX1BqbTJyQ3VqWkRIbjdDS3Fsd3N4QlNVemYweW43aWliaDFQazJ6R0wyb2M9IiwgIml2IjogIm5acW1CbzBfT2QyTHlXejlHclJJMUlhWlRXUk4zbGVBIn19LCB7ImVuY3J5cHRlZF9rZXkiOiAiUlBsQWtTS1NsdFpGeEFJc1VzbWNiUVVMUTJWWHhRT2kzUEIxelhTbGs3TlBtMkZ2TE9zVDdQSEFHQU5Hem5oNiIsICJoZWFkZXIiOiB7ImtpZCI6ICJCS3ZqbUZFYkMyYjF3YkVycUN4R2syYmdxdkc5dUx3UlU5cWdOS3lINXRURiIsICJzZW5kZXIiOiAiTVhvRXl0NlZULXVFQnFzWEM1SWF1VXdZYXFxakxIYTdWWlF0NGRJX3FBaFZHVWhUTi01c004cXB6TnBnQlpUUHJrazFSMlBnbjlraU4waEpTUXk1T0FmOGdkSE43YXRTVDhUWEtMSHJNdm4wcDcyNUNUd3pZVnZFVnlNPSIsICJpdiI6ICJPb2FTVWgycVdOVk5qWVV6ZnZTNTdCQ1RnY3ZQYVhMeCJ9fSwgeyJlbmNyeXB0ZWRfa2V5IjogImY1cXV2amt1c2l6TmtRcm9HMk51akFsa0NzbllleUF1R1pMWDZmXy1DeG4taUNENjI2akp0aEk4OFBSei1TWWUiLCAiaGVhZGVyIjogeyJraWQiOiAiRWZ3cFR3aFVSU0QzY3lxanNWYlNWU0VMeU4yN250Tlk4V3dhZHNnVUNEOW0iLCAic2VuZGVyIjogImlOMDJNRzllSEpZZmQ3V3pGd1VFeWJBNmFWeU1Ma1JHcXVhYlJGQnJobFU3Q29EMzFHdW5yTWhEWTZETGFJV0FoX2dPMVRLMWtpMzYtTzQ4TlEyZGdOLU1RdS0wZTV5V2dQS1dzV1MtQ2xPbllEQ0RpVkc1VHBJS2dpVT0iLCAiaXYiOiAiZUg0cDZOX0dGNnpzU2trQk5nY0dWN3RRQkxfRl93MS0ifX0sIHsiZW5jcnlwdGVkX2tleSI6ICJqa3FnbHlmUlNWSXZqVnpkZ04wSGN4SGVzMTBoTjE3ckJLejZhcUtlczR3UTRLWGNGYjNpa3pNSmFSWHAwblVSIiwgImhlYWRlciI6IHsia2lkIjogIkFROW5IdExubXVHODFweTY0WUc1Z2VGMnZkNWhRQ0tIaTVNcnFRMUxZQ1hFIiwgInNlbmRlciI6ICJpSXJFOVUyOUVUbTRWa045aFdvYy1UN0dGYjVrdHB4SGtGeWp6d3BLcDJ5MWh2WWQ0NDF0SzdFUXlhTXhHeG9KNklMaWFHNnNpbTF4WS05UHV2Ny03clB4QTFCb3FxMTY0VzJZZU9FRjFwbnBOV2VmYmdTc1dtQUk0QlU9IiwgIml2IjogIm03S2h3THJ1OGtyQ1VXN1BiNTczZWpGblI3Ymlod3lNIn19XX0=", "iv": "1_pOOQhySyaYcVxi", "ciphertext": "CYHrOg1HeNxhUECoRIQRLNAOXwAjagUYf0xLp0Knnj6mEALg8lFbfmoh_oDptJ4El8jVbgDLiBExaEXIxYVnR7DR-hZjxjdbOBQAOAMUYnnvAk0lHJM0KBWlhE0AWrek1JlAfTnq-L6VsCXEqGYHg1uvpBIJicE=", "tag": "l1KfDt-VQIAImCTl7SA2og=="}` // nolint: lll msg := "Iiwufh utiweuop fji olioy pio omlim, om kutxrwu gvgbkn kutxr " + @@ -432,7 +467,7 @@ func TestDecrypt(t *testing.T) { require.ElementsMatch(t, []byte(msg), msgOut) }) - t.Run("Test decrypting python envelope with invalid recipient", func(t *testing.T) { + t.Run("Test unpacking python envelope with invalid recipient", func(t *testing.T) { env := `{"protected": "eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMCIsICJhbGciOiAiQXV0aGNyeXB0IiwgInJlY2lwaWVudHMiOiBbeyJlbmNyeXB0ZWRfa2V5IjogIjdzN0ZTRXR6Sy1vTzdSWmdISklsSTlzX1lVU2xkMUpnRldPeUNhYUdGY1Y0aHBSTWxQbG0wNDBFcUJXRWVwY3oiLCAiaGVhZGVyIjogeyJraWQiOiAiN0RLbk56TWJHRWNYODYxOGp2WWtiNlhQTFR6eXU2YnhSbTh3RnhZb0d3SHEiLCAic2VuZGVyIjogInFLYTRDeXV1OXZOcmJzX1RCLXhQWXI2aFg2cXJZLTM4Vjd4VXdOQjFyd0J1TjVNTUVJYmRERDFvRElhV2o0QUpSYUZDTEVhSzMtakFSZHBsR1UtM2d4TWY2dkpRZWhiZkZhZHNwemdxRE9iWFZDWUJONGxrVXZLZWhvND0iLCAiaXYiOiAiSWFqeVdudFdSMENxS1BYUWJpWWptbWJRWFNNTEp2X1UifX0sIHsiZW5jcnlwdGVkX2tleSI6ICJZa05vVGh2ZUlIcC13NGlrRW1kQU51VHdxTEx1ZjBocVlVbXRJc2c5WlJMd1BKaUZHWVZuTXl1ZktKZWRvcmthIiwgImhlYWRlciI6IHsia2lkIjogIjdDRURlZUpZTnlRUzhyQjdNVHpvUHhWYXFIWm9ZZkQxNUVIVzhaVVN3VnVhIiwgInNlbmRlciI6ICJ3ZEhjc1hDemdTSjhucDRFU0pDcmJ5OWNrNjJaUEFFVjhJRjYwQmotaUhhbXJLRnBKOTJpZVNTaE1JcTdwdTNmQWZQLWo5S3J6ajAwMEV0SXB5cm05SmNrM0QwSnRBcmtYV2VsSzBoUF9ZeDR4Vlc5dW43MWlfdFBXNWM9IiwgIml2IjogIkRlbUlJbHRKaXd5TU1faGhIS29kcTZpQkx4Q1J5Z2Z3In19XX0=", "iv": "BKWHs6z0UHxGddwg", "ciphertext": "YC2eQQPYVjPHj3wIxUXxBj0yXFLuRN5Lc-9WM8hY6TXoekh-ca9-UWbHasikbcxyukTT3e-QiteOilG-6X7e9x4wiQmWn_NFLOLrqoFe669JIbkgvjHYwuQEQkIVfbD-2woSxsMUl9yln5RS-NssI5cEIVH_C1w=", "tag": "M8GPexbguDoZk5L51AvLjA=="}` // nolint: lll recPub := "A3KnccxQu27yWQrSLwA2YFbfoSs4CHo3q6LjvhmpKz9h" @@ -450,7 +485,7 @@ func TestDecrypt(t *testing.T) { }) } -func decryptComponentFailureTest( +func unpackComponentFailureTest( t *testing.T, protectedHeader, msg string, @@ -472,7 +507,7 @@ func decryptComponentFailureTest( require.Contains(t, err.Error(), errString) } -func TestDecryptComponents(t *testing.T) { +func TestUnpackComponents(t *testing.T) { recKey := getB58Key("Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "5pG8rLcp9WqPXQLSyQetPiyTEnLuanjS2TGd7h4DqutY6gNbLD6pnvT3H8nC5K9vEjy1UJdTtwaejf1xqDyhCrzr") @@ -503,7 +538,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Fail: header not json", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `}eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMC`, `"not important":[]}`, recKey, @@ -511,7 +546,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Fail: bad 'typ' field", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JSON", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -519,7 +554,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Fail: anoncrypt not supported", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Anoncrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, //nolint: lll recKey, @@ -527,7 +562,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Fail: no recipients in header", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": []}`, `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -538,7 +573,7 @@ func TestDecryptComponents(t *testing.T) { rec := getB58Key("6ZAQ7QpmR9EqhJdwx1jQsjq6nnpehwVqUbhVxiEiYEV7", // invalid key, won't convert "5pG8rLcp9WqPXQLSyQetPiyTEnLuanjS2TGd7h4DqutY6gNbLD6pnvT3H8nC5K9vEjy1UJdTtwaejf1xqDyhCrzr") - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "6ZAQ7QpmR9EqhJdwx1jQsjq6nnpehwVqUbhVxiEiYEV7", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll rec, @@ -549,7 +584,7 @@ func TestDecryptComponents(t *testing.T) { rec := getB58Key("57N4aoQKaxUGNeEn3ETnTKgeD1L5Wm3U3Vb8qi3hupLn", // mismatched keypair, won't decrypt "5pG8rLcp9WqPXQLSyQetPiyTEnLuanjS2TGd7h4DqutY6gNbLD6pnvT3H8nC5K9vEjy1UJdTtwaejf1xqDyhCrzr") - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "57N4aoQKaxUGNeEn3ETnTKgeD1L5Wm3U3Vb8qi3hupLn", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll rec, @@ -557,7 +592,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Sender is invalid base64 data", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "*^&", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -565,7 +600,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Sender is invalid public key", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "7ZA_k_bM4FRp6jY_LNzv9pjuOh1NbVlbBA-yTjzsc22HnPKPK8_MKUNU1Rlt0woNUNWLZI4ShBD_th14ULmTjggBI8K4A8efTI4efxv5xTYEemj9uVPvvLKs4Go=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -573,7 +608,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Message auth fail, protected header has extra whitespace", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, ` {"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -581,7 +616,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Nonce is invalid base64 data", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "(^_^)"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -589,7 +624,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Encrypted CEK is invalid base64 data", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "_-", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -597,7 +632,7 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Bad encrypted key cannot be decrypted", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_W", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -608,7 +643,7 @@ func TestDecryptComponents(t *testing.T) { prot := `{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "wZ4cC42eDMeLApmJvJC4INbuKINzdZZECGHpWDgsrmBURPJN_bWOkUV3E6oORN4ILAf_xEuWefS4b_goRycCogkZvTyS1HgvBtx2YO1A2q-a7tp__08Ky4qtSiY=", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}` // nolint: lll t.Run("Ciphertext nonce not valid b64 data", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, prot, `"iv": "!!!!!", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll recKey, @@ -616,14 +651,14 @@ func TestDecryptComponents(t *testing.T) { }) t.Run("Ciphertext not valid b64 data", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, prot, `"iv": "oDZpVO648Po3UcoW", "ciphertext": "=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, recKey, "illegal base64 data at input byte 0") }) t.Run("Ciphertext tag not valid b64 data", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, prot, `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "123"}`, // nolint: lll recKey, @@ -636,7 +671,7 @@ func TestDecryptComponents(t *testing.T) { } t.Run("Recipient Key not valid key", func(t *testing.T) { - decryptComponentFailureTest(t, + unpackComponentFailureTest(t, prot, `"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll &badKey, diff --git a/pkg/didcomm/packer/legacy/authcrypt/pack.go b/pkg/didcomm/packer/legacy/authcrypt/pack.go index 390027d65f..458fe8f23b 100644 --- a/pkg/didcomm/packer/legacy/authcrypt/pack.go +++ b/pkg/didcomm/packer/legacy/authcrypt/pack.go @@ -57,7 +57,7 @@ func (p *Packer) Pack(payload, sender []byte, recipientPubKeys [][]byte) ([]byte header := protected{ Enc: "chacha20poly1305_ietf", - Typ: "JWM/1.0", + Typ: encodingType, Alg: "Authcrypt", Recipients: recipients, } diff --git a/pkg/didcomm/packer/legacy/authcrypt/unpack.go b/pkg/didcomm/packer/legacy/authcrypt/unpack.go index 6151529690..b826f96fb2 100644 --- a/pkg/didcomm/packer/legacy/authcrypt/unpack.go +++ b/pkg/didcomm/packer/legacy/authcrypt/unpack.go @@ -40,7 +40,7 @@ func (p *Packer) Unpack(envelope []byte) ([]byte, error) { return nil, err } - if protectedData.Typ != "JWM/1.0" { + if protectedData.Typ != encodingType { return nil, fmt.Errorf("message type %s not supported", protectedData.Typ) } diff --git a/pkg/didcomm/transport/http/inbound.go b/pkg/didcomm/transport/http/inbound.go index b02ff410af..a039c7cd9e 100644 --- a/pkg/didcomm/transport/http/inbound.go +++ b/pkg/didcomm/transport/http/inbound.go @@ -14,7 +14,7 @@ import ( "net/http" "github.com/hyperledger/aries-framework-go/pkg/common/log" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + transport2 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" ) @@ -23,7 +23,7 @@ var logger = log.New("aries-framework/transport") // provider contains dependencies for the HTTP Handler creation and is typically created by using aries.Context() type provider interface { InboundMessageHandler() transport.InboundMessageHandler - Packager() envelope.Packager + Packager() transport2.Packager } // NewInboundHandler will create a new handler to enforce Did-Comm HTTP transport specs diff --git a/pkg/didcomm/transport/http/inbound_test.go b/pkg/didcomm/transport/http/inbound_test.go index 6537c8a67e..0c5248f88e 100644 --- a/pkg/didcomm/transport/http/inbound_test.go +++ b/pkg/didcomm/transport/http/inbound_test.go @@ -20,13 +20,13 @@ import ( "github.com/stretchr/testify/require" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + transport2 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" - mockpackager "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/envelope" + mockpackager "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/packager" ) type mockProvider struct { - packagerValue envelope.Packager + packagerValue transport2.Packager } func (p *mockProvider) InboundMessageHandler() transport.InboundMessageHandler { @@ -36,7 +36,7 @@ func (p *mockProvider) InboundMessageHandler() transport.InboundMessageHandler { } } -func (p *mockProvider) Packager() envelope.Packager { +func (p *mockProvider) Packager() transport2.Packager { return p.packagerValue } @@ -46,7 +46,7 @@ func TestInboundHandler(t *testing.T) { require.Error(t, err) require.Nil(t, inHandler) - mockPackager := &mockpackager.BasePackager{UnpackValue: &envelope.Envelope{Message: []byte("data")}} + mockPackager := &mockpackager.Packager{UnpackValue: &transport2.Envelope{Message: []byte("data")}} // now create a valid inboundHandler to continue testing.. inHandler, err = NewInboundHandler(&mockProvider{packagerValue: mockPackager}) @@ -147,7 +147,7 @@ func TestInboundTransport(t *testing.T) { inbound, err := NewInbound(":26603", "") require.NoError(t, err) require.NotEmpty(t, inbound) - mockPackager := &mockpackager.BasePackager{UnpackValue: &envelope.Envelope{Message: []byte("data")}} + mockPackager := &mockpackager.Packager{UnpackValue: &transport2.Envelope{Message: []byte("data")}} err = inbound.Start(&mockProvider{packagerValue: mockPackager}) require.NoError(t, err) @@ -177,7 +177,7 @@ func TestInboundTransport(t *testing.T) { require.NotEmpty(t, inbound) // start server - mockPackager := &mockpackager.BasePackager{UnpackValue: &envelope.Envelope{Message: []byte("data")}} + mockPackager := &mockpackager.Packager{UnpackValue: &transport2.Envelope{Message: []byte("data")}} err = inbound.Start(&mockProvider{packagerValue: mockPackager}) require.NoError(t, err) require.NoError(t, listenFor("localhost:26605", time.Second)) diff --git a/pkg/didcomm/transport/transport_interface.go b/pkg/didcomm/transport/transport_interface.go index 78b2ba5f9f..5e2eb9d5f4 100644 --- a/pkg/didcomm/transport/transport_interface.go +++ b/pkg/didcomm/transport/transport_interface.go @@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0 package transport import ( - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" ) // OutboundTransport interface definition for transport layer @@ -27,7 +27,7 @@ type InboundMessageHandler func(message []byte) error // It is typically created by using aries.Context(). type InboundProvider interface { InboundMessageHandler() InboundMessageHandler - Packager() envelope.Packager + Packager() transport.Packager } // InboundTransport interface definition for inbound transport layer diff --git a/pkg/framework/aries/api/protocol.go b/pkg/framework/aries/api/protocol.go index 79d3dc9f9e..bb8bfd6793 100644 --- a/pkg/framework/aries/api/protocol.go +++ b/pkg/framework/aries/api/protocol.go @@ -9,8 +9,8 @@ package api import ( "errors" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/dispatcher" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/didcreator" "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/didstore" "github.com/hyperledger/aries-framework-go/pkg/framework/didresolver" @@ -27,8 +27,7 @@ type Provider interface { Service(id string) (interface{}, error) StorageProvider() storage.Provider KMS() kms.KeyManager - Packer() envelope.Packer - Packager() envelope.Packager + Packager() transport.Packager InboundTransportEndpoint() string DIDCreator() didcreator.Creator Signer() kms.Signer diff --git a/pkg/framework/aries/default.go b/pkg/framework/aries/default.go index 4678f2fb0e..04d779e898 100644 --- a/pkg/framework/aries/default.go +++ b/pkg/framework/aries/default.go @@ -10,9 +10,12 @@ import ( "fmt" "net/http" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/dispatcher" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer/legacy/authcrypt" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packager" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" + jwe "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer/jwe/authcrypt" + legacy "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer/legacy/authcrypt" "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/didexchange" didcommtrans "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" arieshttp "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport/http" @@ -125,14 +128,25 @@ func setAdditionalDefaultOpts(frameworkOpts *Aries) { } if frameworkOpts.packerCreator == nil { - frameworkOpts.packerCreator = func(provider envelope.KMSProvider) (envelope.Packer, error) { - return authcrypt.New(provider), nil + frameworkOpts.packerCreator = func(provider packer.Provider) (packer.Packer, error) { + return legacy.New(provider), nil + } + } + + if frameworkOpts.inboundPackerCreators == nil { + frameworkOpts.inboundPackerCreators = []packer.Creator{ + func(provider packer.Provider) (packer.Packer, error) { + return legacy.New(provider), nil + }, + func(provider packer.Provider) (packer.Packer, error) { + return jwe.New(provider, jwe.XC20P) + }, } } if frameworkOpts.packagerCreator == nil { - frameworkOpts.packagerCreator = func(provider envelope.PackerProvider) (envelope.Packager, error) { - return envelope.New(provider) + frameworkOpts.packagerCreator = func(prov packager.Provider) (transport.Packager, error) { + return packager.New(prov) } } diff --git a/pkg/framework/aries/framework.go b/pkg/framework/aries/framework.go index ae23b18799..efbecd1f27 100644 --- a/pkg/framework/aries/framework.go +++ b/pkg/framework/aries/framework.go @@ -9,8 +9,10 @@ package aries import ( "fmt" + transport2 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/dispatcher" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packager" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api" "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/didstore" @@ -31,10 +33,12 @@ type Aries struct { kms api.CloseableKMS outboundDispatcherCreator dispatcher.OutboundCreator outboundDispatcher dispatcher.Outbound - packagerCreator envelope.PackagerCreator - packager envelope.Packager - packerCreator envelope.Creator - packer envelope.Packer + packagerCreator packager.Creator + packager transport2.Packager + packerCreator packer.Creator + inboundPackerCreators []packer.Creator + packer packer.Packer + inboundPackers []packer.Packer didResolver didresolver.Resolver // TODO: the DID provider options should be part of a verifiable data registry (vdr) option. didStore didstore.Storage @@ -76,8 +80,8 @@ func New(opts ...Option) (*Aries, error) { return nil, e } - // create create packer and packager (must be done after KMS) - err = createCrypterAndPackager(frameworkOpts) + // create packers and packager (must be done after KMS) + err = createPackersAndPackager(frameworkOpts) if err != nil { return nil, err } @@ -167,18 +171,20 @@ func WithKMS(k api.KMSCreator) Option { } } -// WithPacker injects a packer service to the Aries framework -func WithPacker(c envelope.Creator) Option { +// WithPacker injects a Packer service to the Aries framework +// to pack outbound messages and be available for unpacking inbound messages. +func WithPacker(c packer.Creator) Option { return func(opts *Aries) error { opts.packerCreator = c return nil } } -// WithPackager injects a packager service to the Aries framework -func WithPackager(p envelope.PackagerCreator) Option { +// WithInboundPackers injects a variable number of Packer services into the Aries framework +// for unpacking inbound messages. +func WithInboundPackers(packers ...packer.Creator) Option { return func(opts *Aries) error { - opts.packagerCreator = p + opts.inboundPackerCreators = append(opts.inboundPackerCreators, packers...) return nil } } @@ -208,6 +214,7 @@ func (a *Aries) Context() (*context.Provider, error) { context.WithStorageProvider(a.storeProvider), context.WithTransientStorageProvider(a.transientStoreProvider), context.WithPacker(a.packer), + context.WithInboundPackers(a.inboundPackers...), context.WithPackager(a.packager), context.WithDIDResolver(a.didResolver), context.WithDIDStore(a.didStore), @@ -319,10 +326,10 @@ func loadServices(frameworkOpts *Aries) error { return nil } -func createCrypterAndPackager(frameworkOpts *Aries) error { +func createPackersAndPackager(frameworkOpts *Aries) error { ctx, err := context.New(context.WithKMS(frameworkOpts.kms)) if err != nil { - return fmt.Errorf("create packer context failed: %w", err) + return fmt.Errorf("create envelope context failed: %w", err) } frameworkOpts.packer, err = frameworkOpts.packerCreator(ctx) @@ -330,7 +337,18 @@ func createCrypterAndPackager(frameworkOpts *Aries) error { return fmt.Errorf("create packer failed: %w", err) } - ctx, err = context.New(context.WithPacker(frameworkOpts.packer)) + for _, pC := range frameworkOpts.inboundPackerCreators { + p, e := pC(ctx) + if e != nil { + return fmt.Errorf("create packer failed: %w", e) + } + + frameworkOpts.inboundPackers = append(frameworkOpts.inboundPackers, p) + } + + ctx, err = context.New( + context.WithPacker(frameworkOpts.packer), + context.WithInboundPackers(frameworkOpts.inboundPackers...)) if err != nil { return fmt.Errorf("create packager context failed: %w", err) } diff --git a/pkg/framework/aries/framework_test.go b/pkg/framework/aries/framework_test.go index 7fd970095a..83f404cba2 100644 --- a/pkg/framework/aries/framework_test.go +++ b/pkg/framework/aries/framework_test.go @@ -20,7 +20,7 @@ import ( "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" "github.com/hyperledger/aries-framework-go/pkg/didcomm/dispatcher" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/didexchange" "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" "github.com/hyperledger/aries-framework-go/pkg/didmethod/peer" @@ -29,7 +29,6 @@ import ( "github.com/hyperledger/aries-framework-go/pkg/framework/didresolver" "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm" mockdispatcher "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/dispatcher" - mockenvelope "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/envelope" "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/protocol" mockdidstore "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didstore" mockkms "github.com/hyperledger/aries-framework-go/pkg/internal/mock/kms" @@ -91,11 +90,20 @@ func TestFramework(t *testing.T) { WithKMS(func(ctx api.Provider) (api.CloseableKMS, error) { return &mockkms.CloseableKMS{SignMessageValue: []byte("mockValue")}, nil }), - WithPacker(func(ctx envelope.KMSProvider) (envelope.Packer, error) { - return &didcomm.MockAuthCrypt{EncryptValue: nil}, nil + WithPacker(func(ctx packer.Provider) (packer.Packer, error) { + return &didcomm.MockAuthCrypt{ + EncryptValue: func(payload, senderPubKey []byte, recipients [][]byte) (bytes []byte, e error) { + return []byte("packed message"), nil + }, + DecryptValue: nil, + Type: "", + }, nil }), - WithPackager(func(ctx envelope.PackerProvider) (envelope.Packager, error) { - return &mockenvelope.BasePackager{PackValue: []byte("mockPackValue")}, nil + WithInboundPackers(func(ctx packer.Provider) (packer.Packer, error) { + return &didcomm.MockAuthCrypt{ + EncryptValue: nil, + Type: "dummy format", + }, nil })) require.NoError(t, err) @@ -401,6 +409,30 @@ func TestFramework(t *testing.T) { }) } +func Test_Packager(t *testing.T) { + t.Run("test error from packager svc - outbound packer", func(t *testing.T) { + f, err := New(WithInboundTransport(&mockInboundTransport{}), + WithStoreProvider(storage.NewMockStoreProvider()), + WithPacker(func(ctx packer.Provider) (packer.Packer, error) { + return nil, fmt.Errorf("error from outbound packer") + })) + require.Error(t, err) + require.Nil(t, f) + require.Contains(t, err.Error(), "error from outbound packer") + }) + + t.Run("test error from packager svc - fallback packer", func(t *testing.T) { + f, err := New(WithInboundTransport(&mockInboundTransport{}), + WithStoreProvider(storage.NewMockStoreProvider()), + WithInboundPackers(func(ctx packer.Provider) (packer.Packer, error) { + return nil, fmt.Errorf("error from packer") + })) + require.Error(t, err) + require.Nil(t, f) + require.Contains(t, err.Error(), "error from packer") + }) +} + type mockDidMethod struct { readValue []byte readErr error diff --git a/pkg/framework/context/context.go b/pkg/framework/context/context.go index b88c9b1266..93a8e3df9a 100644 --- a/pkg/framework/context/context.go +++ b/pkg/framework/context/context.go @@ -10,8 +10,9 @@ import ( "fmt" "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" + transport2 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/didcomm/dispatcher" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api" "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/didcreator" @@ -28,8 +29,9 @@ type Provider struct { storeProvider storage.Provider transientStoreProvider storage.Provider kms kms.KMS - packager envelope.Packager - packer envelope.Packer + packager transport2.Packager + packer packer.Packer + inboundPackers []packer.Packer inboundTransportEndpoint string outboundTransport transport.OutboundTransport didResolver didresolver.Resolver @@ -78,12 +80,17 @@ func (p *Provider) KMS() kms.KeyManager { } // Packager returns the packager service -func (p *Provider) Packager() envelope.Packager { +func (p *Provider) Packager() transport2.Packager { return p.packager } -// Packer returns the packer service to be used by the packager -func (p *Provider) Packer() envelope.Packer { +// InboundPackers returns a list of enabled packers +func (p *Provider) InboundPackers() []packer.Packer { + return p.inboundPackers +} + +// Packer returns the outbound Packer service +func (p *Provider) Packer() packer.Packer { return p.packer } @@ -217,17 +224,25 @@ func WithDIDResolver(r didresolver.Resolver) ProviderOption { } // WithPackager injects a packager into the context -func WithPackager(p envelope.Packager) ProviderOption { +func WithPackager(p transport2.Packager) ProviderOption { return func(opts *Provider) error { opts.packager = p return nil } } -// WithPacker injects a packer into the context -func WithPacker(p envelope.Packer) ProviderOption { +// WithPacker injects a Packer into the context as the outbound Packer +func WithPacker(p packer.Packer) ProviderOption { return func(opts *Provider) error { opts.packer = p return nil } } + +// WithInboundPackers injects a variable number of Packer services into the Aries framework +func WithInboundPackers(packers ...packer.Packer) ProviderOption { + return func(opts *Provider) error { + opts.inboundPackers = append(opts.inboundPackers, packers...) + return nil + } +} diff --git a/pkg/framework/context/context_test.go b/pkg/framework/context/context_test.go index 9f6f064207..93ba5f846c 100644 --- a/pkg/framework/context/context_test.go +++ b/pkg/framework/context/context_test.go @@ -16,11 +16,11 @@ import ( "github.com/stretchr/testify/require" "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/doc/did" mockdidcomm "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm" mockdispatcher "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/dispatcher" - mockenvelope "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/envelope" + mockpackager "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/packager" "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didcomm/protocol" "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didresolver" mockdidstore "github.com/hyperledger/aries-framework-go/pkg/internal/mock/didstore" @@ -134,7 +134,19 @@ func TestNewProvider(t *testing.T) { t.Run("test new with kms and packager service", func(t *testing.T) { prov, err := New( WithKMS(&mockkms.CloseableKMS{SignMessageValue: []byte("mockValue")}), - WithPackager(&mockenvelope.BasePackager{PackValue: []byte("data")}), + WithPackager(&mockpackager.Packager{PackValue: []byte("data")}), + WithInboundPackers(&mockdidcomm.MockAuthCrypt{ + EncryptValue: nil, + DecryptValue: nil, + Type: "TYPE", + }), + WithPacker(&mockdidcomm.MockAuthCrypt{ + EncryptValue: func(p, spk []byte, rpks [][]byte) ([]byte, error) { + return []byte("data data"), nil + }, + DecryptValue: nil, + Type: "", + }), ) require.NoError(t, err) v, err := prov.Signer().SignMessage(nil, "") @@ -143,9 +155,18 @@ func TestNewProvider(t *testing.T) { index, err := prov.KMS().FindVerKey([]string{"non-existent"}) require.NoError(t, err) require.Equal(t, 0, index) - v, err = prov.packager.PackMessage(&envelope.Envelope{}) + v, err = prov.Packager().PackMessage(&transport.Envelope{}) require.NoError(t, err) require.Equal(t, []byte("data"), v) + + v, err = prov.Packer().Pack(nil, nil, nil) + require.NoError(t, err) + require.Equal(t, []byte("data data"), v) + + packers := prov.InboundPackers() + require.Len(t, packers, 1) + typ := packers[0].EncodingType() + require.Equal(t, "TYPE", typ) }) t.Run("test new with inbound transport endpoint", func(t *testing.T) { diff --git a/pkg/internal/mock/didcomm/envelope/mock_packager.go b/pkg/internal/mock/didcomm/envelope/mock_packager.go deleted file mode 100644 index d0b6bf252e..0000000000 --- a/pkg/internal/mock/didcomm/envelope/mock_packager.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package envelope - -import baseenv "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" - -// BasePackager represents a mocked Packager -type BasePackager struct { - PackValue []byte - PackErr error - UnpackValue *baseenv.Envelope - UnpackErr error -} - -// PackMessage Pack a message for one or more recipients. -func (m *BasePackager) PackMessage(envelope *baseenv.Envelope) ([]byte, error) { - return m.PackValue, m.PackErr -} - -// UnpackMessage Unpack a message. -func (m *BasePackager) UnpackMessage(encMessage []byte) (*baseenv.Envelope, error) { - return m.UnpackValue, m.UnpackErr -} diff --git a/pkg/internal/mock/didcomm/mock_authcrypt.go b/pkg/internal/mock/didcomm/mock_authcrypt.go index 20ee53d654..e47f2009ef 100644 --- a/pkg/internal/mock/didcomm/mock_authcrypt.go +++ b/pkg/internal/mock/didcomm/mock_authcrypt.go @@ -10,15 +10,21 @@ package didcomm type MockAuthCrypt struct { EncryptValue func(payload, senderPubKey []byte, recipients [][]byte) ([]byte, error) DecryptValue func(envelope []byte) ([]byte, error) + Type string } -// Pack mock encrypt +// Pack mock message packing func (m *MockAuthCrypt) Pack(payload, senderPubKey []byte, recipients [][]byte) ([]byte, error) { return m.EncryptValue(payload, senderPubKey, recipients) } -// Unpack mock decrypt +// Unpack mock message unpacking func (m *MockAuthCrypt) Unpack(envelope []byte) ([]byte, error) { return m.DecryptValue(envelope) } + +// EncodingType mock encoding type +func (m *MockAuthCrypt) EncodingType() string { + return m.Type +} diff --git a/pkg/internal/mock/didcomm/packager/mock_packager.go b/pkg/internal/mock/didcomm/packager/mock_packager.go new file mode 100644 index 0000000000..9e785ecce5 --- /dev/null +++ b/pkg/internal/mock/didcomm/packager/mock_packager.go @@ -0,0 +1,29 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package packager + +import ( + "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" +) + +// Packager represents a mocked Packager +type Packager struct { + PackValue []byte + PackErr error + UnpackValue *transport.Envelope + UnpackErr error +} + +// PackMessage Pack a message for one or more recipients. +func (m *Packager) PackMessage(e *transport.Envelope) ([]byte, error) { + return m.PackValue, m.PackErr +} + +// UnpackMessage Unpack a message. +func (m *Packager) UnpackMessage(encMessage []byte) (*transport.Envelope, error) { + return m.UnpackValue, m.UnpackErr +} diff --git a/pkg/internal/mock/kms/mock_kms.go b/pkg/internal/mock/kms/mock_kms.go index 4f5b2c7162..2f5d1373ed 100644 --- a/pkg/internal/mock/kms/mock_kms.go +++ b/pkg/internal/mock/kms/mock_kms.go @@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0 package kms import ( - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport" "github.com/hyperledger/aries-framework-go/pkg/doc/did" ) @@ -24,7 +24,7 @@ type CloseableKMS struct { DecryptMessageErr error PackValue []byte PackErr error - UnpackValue *envelope.Envelope + UnpackValue *transport.Envelope UnpackErr error MockDID *did.Doc EncryptionKeyValue []byte diff --git a/pkg/internal/mock/provider/mock_provider.go b/pkg/internal/mock/provider/mock_provider.go index e89169ba65..586e8cfe0f 100644 --- a/pkg/internal/mock/provider/mock_provider.go +++ b/pkg/internal/mock/provider/mock_provider.go @@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0 package provider import ( - "github.com/hyperledger/aries-framework-go/pkg/didcomm/envelope" + "github.com/hyperledger/aries-framework-go/pkg/didcomm/packer" "github.com/hyperledger/aries-framework-go/pkg/kms" "github.com/hyperledger/aries-framework-go/pkg/storage" ) @@ -20,7 +20,8 @@ type Provider struct { InboundEndpointValue string StorageProviderValue storage.Provider TransientStorageProviderValue storage.Provider - PackerValue envelope.Packer + PackerList []packer.Packer + PackerValue packer.Packer } // Service return service @@ -48,7 +49,12 @@ func (p *Provider) TransientStorageProvider() storage.Provider { return p.TransientStorageProviderValue } -// Packer returns the crypter service -func (p *Provider) Packer() envelope.Packer { +// InboundPackers returns the available Packer services +func (p *Provider) InboundPackers() []packer.Packer { + return p.PackerList +} + +// Packer returns the outbound Packer service +func (p *Provider) Packer() packer.Packer { return p.PackerValue }