github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/packer/legacy/anoncrypt/anoncrypt_test.go (about)

     1  /*
     2  Copyright Avast Software. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package anoncryt
     8  
     9  import (
    10  	"crypto/ed25519"
    11  	"crypto/rand"
    12  	"encoding/base64"
    13  	"errors"
    14  	"fmt"
    15  	"io"
    16  	insecurerand "math/rand"
    17  	"testing"
    18  
    19  	"github.com/btcsuite/btcutil/base58"
    20  	"github.com/stretchr/testify/require"
    21  
    22  	"github.com/hyperledger/aries-framework-go/pkg/doc/util/jwkkid"
    23  
    24  	cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto"
    25  	"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto"
    26  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
    27  	vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
    28  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    29  	"github.com/hyperledger/aries-framework-go/pkg/kms/localkms"
    30  	"github.com/hyperledger/aries-framework-go/pkg/kms/webkms"
    31  	mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms"
    32  	mockStorage "github.com/hyperledger/aries-framework-go/pkg/mock/storage"
    33  	"github.com/hyperledger/aries-framework-go/pkg/secretlock"
    34  	"github.com/hyperledger/aries-framework-go/pkg/secretlock/noop"
    35  	"github.com/hyperledger/aries-framework-go/spi/storage"
    36  )
    37  
    38  // failReader wraps a Reader, used for testing different failure checks for encryption tests.
    39  //	count: count the number of Reads called before the failWriter fails.
    40  type failReader struct {
    41  	count int
    42  	data  io.Reader
    43  }
    44  
    45  // newFailReader constructs a failWriter.
    46  func newFailReader(numSuccesses int, reader io.Reader) *failReader {
    47  	fw := failReader{numSuccesses, reader}
    48  	return &fw
    49  }
    50  
    51  // Write will count down a counter, with each call, and fail when the counter is 0
    52  // It calls the wrapped Writer until it's time to fail, after which all calls fail.
    53  // Note: the wrapped Writer can still return errors.
    54  func (fw *failReader) Read(out []byte) (int, error) {
    55  	if fw.count <= 0 {
    56  		// panic(fw)
    57  		return 0, errors.New("mock Reader has failed intentionally")
    58  	}
    59  
    60  	fw.count--
    61  
    62  	return fw.data.Read(out)
    63  }
    64  
    65  type provider struct {
    66  	storeProvider storage.Provider
    67  	kms           kms.KeyManager
    68  	cryptoService cryptoapi.Crypto
    69  }
    70  
    71  func (p *provider) StorageProvider() storage.Provider {
    72  	return p.storeProvider
    73  }
    74  
    75  func (p *provider) Crypto() cryptoapi.Crypto {
    76  	return p.cryptoService
    77  }
    78  
    79  type kmsProvider struct {
    80  	store             kms.Store
    81  	secretLockService secretlock.Service
    82  }
    83  
    84  func (k *kmsProvider) StorageProvider() kms.Store {
    85  	return k.store
    86  }
    87  
    88  func (k *kmsProvider) SecretLock() secretlock.Service {
    89  	return k.secretLockService
    90  }
    91  
    92  func newKMS(t *testing.T) (kms.KeyManager, storage.Store) {
    93  	msp := mockStorage.NewMockStoreProvider()
    94  	p := &provider{storeProvider: msp}
    95  
    96  	store, err := p.StorageProvider().OpenStore("test-kms")
    97  	require.NoError(t, err)
    98  
    99  	kmsStore, err := kms.NewAriesProviderWrapper(msp)
   100  	require.NoError(t, err)
   101  
   102  	kmsProv := &kmsProvider{
   103  		store:             kmsStore,
   104  		secretLockService: &noop.NoLock{},
   105  	}
   106  
   107  	customKMS, err := localkms.New("local-lock://primary/test/", kmsProv)
   108  	require.NoError(t, err)
   109  
   110  	return customKMS, store
   111  }
   112  
   113  func persistKey(t *testing.T, pub, priv string, km kms.KeyManager) error {
   114  	t.Helper()
   115  
   116  	kid, err := jwkkid.CreateKID(base58.Decode(pub), kms.ED25519Type)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	edPriv := ed25519.PrivateKey(base58.Decode(priv))
   122  	if len(edPriv) == 0 {
   123  		return fmt.Errorf("error converting bad public key")
   124  	}
   125  
   126  	k1, _, err := km.ImportPrivateKey(edPriv, kms.ED25519Type, kms.WithKeyID(kid))
   127  	require.NoError(t, err)
   128  	require.Equal(t, kid, k1)
   129  
   130  	return nil
   131  }
   132  
   133  func (p *provider) KMS() kms.KeyManager {
   134  	return p.kms
   135  }
   136  
   137  func newWithKMSAndCrypto(t *testing.T, k kms.KeyManager) *Packer {
   138  	c, err := tinkcrypto.New()
   139  	require.NoError(t, err)
   140  
   141  	return New(&provider{
   142  		kms:           k,
   143  		cryptoService: c,
   144  	})
   145  }
   146  
   147  func (p *provider) VDRegistry() vdrapi.Registry {
   148  	return nil
   149  }
   150  
   151  func createKey(t *testing.T, km kms.KeyManager) []byte {
   152  	_, key, err := km.CreateAndExportPubKeyBytes(kms.ED25519Type)
   153  	require.NoError(t, err)
   154  
   155  	return key
   156  }
   157  
   158  func TestEncodingType(t *testing.T) {
   159  	testKMS, store := newKMS(t)
   160  	require.NotEmpty(t, testKMS)
   161  
   162  	packer := New(&provider{
   163  		storeProvider: mockStorage.NewCustomMockStoreProvider(store),
   164  		kms:           testKMS,
   165  	})
   166  	require.NotEmpty(t, packer)
   167  
   168  	require.Equal(t, encodingType, packer.EncodingType())
   169  }
   170  
   171  func TestEncrypt(t *testing.T) {
   172  	testingKMS, _ := newKMS(t)
   173  
   174  	t.Run("Failure: pack without any recipients", func(t *testing.T) {
   175  		packer := newWithKMSAndCrypto(t, testingKMS)
   176  		require.NotEmpty(t, packer)
   177  
   178  		_, err := packer.Pack("", []byte("Test Message"), []byte{}, [][]byte{})
   179  		require.EqualError(t, err, "empty recipients keys, must have at least one recipient")
   180  	})
   181  
   182  	t.Run("Failure: pack with an invalid recipient key", func(t *testing.T) {
   183  		packer := newWithKMSAndCrypto(t, testingKMS)
   184  		require.NotEmpty(t, packer)
   185  
   186  		badKey := "6ZAQ7QpmR9EqhJdwx1jQsjq6nnpehwVqUbhVxiEiYEV7"
   187  
   188  		_, err := packer.Pack("", []byte("Test Message"), []byte{}, [][]byte{base58.Decode(badKey)})
   189  		require.EqualError(t, err, "pack: failed to build recipients: recipients keys are empty")
   190  	})
   191  
   192  	recipientKey := createKey(t, testingKMS)
   193  
   194  	t.Run("Success: given keys, generate envelope", func(t *testing.T) {
   195  		packer := newWithKMSAndCrypto(t, testingKMS)
   196  		require.NotEmpty(t, packer)
   197  
   198  		enc, e := packer.Pack("", []byte("Pack my box with five dozen liquor jugs!"),
   199  			[]byte{}, [][]byte{recipientKey})
   200  		require.NoError(t, e)
   201  		require.NotEmpty(t, enc)
   202  	})
   203  
   204  	t.Run("Success: with multiple recipients", func(t *testing.T) {
   205  		rec1Key := createKey(t, testingKMS)
   206  		rec2Key := createKey(t, testingKMS)
   207  		rec3Key := createKey(t, testingKMS)
   208  		rec4Key := createKey(t, testingKMS)
   209  
   210  		recipientKeys := [][]byte{rec1Key, rec2Key, rec3Key, rec4Key}
   211  		packer := newWithKMSAndCrypto(t, testingKMS)
   212  		require.NotEmpty(t, packer)
   213  
   214  		enc, err := packer.Pack("", []byte("God! a red nugget! A fat egg under a dog!"), []byte{}, recipientKeys)
   215  		require.NoError(t, err)
   216  		require.NotEmpty(t, enc)
   217  	})
   218  
   219  	t.Run("Success: pack empty payload using deterministic random source, verify result", func(t *testing.T) {
   220  		senderPub := "4SPtrDH1ZH8Zsh6upbUG3TbgXjYbW1CEBRnNY6iMudX9"
   221  		senderPriv := "5MF9crszXCvzh9tWUWQwAuydh6tY2J5ErsaebwRzTsbNXx74mfaJXaKq7oTkoN4VMc2RtKktjMpPoU7vti9UnrdZ"
   222  
   223  		recipientPub := "CP1eVoFxCguQe1ttDbS3L35ZiJckZ8PZykX1SCDNgEYZ"
   224  		recipientPriv := "5aFcdEMws6ZUL7tWYrJ6DsZvY2GHZYui1jLcYquGr8uHfmyHCs96QU3nRUarH1gVYnMU2i4uUPV5STh2mX7EHpNu"
   225  
   226  		kms2, _ := newKMS(t)
   227  		require.NoError(t, persistKey(t, senderPub, senderPriv, kms2))
   228  		require.NoError(t, persistKey(t, recipientPub, recipientPriv, kms2))
   229  
   230  		source := insecurerand.NewSource(5937493) // constant fixed to ensure constant output
   231  		constRand := insecurerand.New(source)     //nolint:gosec
   232  
   233  		packer := newWithKMSAndCrypto(t, kms2)
   234  		require.NotEmpty(t, packer)
   235  		packer.randSource = constRand
   236  		enc, err := packer.Pack("", nil, []byte{}, [][]byte{base58.Decode(recipientPub)})
   237  		require.NoError(t, err)
   238  
   239  		test := "eyJwcm90ZWN0ZWQiOiJleUpsYm1NaU9pSmphR0ZqYUdFeU1IQnZiSGt4TXpBMVgybGxkR1lpTENKMGVYQWlPaUpLVjAwdk1TNHdJaXdpWVd4bklqb2lRVzV2Ym1OeWVYQjBJaXdpY21WamFYQnBaVzUwY3lJNlczc2laVzVqY25sd2RHVmtYMnRsZVNJNklsWXRUMXBaUXpjdFNucEpVVFZGYUhCYWVIb3dTV0ZDTXkxWlZFNXhUbkZ5Y0RaRmVFVXRlbDlNUjFaaldVOVRPRkpaVkZGYVYwcHllVXRRUkU5bU5FNWtTRTVRV0VsQ1JXMUxVbEZoVURscGVGcGlNbUp0VUdnemJuZHlTR0l6VkZFelNWbExZbnBvT0ROdlBTSXNJbWhsWVdSbGNpSTZleUpyYVdRaU9pSkRVREZsVm05R2VFTm5kVkZsTVhSMFJHSlRNMHd6TlZwcFNtTnJXamhRV25scldERlRRMFJPWjBWWldpSjlmVjE5IiwiaXYiOiJpS2RxcUVqc05LaXluLWhrIiwidGFnIjoiR3FVZHVhamVfSHNLS3c3QXJ3dnQ0Zz09In0=" // nolint: lll
   240  
   241  		require.Equal(t, test, base64.URLEncoding.EncodeToString(enc))
   242  	})
   243  
   244  	t.Run("Success: pack payload using deterministic random source for multiple recipients, verify result", func(t *testing.T) { // nolint: lll
   245  		senderPub := "9NKZ9pHL9YVS7BzqJsz3e9uVvk44rJodKfLKbq4hmeUw"
   246  		senderPriv := "2VZLugb22G3iovUvGrecKj3VHFUNeCetkApeB4Fn4zkgBqYaMSFTW2nvF395voJ76vHkfnUXH2qvJoJnFydRoQBR"
   247  		senderKMS, _ := newKMS(t)
   248  		require.NoError(t, persistKey(t, senderPub, senderPriv, senderKMS))
   249  
   250  		rec1Pub := base58.Decode("DDk4ac2ZA19P8qXjk8XaCY9Fx7WwAmCtELkxeDNqS6Vs")
   251  		rec2Pub := base58.Decode("G79vtfWgtBG5J7R2QaBQpZfPUQaAab1QJWedWH7q3VK1")
   252  		rec3Pub := base58.Decode("7snUUwA23DVBmafz9ibmBgwFFCUwzgTzmvcJGepuzjmK")
   253  		rec4Pub := base58.Decode("GSRovbnQy8HRjVjvzGbbfN387EX9NFfLj89C1ScXYfrF")
   254  
   255  		source := insecurerand.NewSource(6572692) // constant fixed to ensure constant output
   256  		constRand := insecurerand.New(source)     //nolint:gosec
   257  
   258  		packer := newWithKMSAndCrypto(t, senderKMS)
   259  		require.NotEmpty(t, packer)
   260  		packer.randSource = constRand
   261  		enc, err := packer.Pack(
   262  			"",
   263  			[]byte("Sphinx of black quartz, judge my vow!"),
   264  			[]byte{},
   265  			[][]byte{rec1Pub, rec2Pub, rec3Pub, rec4Pub})
   266  		require.NoError(t, err)
   267  
   268  		test := "eyJwcm90ZWN0ZWQiOiJleUpsYm1NaU9pSmphR0ZqYUdFeU1IQnZiSGt4TXpBMVgybGxkR1lpTENKMGVYQWlPaUpLVjAwdk1TNHdJaXdpWVd4bklqb2lRVzV2Ym1OeWVYQjBJaXdpY21WamFYQnBaVzUwY3lJNlczc2laVzVqY25sd2RHVmtYMnRsZVNJNklubFdTWEJ0VTFaSWEyVm9hVXRRWm1GQmRVNW1OMUpyT1c5cmJqTk9WMHhCWjBRM1NVTkNVVVpZVkVnMmN6WXRUbFpRWWtwRE1GQk9OR1ozTkZkZmVWSXpPVVpJTlU1QlJVNW9OMlpOWTBacFdYSmZNbGhCZVhwb1FubG1lRkZ6ZUhCSVh6ZEtkR00yTlVoblBTSXNJbWhsWVdSbGNpSTZleUpyYVdRaU9pSkVSR3MwWVdNeVdrRXhPVkE0Y1ZocWF6aFlZVU5aT1VaNE4xZDNRVzFEZEVWTWEzaGxSRTV4VXpaV2N5SjlmU3g3SW1WdVkzSjVjSFJsWkY5clpYa2lPaUpuZW5ScFpHeFpjWGwwUlRSb2RHczFSbTR3V21KSlRFUnJZbFZZV210WVJqTkZOUzFMTkY5dk1sWlNhREZUZUhkb2JEZHNNbWxTU20xVE1ISmlNREpxWTBaU2QwUkNkMmxxUzFWS1JYbDFTek0yYTBneldXTnRRbVl5UzFGdFVXbE1lR05KUlRoRGEzVkdRVDBpTENKb1pXRmtaWElpT25zaWEybGtJam9pUnpjNWRuUm1WMmQwUWtjMVNqZFNNbEZoUWxGd1dtWlFWVkZoUVdGaU1WRktWMlZrVjBnM2NUTldTekVpZlgwc2V5SmxibU55ZVhCMFpXUmZhMlY1SWpvaVdFdEZWMkZ3YUVzelFTMXBiRVZLTFVwNlVtdFhaRTAwZUVKcFRtTXRXa1ZvVlZwNmRVdFZSVlI2WDFSWlJqRXdSWFZNUXpoZmNHUlVUMUV6VlROSmExVmhMV0ZGUkhGalluZFpSM05VVEVkQlVWVXdZVWh4YlhWbVNHUXRUamxRVTJaVVFuVklWRTVuTFRROUlpd2lhR1ZoWkdWeUlqcDdJbXRwWkNJNklqZHpibFZWZDBFeU0wUldRbTFoWm5vNWFXSnRRbWQzUmtaRFZYZDZaMVI2YlhaalNrZGxjSFY2YW0xTEluMTlMSHNpWlc1amNubHdkR1ZrWDJ0bGVTSTZJblZwTFhFMGJtRmtRVzF5VDFSZmVteE5OWFZHWWpCT1kzRTBaV3h5YVhkQ1gwUk5kRmhsV0U5cGVIazFRblZoYW01S2RHdzVja2RvZDJONlltWmZjbEZ0WTJadUxVMUhXR3BFYlROb1NYUkVjWGQ0YmpoWmVEWnROVUU1T1V4NVdtcHBaemhVTW1OeFoycHJQU0lzSW1obFlXUmxjaUk2ZXlKcmFXUWlPaUpIVTFKdmRtSnVVWGs0U0ZKcVZtcDJla2RpWW1aT016ZzNSVmc1VGtabVRHbzRPVU14VTJOWVdXWnlSaUo5ZlYxOSIsIml2IjoiWW91Q1YtZ2xmUWhQYWw3NSIsImNpcGhlcnRleHQiOiJfY0VDazA0N2NsOGN3RWlLNVJ2S2x2TkQyY05aNW02QU1vb3ZSODJwaTBIS28xZ2ZWQT09IiwidGFnIjoiNmpZR2xreEdaRXp0ME5yQ1lkcFVLUT09In0=" // nolint: lll
   269  
   270  		require.Equal(t, test, base64.URLEncoding.EncodeToString(enc))
   271  	})
   272  }
   273  
   274  func TestEncryptComponents(t *testing.T) {
   275  	senderPub := "9NKZ9pHL9YVS7BzqJsz3e9uVvk44rJodKfLKbq4hmeUw"
   276  	senderPriv := "2VZLugb22G3iovUvGrecKj3VHFUNeCetkApeB4Fn4zkgBqYaMSFTW2nvF395voJ76vHkfnUXH2qvJoJnFydRoQBR"
   277  	recPub := "DDk4ac2ZA19P8qXjk8XaCY9Fx7WwAmCtELkxeDNqS6Vs"
   278  
   279  	testKMS, _ := newKMS(t)
   280  	require.NoError(t, persistKey(t, senderPub, senderPriv, testKMS))
   281  
   282  	packer := newWithKMSAndCrypto(t, testKMS)
   283  
   284  	t.Run("Failure: content encryption nonce generation fails", func(t *testing.T) {
   285  		failRand := newFailReader(0, rand.Reader)
   286  		packer.randSource = failRand
   287  
   288  		_, err := packer.Pack(
   289  			"",
   290  			[]byte("Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   291  			[]byte{}, [][]byte{base58.Decode(recPub)})
   292  		require.EqualError(t, err, "pack: failed to generate random nonce: mock Reader has failed intentionally")
   293  	})
   294  
   295  	t.Run("Failure: CEK generation fails", func(t *testing.T) {
   296  		failRand := newFailReader(1, rand.Reader)
   297  		packer.randSource = failRand
   298  
   299  		_, err := packer.Pack(
   300  			"",
   301  			[]byte("Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   302  			[]byte{}, [][]byte{base58.Decode(recPub)})
   303  		require.EqualError(t, err, "pack: failed to generate cek: mock Reader has failed intentionally")
   304  	})
   305  
   306  	t.Run("Failure: recipient nonce generation fails", func(t *testing.T) {
   307  		failRand := newFailReader(2, rand.Reader)
   308  		packer.randSource = failRand
   309  
   310  		_, err := packer.Pack(
   311  			"", []byte(
   312  				"Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   313  			[]byte{}, [][]byte{base58.Decode(recPub)})
   314  		require.EqualError(t, err, "pack: failed to build recipients: recipients keys are empty")
   315  	})
   316  
   317  	t.Run("Success: 3 reads necessary for pack", func(t *testing.T) {
   318  		failRand := newFailReader(3, rand.Reader)
   319  		packer.randSource = failRand
   320  
   321  		_, err := packer.Pack(
   322  			"",
   323  			[]byte("Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   324  			[]byte{}, [][]byte{base58.Decode(recPub)})
   325  		require.NoError(t, err)
   326  	})
   327  }
   328  
   329  func TestDecrypt(t *testing.T) {
   330  	testingKMS, _ := newKMS(t)
   331  
   332  	_, recKey, err := testingKMS.CreateAndExportPubKeyBytes(kms.ED25519Type)
   333  	require.NoError(t, err)
   334  
   335  	t.Run("Success: pack then unpack, same packer", func(t *testing.T) {
   336  		packer := newWithKMSAndCrypto(t, testingKMS)
   337  		msgIn := []byte("Junky qoph-flags vext crwd zimb.")
   338  
   339  		var (
   340  			enc []byte
   341  			env *transport.Envelope
   342  		)
   343  
   344  		enc, err = packer.Pack("", msgIn, []byte{}, [][]byte{recKey})
   345  		require.NoError(t, err)
   346  		env, err = packer.Unpack(enc)
   347  		require.NoError(t, err)
   348  
   349  		require.ElementsMatch(t, msgIn, env.Message)
   350  		require.Equal(t, recKey, env.ToKey)
   351  	})
   352  
   353  	t.Run("Success: pack and unpack, different packers, including fail recipient who wasn't sent the message", func(t *testing.T) { // nolint: lll
   354  		rec1KMS, _ := newKMS(t)
   355  		rec1Key := createKey(t, rec1KMS)
   356  
   357  		rec2KMS, _ := newKMS(t)
   358  		rec2Key := createKey(t, rec2KMS)
   359  
   360  		rec3KMS, _ := newKMS(t)
   361  		rec3Key := createKey(t, rec3KMS)
   362  
   363  		require.NoError(t, err)
   364  
   365  		sendPacker := newWithKMSAndCrypto(t, testingKMS)
   366  		rec2Packer := newWithKMSAndCrypto(t, rec2KMS)
   367  
   368  		msgIn := []byte("Junky qoph-flags vext crwd zimb.")
   369  
   370  		var (
   371  			enc []byte
   372  			env *transport.Envelope
   373  		)
   374  
   375  		enc, err = sendPacker.Pack("", msgIn, []byte{}, [][]byte{rec1Key, rec2Key, rec3Key})
   376  		require.NoError(t, err)
   377  		env, err = rec2Packer.Unpack(enc)
   378  		require.NoError(t, err)
   379  		require.ElementsMatch(t, msgIn, env.Message)
   380  		require.Equal(t, rec2Key, env.ToKey)
   381  
   382  		emptyKMS, _ := newKMS(t)
   383  		rec4Packer := newWithKMSAndCrypto(t, emptyKMS)
   384  
   385  		_, err = rec4Packer.Unpack(enc)
   386  		require.NotNil(t, err)
   387  		require.Contains(t, err.Error(), "no key accessible")
   388  	})
   389  
   390  	t.Run("Test unpacking envelope", func(t *testing.T) {
   391  		env := `{"protected":"eyJlbmMiOiJjaGFjaGEyMHBvbHkxMzA1X2lldGYiLCJ0eXAiOiJKV00vMS4wIiwiYWxnIjoiQW5vbmNyeXB0IiwicmVjaXBpZW50cyI6W3siZW5jcnlwdGVkX2tleSI6IjN3eFg1UUYybmVuYzUwUlRmSG10TmpQcVdieVhsOURseXhvRHlOYWx2a3U4MUhQdDVGanNrS3JpR1A1dE9FaHhYNmNyT3E2bjcxZXJRMU5zdWhGcm43VXVTUll3anRucmt1bmFaMjNaOWxZPSIsImhlYWRlciI6eyJraWQiOiI0U1B0ckRIMVpIOFpzaDZ1cGJVRzNUYmdYalliVzFDRUJSbk5ZNmlNdWRYOSJ9fV19","iv":"_Bp1NvfmNZ5Qe3iH","ciphertext":"eyETwK9I4NNPyitd","tag":"M8tMmORU7k11SvB_vStMpA=="}` // nolint: lll
   392  		msg := "Hello World!"
   393  
   394  		recPub := "4SPtrDH1ZH8Zsh6upbUG3TbgXjYbW1CEBRnNY6iMudX9"
   395  		recPriv := "5MF9crszXCvzh9tWUWQwAuydh6tY2J5ErsaebwRzTsbNXx74mfaJXaKq7oTkoN4VMc2RtKktjMpPoU7vti9UnrdZ"
   396  
   397  		recKMS, _ := newKMS(t)
   398  		require.NoError(t, persistKey(t, recPub, recPriv, recKMS))
   399  
   400  		recPacker := newWithKMSAndCrypto(t, recKMS)
   401  
   402  		var envOut *transport.Envelope
   403  		envOut, err = recPacker.Unpack([]byte(env))
   404  		require.NoError(t, err)
   405  		require.ElementsMatch(t, []byte(msg), envOut.Message)
   406  		require.Empty(t, envOut.FromKey)
   407  		require.NotEmpty(t, envOut.ToKey)
   408  		require.Equal(t, recPub, base58.Encode(envOut.ToKey))
   409  	})
   410  
   411  	t.Run("Test unpacking envelope with multiple recipients", func(t *testing.T) {
   412  		env := `{"protected":"eyJlbmMiOiJjaGFjaGEyMHBvbHkxMzA1X2lldGYiLCJ0eXAiOiJKV00vMS4wIiwiYWxnIjoiQW5vbmNyeXB0IiwicmVjaXBpZW50cyI6W3siZW5jcnlwdGVkX2tleSI6ImZDMzgxN05OUWVCSTBtODNGOVlwbXdCWE5VNlRkX2V5WWdfSHI1WW41Z1ZlclliZmlHUXFTdGlZVmRBSUc4RlgwclJKd1c3SVBtYUcyTDY3dmQwSXZwWFowQ2sydjlfSldDbjNjSWkwa3Y0PSIsImhlYWRlciI6eyJraWQiOiJGN21OdEYyZnJMdVJ1MmNNRWpYQm5XZFljVFpBWE5QOWpFa3ByWHhpYVppMSJ9fSx7ImVuY3J5cHRlZF9rZXkiOiJKTjdaN3ZhOHc0T05iQkVnczI1bTdYbVFRM2NqTGo0WkZrRzBSOVc5SndVX1RsV3g5Q1pvb3lrZDZ4SWZBZk1tNVJjTjZIaGZKdEg5enpiVlVuVTlObF8wck9MVm96WEVIUGF1R2Vkc25uOD0iLCJoZWFkZXIiOnsia2lkIjoiQVE5bkh0TG5tdUc4MXB5NjRZRzVnZUYydmQ1aFFDS0hpNU1ycVExTFlDWEUifX1dfQ==","iv":"s5LdqRVlm23pxhxq","ciphertext":"HiMHFMlk6nwg7F6Q","tag":"tqPiHBpA2h4TeZFB9wNnyw=="}` // nolint: lll
   413  		msg := "Hello World!"
   414  
   415  		rec1Pub := "F7mNtF2frLuRu2cMEjXBnWdYcTZAXNP9jEkprXxiaZi1"
   416  		rec1Priv := "2nYsWTQ1ZguQ7G2HYfMWjMNqWagBQfaKB9GLbsFk7Z7tKVBEr2arwpVKDwgLUbaxguUzQuf7o67aWKzgtHmKaypM"
   417  
   418  		rec2Pub := "AQ9nHtLnmuG81py64YG5geF2vd5hQCKHi5MrqQ1LYCXE"
   419  		rec2Priv := "2YbSVZzSVaim41bWDdsBzamrhXrPFKKEpzXZRmgDuoFJco5VQELRSj1oWFR9aRdaufsdUyw8sozTtZuX8Mzsqboz"
   420  
   421  		rec1KMS, _ := newKMS(t)
   422  		require.NoError(t, persistKey(t, rec1Pub, rec1Priv, rec1KMS))
   423  
   424  		rec2KMS, _ := newKMS(t)
   425  		require.NoError(t, persistKey(t, rec2Pub, rec2Priv, rec2KMS))
   426  
   427  		rec1Packer := newWithKMSAndCrypto(t, rec1KMS)
   428  		rec2Packer := newWithKMSAndCrypto(t, rec2KMS)
   429  
   430  		var envOut *transport.Envelope
   431  		envOut, err = rec1Packer.Unpack([]byte(env))
   432  		require.NoError(t, err)
   433  		require.ElementsMatch(t, []byte(msg), envOut.Message)
   434  		require.Empty(t, envOut.FromKey)
   435  		require.NotEmpty(t, envOut.ToKey)
   436  		require.Equal(t, rec1Pub, base58.Encode(envOut.ToKey))
   437  
   438  		envOut, err = rec2Packer.Unpack([]byte(env))
   439  		require.NoError(t, err)
   440  		require.ElementsMatch(t, []byte(msg), envOut.Message)
   441  		require.Empty(t, envOut.FromKey)
   442  		require.NotEmpty(t, envOut.ToKey)
   443  		require.Equal(t, rec2Pub, base58.Encode(envOut.ToKey))
   444  	})
   445  
   446  	t.Run("Test unpacking envelope with invalid recipient", func(t *testing.T) {
   447  		env := `{"protected":"eyJlbmMiOiJjaGFjaGEyMHBvbHkxMzA1X2lldGYiLCJ0eXAiOiJKV00vMS4wIiwiYWxnIjoiQW5vbmNyeXB0IiwicmVjaXBpZW50cyI6W3siZW5jcnlwdGVkX2tleSI6IkgwY09vVk5pT3FybTZPUFR1YzJ4cnBYaTRrTm1kSnhZV3haOE1iRWVOU0pYMENkR3EzaWRpQmtibjVYSDBTWjBtNEpfa0NYUFJaYVNqYjhLMVB3X0s5NnYzTFBjVzVPWjhWVkNKYkhHRUU0PSIsImhlYWRlciI6eyJraWQiOiJGN21OdEYyZnJMdVJ1MmNNRWpYQm5XZFljVFpBWE5QOWpFa3ByWHhpYVppMSJ9fV19","iv":"6cVlG23Fhy9oXB2h","ciphertext":"8vMl1QjgbCHreGCe","tag":"-VYChuk4kmnTk8Kz0Kz3Pg=="}` // nolint: lll
   448  
   449  		recPub := "A3KnccxQu27yWQrSLwA2YFbfoSs4CHo3q6LjvhmpKz9h"
   450  		recPriv := "49Y63zwonNoj2jEhMYE22TDwQCn7RLKMqNeSkSoBBucbAWceJuXXNCACXfpbXD7PHKM13SWaySyDukEakPVn5sWs"
   451  
   452  		recKMS, _ := newKMS(t)
   453  		require.NoError(t, persistKey(t, recPub, recPriv, recKMS))
   454  
   455  		recPacker := newWithKMSAndCrypto(t, recKMS)
   456  
   457  		_, err = recPacker.Unpack([]byte(env))
   458  		require.NotNil(t, err)
   459  		require.Contains(t, err.Error(), "no key accessible")
   460  	})
   461  }
   462  
   463  func unpackComponentFailureTest(t *testing.T, protectedHeader, msg, recKeyPub, recKeyPriv, errString string) {
   464  	t.Helper()
   465  
   466  	fullMessage := `{"protected": "` + base64.URLEncoding.EncodeToString([]byte(protectedHeader)) + "\", " + msg
   467  
   468  	w, _ := newKMS(t)
   469  
   470  	err := persistKey(t, recKeyPub, recKeyPriv, w)
   471  
   472  	if errString == "createKID: empty key" {
   473  		require.EqualError(t, err, errString)
   474  		return
   475  	}
   476  
   477  	require.NoError(t, err)
   478  
   479  	recPacker := newWithKMSAndCrypto(t, w)
   480  	_, err = recPacker.Unpack([]byte(fullMessage))
   481  	require.NotNil(t, err)
   482  	require.Contains(t, err.Error(), errString)
   483  }
   484  
   485  func TestUnpackComponents(t *testing.T) {
   486  	recKeyPub := "F7mNtF2frLuRu2cMEjXBnWdYcTZAXNP9jEkprXxiaZi1"
   487  	recKeyPriv := "2nYsWTQ1ZguQ7G2HYfMWjMNqWagBQfaKB9GLbsFk7Z7tKVBEr2arwpVKDwgLUbaxguUzQuf7o67aWKzgtHmKaypM"
   488  
   489  	t.Run("Fail: non-JSON envelope", func(t *testing.T) {
   490  		msg := `ed": "eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEu"}`
   491  
   492  		w, _ := newKMS(t)
   493  		require.NoError(t, persistKey(t, recKeyPub, recKeyPriv, w))
   494  
   495  		recPacker := newWithKMSAndCrypto(t, w)
   496  
   497  		_, err := recPacker.Unpack([]byte(msg))
   498  		require.EqualError(t, err, "invalid character 'e' looking for beginning of value")
   499  	})
   500  
   501  	t.Run("Fail: non-base64 protected header", func(t *testing.T) {
   502  		msg := `{"protected":"&**^(&^%","iv":"6cVlG23Fhy9oXB2h","ciphertext":"8vMl1QjgbCHreGCe","tag":"-VYChuk4kmnTk8Kz0Kz3Pg=="}` // nolint: lll
   503  
   504  		w, _ := newKMS(t)
   505  		require.NoError(t, persistKey(t, recKeyPub, recKeyPriv, w))
   506  
   507  		recPacker := newWithKMSAndCrypto(t, w)
   508  
   509  		_, err := recPacker.Unpack([]byte(msg))
   510  		require.EqualError(t, err, "illegal base64 data at input byte 0")
   511  	})
   512  
   513  	t.Run("Fail: header not json", func(t *testing.T) {
   514  		unpackComponentFailureTest(t,
   515  			`}eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMC`,
   516  			`"not important":[]}`,
   517  			recKeyPub, recKeyPriv,
   518  			"invalid character '}' looking for beginning of value")
   519  	})
   520  
   521  	t.Run("Fail: bad 'typ' field", func(t *testing.T) {
   522  		unpackComponentFailureTest(t,
   523  			`{"enc":"chacha20poly1305_ietf","typ":"JSON","alg":"Anoncrypt","recipients":[{"encrypted_key":"H0cOoVNiOqrm6OPTuc2xrpXi4kNmdJxYWxZ8MbEeNSJX0CdGq3idiBkbn5XH0SZ0m4J_kCXPRZaSjb8K1Pw_K96v3LPcW5OZ8VVCJbHGEE4=","header":{"kid":"F7mNtF2frLuRu2cMEjXBnWdYcTZAXNP9jEkprXxiaZi1"}}]}`, // nolint: lll
   524  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                 // nolint: lll
   525  			recKeyPub, recKeyPriv,
   526  			"message type JSON not supported")
   527  	})
   528  
   529  	t.Run("Fail: authcrypt not supported", func(t *testing.T) {
   530  		unpackComponentFailureTest(t,
   531  			`{"enc":"chacha20poly1305_ietf","typ":"JWM/1.0","alg":"Authcrypt","recipients":[{"encrypted_key":"H0cOoVNiOqrm6OPTuc2xrpXi4kNmdJxYWxZ8MbEeNSJX0CdGq3idiBkbn5XH0SZ0m4J_kCXPRZaSjb8K1Pw_K96v3LPcW5OZ8VVCJbHGEE4=","header":{"kid":"F7mNtF2frLuRu2cMEjXBnWdYcTZAXNP9jEkprXxiaZi1"}}]}`, // nolint: lll
   532  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                    // nolint: lll
   533  			recKeyPub, recKeyPriv,
   534  			"message format Authcrypt not supported")
   535  	})
   536  
   537  	t.Run("Fail: no recipients in header", func(t *testing.T) {
   538  		unpackComponentFailureTest(t,
   539  			`{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Anoncrypt", "recipients": []}`,
   540  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll
   541  			recKeyPub, recKeyPriv,
   542  			"no key accessible")
   543  	})
   544  
   545  	t.Run("Fail: invalid public key", func(t *testing.T) {
   546  		recPub := "6ZAQ7QpmR9EqhJdwx1jQsjq6nnpehwVqUbhVxiEiYEV7" // invalid key, won't convert
   547  
   548  		unpackComponentFailureTest(t,
   549  			`{"enc":"chacha20poly1305_ietf","typ":"JWM/1.0","alg":"Anoncrypt","recipients":[{"encrypted_key":"H0cOoVNiOqrm6OPTuc2xrpXi4kNmdJxYWxZ8MbEeNSJX0CdGq3idiBkbn5XH0SZ0m4J_kCXPRZaSjb8K1Pw_K96v3LPcW5OZ8VVCJbHGEE4=","header":{"kid":"6ZAQ7QpmR9EqhJdwx1jQsjq6nnpehwVqUbhVxiEiYEV7"}}]}`, // nolint: lll
   550  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                    // nolint: lll
   551  			recPub, recKeyPriv,
   552  			"sealOpen: failed to convert pub Ed25519 to X25519 key: error converting public key")
   553  	})
   554  
   555  	t.Run("Fail: invalid public key", func(t *testing.T) {
   556  		recPub := "57N4aoQKaxUGNeEn3ETnTKgeD1L5Wm3U3Vb8qi3hupLn" // mismatched keypair, won't decrypt
   557  
   558  		unpackComponentFailureTest(t,
   559  			`{"enc":"chacha20poly1305_ietf","typ":"JWM/1.0","alg":"Anoncrypt","recipients":[{"encrypted_key":"H0cOoVNiOqrm6OPTuc2xrpXi4kNmdJxYWxZ8MbEeNSJX0CdGq3idiBkbn5XH0SZ0m4J_kCXPRZaSjb8K1Pw_K96v3LPcW5OZ8VVCJbHGEE4=","header":{"kid":"57N4aoQKaxUGNeEn3ETnTKgeD1L5Wm3U3Vb8qi3hupLn"}}]}`, // nolint: lll
   560  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                    // nolint: lll
   561  			recPub, recKeyPriv,
   562  			"failed to unpack")
   563  	})
   564  
   565  	t.Run("Encrypted CEK is invalid base64 data", func(t *testing.T) {
   566  		unpackComponentFailureTest(t,
   567  			`{"enc":"chacha20poly1305_ietf","typ":"JWM/1.0","alg":"Anoncrypt","recipients":[{"encrypted_key":"-","header":{"kid":"F7mNtF2frLuRu2cMEjXBnWdYcTZAXNP9jEkprXxiaZi1"}}]}`,                                                                         // nolint: lll
   568  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll
   569  			recKeyPub, recKeyPriv,
   570  			"illegal base64 data at input byte 0")
   571  	})
   572  
   573  	t.Run("Bad encrypted key cannot be decrypted", func(t *testing.T) {
   574  		unpackComponentFailureTest(t,
   575  			`{"enc":"chacha20poly1305_ietf","typ":"JWM/1.0","alg":"Anoncrypt","recipients":[{"encrypted_key":"H0cOoVNi","header":{"kid":"F7mNtF2frLuRu2cMEjXBnWdYcTZAXNP9jEkprXxiaZi1"}}]}`,                                                                  // nolint: lll
   576  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll
   577  			recKeyPub, recKeyPriv,
   578  			"failed to decrypt CEK")
   579  	})
   580  
   581  	// valid protected header for envelope being used
   582  	prot := `{"enc":"chacha20poly1305_ietf","typ":"JWM/1.0","alg":"Anoncrypt","recipients":[{"encrypted_key":"H0cOoVNiOqrm6OPTuc2xrpXi4kNmdJxYWxZ8MbEeNSJX0CdGq3idiBkbn5XH0SZ0m4J_kCXPRZaSjb8K1Pw_K96v3LPcW5OZ8VVCJbHGEE4=","header":{"kid":"F7mNtF2frLuRu2cMEjXBnWdYcTZAXNP9jEkprXxiaZi1"}}]}` // nolint: lll
   583  
   584  	t.Run("Ciphertext nonce not valid b64 data", func(t *testing.T) {
   585  		unpackComponentFailureTest(t,
   586  			prot,
   587  			`"iv":"!!!","ciphertext":"8vMl1QjgbCHreGCe","tag":"-VYChuk4kmnTk8Kz0Kz3Pg=="}`,
   588  			recKeyPub, recKeyPriv,
   589  			"illegal base64 data at input byte 0")
   590  	})
   591  
   592  	t.Run("Ciphertext not valid b64 data", func(t *testing.T) {
   593  		unpackComponentFailureTest(t,
   594  			prot, `"iv":"6cVlG23Fhy9oXB2h","ciphertext":"-","tag":"-VYChuk4kmnTk8Kz0Kz3Pg=="}`,
   595  			recKeyPub, recKeyPriv,
   596  			"illegal base64 data at input byte 0")
   597  	})
   598  
   599  	t.Run("Ciphertext tag not valid b64 data", func(t *testing.T) {
   600  		unpackComponentFailureTest(t,
   601  			prot,
   602  			`"iv":"6cVlG23Fhy9oXB2h","ciphertext":"8vMl1QjgbCHreGCe","tag":"-"}`,
   603  			recKeyPub, recKeyPriv,
   604  			"illegal base64 data at input byte 0")
   605  	})
   606  
   607  	badKeyPriv := "badkeyabcdefghijklmnopqrstuvwxyzbadkeyabcdefghijklmnopqrstuvwxyz"
   608  	badKeyPub := "badkeyabcdefghijklmnopqrstuvwxyz"
   609  
   610  	t.Run("Recipient Key not valid key", func(t *testing.T) {
   611  		unpackComponentFailureTest(t,
   612  			prot,
   613  			`"iv":"6cVlG23Fhy9oXB2h","ciphertext":"8vMl1QjgbCHreGCe","tag":"-VYChuk4kmnTk8Kz0Kz3Pg=="}`,
   614  			badKeyPub, badKeyPriv,
   615  			"createKID: empty key")
   616  	})
   617  }
   618  
   619  func Test_getCEK(t *testing.T) {
   620  	k := mockkms.KeyManager{
   621  		GetKeyValue: nil,
   622  		GetKeyErr:   fmt.Errorf("mock error"),
   623  	}
   624  
   625  	recs := []recipient{
   626  		{
   627  			EncryptedKey: "",
   628  			Header: recipientHeader{
   629  				KID: "BADKEY",
   630  			},
   631  		},
   632  	}
   633  
   634  	_, err := getCEK(recs, &k)
   635  	require.EqualError(t, err, "getCEK: no key accessible none of the recipient keys were found in kms: "+
   636  		"[mock error]")
   637  }
   638  
   639  func Test_newCryptoBox(t *testing.T) {
   640  	_, err := newCryptoBox(&mockkms.KeyManager{})
   641  	require.EqualError(t, err, "cannot use parameter argument as KMS")
   642  
   643  	_, err = newCryptoBox(&webkms.RemoteKMS{})
   644  	require.NoError(t, err)
   645  }