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

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package authcrypt
     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  	secretLock    secretlock.Service
    69  	cryptoService cryptoapi.Crypto
    70  }
    71  
    72  func (p *provider) StorageProvider() storage.Provider {
    73  	return p.storeProvider
    74  }
    75  
    76  func (p *provider) Crypto() cryptoapi.Crypto {
    77  	return p.cryptoService
    78  }
    79  
    80  type kmsProvider struct {
    81  	store             kms.Store
    82  	secretLockService secretlock.Service
    83  }
    84  
    85  func (k *kmsProvider) StorageProvider() kms.Store {
    86  	return k.store
    87  }
    88  
    89  func (k *kmsProvider) SecretLock() secretlock.Service {
    90  	return k.secretLockService
    91  }
    92  
    93  func newKMS(t *testing.T) (kms.KeyManager, storage.Store) {
    94  	msp := mockStorage.NewMockStoreProvider()
    95  	p := &provider{storeProvider: msp, secretLock: &noop.NoLock{}}
    96  
    97  	store, err := p.StorageProvider().OpenStore("test-kms")
    98  	require.NoError(t, err)
    99  
   100  	kmsStore, err := kms.NewAriesProviderWrapper(msp)
   101  	require.NoError(t, err)
   102  
   103  	kmsProv := &kmsProvider{
   104  		store:             kmsStore,
   105  		secretLockService: &noop.NoLock{},
   106  	}
   107  
   108  	customKMS, err := localkms.New("local-lock://primary/test/", kmsProv)
   109  	require.NoError(t, err)
   110  
   111  	return customKMS, store
   112  }
   113  
   114  func persistKey(t *testing.T, pub, priv string, km kms.KeyManager) error {
   115  	t.Helper()
   116  
   117  	kid, err := jwkkid.CreateKID(base58.Decode(pub), kms.ED25519Type)
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	edPriv := ed25519.PrivateKey(base58.Decode(priv))
   123  	if len(edPriv) == 0 {
   124  		return fmt.Errorf("error converting bad public key")
   125  	}
   126  
   127  	k1, _, err := km.ImportPrivateKey(edPriv, kms.ED25519Type, kms.WithKeyID(kid))
   128  	require.NoError(t, err)
   129  	require.Equal(t, kid, k1)
   130  
   131  	return nil
   132  }
   133  
   134  func (p *provider) KMS() kms.KeyManager {
   135  	return p.kms
   136  }
   137  
   138  func newWithKMSAndCrypto(t *testing.T, k kms.KeyManager) *Packer {
   139  	c, err := tinkcrypto.New()
   140  	require.NoError(t, err)
   141  
   142  	return New(&provider{
   143  		kms:           k,
   144  		cryptoService: c,
   145  	})
   146  }
   147  
   148  func (p *provider) SecretLock() secretlock.Service {
   149  	return p.secretLock
   150  }
   151  
   152  func (p *provider) VDRegistry() vdrapi.Registry {
   153  	return nil
   154  }
   155  
   156  func createKey(t *testing.T, km kms.KeyManager) []byte {
   157  	_, key, err := km.CreateAndExportPubKeyBytes(kms.ED25519Type)
   158  	require.NoError(t, err)
   159  
   160  	return key
   161  }
   162  
   163  func TestEncodingType(t *testing.T) {
   164  	testKMS, store := newKMS(t)
   165  	require.NotEmpty(t, testKMS)
   166  
   167  	packer := New(&provider{
   168  		storeProvider: mockStorage.NewCustomMockStoreProvider(store),
   169  		kms:           testKMS,
   170  	})
   171  	require.NotEmpty(t, packer)
   172  
   173  	require.Equal(t, encodingType, packer.EncodingType())
   174  }
   175  
   176  func TestEncrypt(t *testing.T) {
   177  	testingKMS, _ := newKMS(t)
   178  	senderKey := createKey(t, testingKMS)
   179  
   180  	t.Run("Failure: pack without any recipients", func(t *testing.T) {
   181  		packer := newWithKMSAndCrypto(t, testingKMS)
   182  		require.NotEmpty(t, packer)
   183  
   184  		_, err := packer.Pack("", []byte("Test Message"), senderKey, [][]byte{})
   185  		require.EqualError(t, err, "empty recipients keys, must have at least one recipient")
   186  	})
   187  
   188  	t.Run("Failure: pack with an invalid recipient key", func(t *testing.T) {
   189  		packer := newWithKMSAndCrypto(t, testingKMS)
   190  		require.NotEmpty(t, packer)
   191  
   192  		badKey := "6ZAQ7QpmR9EqhJdwx1jQsjq6nnpehwVqUbhVxiEiYEV7"
   193  
   194  		_, err := packer.Pack("", []byte("Test Message"), senderKey, [][]byte{base58.Decode(badKey)})
   195  		require.EqualError(t, err, "pack: failed to build recipients: recipients keys are empty")
   196  	})
   197  
   198  	recipientKey := createKey(t, testingKMS)
   199  
   200  	t.Run("Failure: pack with an invalid-size sender key", func(t *testing.T) {
   201  		packer := newWithKMSAndCrypto(t, testingKMS)
   202  		require.NotEmpty(t, packer)
   203  
   204  		_, err := packer.Pack("", []byte("Test Message"), []byte{1, 2, 3}, [][]byte{recipientKey})
   205  		require.Error(t, err)
   206  		require.Contains(t, err.Error(), "recipients keys are empty")
   207  	})
   208  
   209  	t.Run("Success test case: given keys, generate envelope", func(t *testing.T) {
   210  		packer := newWithKMSAndCrypto(t, testingKMS)
   211  		require.NotEmpty(t, packer)
   212  
   213  		enc, e := packer.Pack("", []byte("Pack my box with five dozen liquor jugs!"),
   214  			senderKey, [][]byte{recipientKey})
   215  		require.NoError(t, e)
   216  		require.NotEmpty(t, enc)
   217  	})
   218  
   219  	t.Run("Generate testcase with multiple recipients", func(t *testing.T) {
   220  		senderKey1 := createKey(t, testingKMS)
   221  		rec1Key := createKey(t, testingKMS)
   222  		rec2Key := createKey(t, testingKMS)
   223  		rec3Key := createKey(t, testingKMS)
   224  		rec4Key := createKey(t, testingKMS)
   225  
   226  		recipientKeys := [][]byte{rec1Key, rec2Key, rec3Key, rec4Key}
   227  		packer := newWithKMSAndCrypto(t, testingKMS)
   228  		require.NotEmpty(t, packer)
   229  
   230  		enc, err := packer.Pack("", []byte("God! a red nugget! A fat egg under a dog!"), senderKey1, recipientKeys)
   231  		require.NoError(t, err)
   232  		require.NotEmpty(t, enc)
   233  	})
   234  
   235  	t.Run("Pack empty payload using deterministic random source, verify result", func(t *testing.T) {
   236  		senderPub := "4SPtrDH1ZH8Zsh6upbUG3TbgXjYbW1CEBRnNY6iMudX9"
   237  		senderPriv := "5MF9crszXCvzh9tWUWQwAuydh6tY2J5ErsaebwRzTsbNXx74mfaJXaKq7oTkoN4VMc2RtKktjMpPoU7vti9UnrdZ"
   238  
   239  		recipientPub := "CP1eVoFxCguQe1ttDbS3L35ZiJckZ8PZykX1SCDNgEYZ"
   240  		recipientPriv := "5aFcdEMws6ZUL7tWYrJ6DsZvY2GHZYui1jLcYquGr8uHfmyHCs96QU3nRUarH1gVYnMU2i4uUPV5STh2mX7EHpNu"
   241  
   242  		kms2, _ := newKMS(t)
   243  		require.NoError(t, persistKey(t, senderPub, senderPriv, kms2))
   244  		require.NoError(t, persistKey(t, recipientPub, recipientPriv, kms2))
   245  
   246  		source := insecurerand.NewSource(5937493) // constant fixed to ensure constant output
   247  		constRand := insecurerand.New(source)     //nolint:gosec
   248  
   249  		packer := newWithKMSAndCrypto(t, kms2)
   250  		require.NotEmpty(t, packer)
   251  		packer.randSource = constRand
   252  		enc, err := packer.Pack("", nil, base58.Decode(senderPub), [][]byte{base58.Decode(recipientPub)})
   253  		require.NoError(t, err)
   254  
   255  		test := "eyJwcm90ZWN0ZWQiOiJleUpsYm1NaU9pSmphR0ZqYUdFeU1IQnZiSGt4TXpBMVgybGxkR1lpTENKMGVYQWlPaUpLVjAwdk1TNHdJaXdpWVd4bklqb2lRWFYwYUdOeWVYQjBJaXdpY21WamFYQnBaVzUwY3lJNlczc2laVzVqY25sd2RHVmtYMnRsZVNJNklqSmlVRFl0VnpaWldXZHpjMlZpVWxOaU0xWlljV0pMTlZWa2FpMDNOSGxGTTFFdFZXaHpjMUF3Vm1aclRHNVhiMFk0WjBSNVVHRkJlREI0VWtGM2NIVWlMQ0pvWldGa1pYSWlPbnNpYTJsa0lqb2lRMUF4WlZadlJuaERaM1ZSWlRGMGRFUmlVek5NTXpWYWFVcGphMW80VUZwNWExZ3hVME5FVG1kRldWb2lMQ0p6Wlc1a1pYSWlPaUpHYzIwMU5WOUNTRkJzVkdsd2RUQlFabEZDY2t0SmRuZ3lTRGw0VTBndFVtbHpXRzgxVVdoemQwTTNjR28yTm5BMVNtOUpVVjlIT1hGdFRrVldNRzVGVG5sTVIwczFlVVZuUzJoeU5ESTBVMnBJYkRWSmQzQnljRnBqYUdGNVprNWtWa2xJTFdKNlprRnhjbXhDWTIxUVZEWkpkR2R4Y3poclRHczlJaXdpYVhZaU9pSm1OV3BVT0VKS2FHeEVZbTQwUWxvMFNGcGZSSEExTkU5TGQyWmxRV1JSTWlKOWZWMTkiLCJpdiI6ImlLZHFxRWpzTktpeW4taGsiLCJ0YWciOiIySm5SbF9iXzM2QS1WaWFKNzNCb1FBPT0ifQ==" // nolint: lll
   256  
   257  		require.Equal(t, test, base64.URLEncoding.EncodeToString(enc))
   258  	})
   259  
   260  	t.Run("Pack payload using deterministic random source for multiple recipients, verify result", func(t *testing.T) {
   261  		senderPub := "9NKZ9pHL9YVS7BzqJsz3e9uVvk44rJodKfLKbq4hmeUw"
   262  		senderPriv := "2VZLugb22G3iovUvGrecKj3VHFUNeCetkApeB4Fn4zkgBqYaMSFTW2nvF395voJ76vHkfnUXH2qvJoJnFydRoQBR"
   263  		senderKMS, _ := newKMS(t)
   264  		require.NoError(t, persistKey(t, senderPub, senderPriv, senderKMS))
   265  
   266  		rec1Pub := base58.Decode("DDk4ac2ZA19P8qXjk8XaCY9Fx7WwAmCtELkxeDNqS6Vs")
   267  		rec2Pub := base58.Decode("G79vtfWgtBG5J7R2QaBQpZfPUQaAab1QJWedWH7q3VK1")
   268  		rec3Pub := base58.Decode("7snUUwA23DVBmafz9ibmBgwFFCUwzgTzmvcJGepuzjmK")
   269  		rec4Pub := base58.Decode("GSRovbnQy8HRjVjvzGbbfN387EX9NFfLj89C1ScXYfrF")
   270  
   271  		source := insecurerand.NewSource(6572692) // constant fixed to ensure constant output
   272  		constRand := insecurerand.New(source)     //nolint:gosec
   273  
   274  		packer := newWithKMSAndCrypto(t, senderKMS)
   275  		require.NotEmpty(t, packer)
   276  		packer.randSource = constRand
   277  		enc, err := packer.Pack(
   278  			"",
   279  			[]byte("Sphinx of black quartz, judge my vow!"),
   280  			base58.Decode(senderPub),
   281  			[][]byte{rec1Pub, rec2Pub, rec3Pub, rec4Pub})
   282  		require.NoError(t, err)
   283  
   284  		test := "eyJwcm90ZWN0ZWQiOiJleUpsYm1NaU9pSmphR0ZqYUdFeU1IQnZiSGt4TXpBMVgybGxkR1lpTENKMGVYQWlPaUpLVjAwdk1TNHdJaXdpWVd4bklqb2lRWFYwYUdOeWVYQjBJaXdpY21WamFYQnBaVzUwY3lJNlczc2laVzVqY25sd2RHVmtYMnRsZVNJNkltRlliRkl0Umkwd2JEZFZTMU10Vkhwb1MwaGFWMmhIWlMxUU5tbzRlVUYwU2pFeFVEbHlSMU4yVFZGQmNHVnpZbk5wTUVsRE5XVmlVREJoVW5kVFozVWlMQ0pvWldGa1pYSWlPbnNpYTJsa0lqb2lSRVJyTkdGak1scEJNVGxRT0hGWWFtczRXR0ZEV1RsR2VEZFhkMEZ0UTNSRlRHdDRaVVJPY1ZNMlZuTWlMQ0p6Wlc1a1pYSWlPaUk1ZG1oRVdHMXBMWFJVVDBaS1FuRTRXSGhSZUROVmFUVk1SemxIT0ZoRlUxTTBaVjlST0ZCNVFUQlhhR0pCZHkxR2FscFpNVzlRWjJSb1YwOWhPVWRCTlVFd1puSkVVMHBzWm5Nd2VVNDRNVmsxV0V0a1MyUlZOVkJoTlRGdlRuQmFOVlV4VmtKSGQycG1WMmxhU0hOc05DMHhOamhuVG01cGVFazlJaXdpYVhZaU9pSjBUMjlFTW1RMVZrdFdRV2xITlMxNGNqWnFNM1UzTkZWalZUWlVibTlVWHlKOWZTeDdJbVZ1WTNKNWNIUmxaRjlyWlhraU9pSmZZa3RtVUdjM056WnphRmR5TXpWMmVXWm1jV05NZW1oTE1VUlJRV0owWTFaQ1pFVXlNM1ZUVEVGUmRHSkdNVUZMYkRrMmJHcE5WSHBzTmt4d2JuYzBJaXdpYUdWaFpHVnlJanA3SW10cFpDSTZJa2MzT1haMFpsZG5kRUpITlVvM1VqSlJZVUpSY0ZwbVVGVlJZVUZoWWpGUlNsZGxaRmRJTjNFelZrc3hJaXdpYzJWdVpHVnlJam9pVUVWNlZrc3laM1JJU25OcWFuSjVNbEZ3ZG0xYVFXazRSSGRUT1ZrM2RuVkZkakJ3Wm1JdFgyc3pRbmxQUjJoSGRHUmxUMlJUVjJaaVZrazFXRVJuV0UxNFVVWjNNM1prWHpoa2RtUndSMFZDWlZsVlNFbHBRMEZuT0VaNlZqSkNZVkZyWDFCSGRDMUliMjFJVFZoNVp6VTBUbHBCVWtsS2RXNVZQU0lzSW1sMklqb2lVV1ZRU0RRM2FsTkxXVU14Y2pSb1h6QldjMlJJVlRSWU1FZENkME5ZVWtVaWZYMHNleUpsYm1OeWVYQjBaV1JmYTJWNUlqb2lTMVZDU3pWRFIwMU5SR1ZDVkV4dFYwSmZObWQxWVhCSGNWWlZaRUpQTWxFdFkyTkdaVXRHZEZjMWRqZEpUbmhWY1VKa1FWcExlRkpGZWxFMlNEQnpXaUlzSW1obFlXUmxjaUk2ZXlKcmFXUWlPaUkzYzI1VlZYZEJNak5FVmtKdFlXWjZPV2xpYlVKbmQwWkdRMVYzZW1kVWVtMTJZMHBIWlhCMWVtcHRTeUlzSW5ObGJtUmxjaUk2SW1NdFZHRnlTSGgyVW5WTlgybFBTRnBFWkZkbVkwbG1jSGhtYVV3eVdXVlRObk4yYUZKRFRuZGlkMUpxWXpBdFJFZFllbVpTU0RkSVNEaDBOa0ZpYm5SbE1FeG5ZbGd4VGpjelQyMVJUM1ZHVUVkWlQxbFdiRGw2YTFCSlprdzNMWGh4YmtKRVF6Tm5MVkpFU0ZoNlgxSkpSSEp3WWpOVU1VTk9UVDBpTENKcGRpSTZJbGgwYVc5SFUyOWxOR0ZWV1Rac2JYcHNOVkIxWlRkMU9FOWxSMWN4YkVNNEluMTlMSHNpWlc1amNubHdkR1ZrWDJ0bGVTSTZJbEV5Wld4YVQyRktiWFZCYjA5S05GRjJXWE52YVc5R1RsRm9ha2w0UjJSWFZuZHpkV2R3WW05Q1ZucHViVVJHTjB4RFZ6RjNjMUZoTUVwMVpreHFkMjhpTENKb1pXRmtaWElpT25zaWEybGtJam9pUjFOU2IzWmlibEY1T0VoU2FsWnFkbnBIWW1KbVRqTTROMFZZT1U1R1preHFPRGxETVZOaldGbG1ja1lpTENKelpXNWtaWElpT2lKc1NYcGxNR0p3UzJ4cWNuVlRMWGREV21wUWVuWmZRMDAwUW1SdmMweHpNbDlKTUZZeFUxQnZla05uWDA5emNVRTViVEZCUVhoWmVVMXZhVXhvVkUxdU9ERmtPREo2YUd4WmVXVmxVMWxTZVdaSmNUZGFYMTlrTVRNemExcE9Wa054UVdwWFEyRllURmxxVjNoamVIUlNjRFJTYkVwYVlrOUxRVVU5SWl3aWFYWWlPaUpvTUdWTGJtRkZOVXhoWDJKYVpHVkNVR0Z1Vm0wNFpGZFVlRkZEU2xGQ2VpSjlmVjE5IiwiaXYiOiJZb3VDVi1nbGZRaFBhbDc1IiwiY2lwaGVydGV4dCI6Il9jRUNrMDQ3Y2w4Y3dFaUs1UnZLbHZORDJjTlo1bTZBTW9vdlI4MnBpMEhLbzFnZlZBPT0iLCJ0YWciOiJCYWZ4TW1CU2R5bmI0dmxvQ3ptUVNRPT0ifQ==" // nolint: lll
   285  
   286  		require.Equal(t, test, base64.URLEncoding.EncodeToString(enc))
   287  	})
   288  }
   289  
   290  func TestEncryptComponents(t *testing.T) {
   291  	senderPub := "9NKZ9pHL9YVS7BzqJsz3e9uVvk44rJodKfLKbq4hmeUw"
   292  	senderPriv := "2VZLugb22G3iovUvGrecKj3VHFUNeCetkApeB4Fn4zkgBqYaMSFTW2nvF395voJ76vHkfnUXH2qvJoJnFydRoQBR"
   293  	rec1Pub := "DDk4ac2ZA19P8qXjk8XaCY9Fx7WwAmCtELkxeDNqS6Vs"
   294  
   295  	testKMS, _ := newKMS(t)
   296  	require.NoError(t, persistKey(t, senderPub, senderPriv, testKMS))
   297  
   298  	packer := newWithKMSAndCrypto(t, testKMS)
   299  
   300  	t.Run("Failure: content encryption nonce generation fails", func(t *testing.T) {
   301  		failRand := newFailReader(0, rand.Reader)
   302  		packer.randSource = failRand
   303  
   304  		_, err := packer.Pack(
   305  			"",
   306  			[]byte("Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   307  			base58.Decode(senderPub), [][]byte{base58.Decode(rec1Pub)})
   308  		require.EqualError(t, err, "pack: failed to generate random nonce: mock Reader has failed intentionally")
   309  	})
   310  
   311  	t.Run("Failure: CEK generation fails", func(t *testing.T) {
   312  		failRand := newFailReader(1, rand.Reader)
   313  		packer.randSource = failRand
   314  
   315  		_, err := packer.Pack(
   316  			"",
   317  			[]byte("Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   318  			base58.Decode(senderPub), [][]byte{base58.Decode(rec1Pub)})
   319  		require.EqualError(t, err, "pack: failed to generate cek: mock Reader has failed intentionally")
   320  	})
   321  
   322  	t.Run("Failure: recipient nonce generation fails", func(t *testing.T) {
   323  		failRand := newFailReader(2, rand.Reader)
   324  		packer.randSource = failRand
   325  
   326  		_, err := packer.Pack(
   327  			"", []byte(
   328  				"Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   329  			base58.Decode(senderPub), [][]byte{base58.Decode(rec1Pub)})
   330  		require.EqualError(t, err, "pack: failed to build recipients: recipients keys are empty")
   331  	})
   332  
   333  	t.Run("Failure: recipient sodiumBoxSeal nonce generation fails", func(t *testing.T) {
   334  		failRand := newFailReader(3, rand.Reader)
   335  		packer.randSource = failRand
   336  
   337  		_, err := packer.Pack(
   338  			"",
   339  			[]byte("Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   340  			base58.Decode(senderPub), [][]byte{base58.Decode(rec1Pub)})
   341  		require.EqualError(t, err, "pack: failed to build recipients: recipients keys are empty")
   342  	})
   343  
   344  	t.Run("Success: 4 reads necessary for pack", func(t *testing.T) {
   345  		failRand := newFailReader(4, rand.Reader)
   346  		packer.randSource = failRand
   347  
   348  		_, err := packer.Pack(
   349  			"",
   350  			[]byte("Lorem Ipsum Dolor Sit Amet Consectetur Adispici Elit"),
   351  			base58.Decode(senderPub), [][]byte{base58.Decode(rec1Pub)})
   352  		require.NoError(t, err)
   353  	})
   354  
   355  	packer2 := newWithKMSAndCrypto(t, testKMS)
   356  
   357  	t.Run("Failure: generate recipient header with bad sender key", func(t *testing.T) {
   358  		_, err := packer2.buildRecipient(&[32]byte{}, []byte(""), base58.Decode(rec1Pub))
   359  		require.EqualError(t, err, "buildRecipient: failed to create KID for public key: createKID: "+
   360  			"empty key")
   361  	})
   362  
   363  	t.Run("Failure: generate recipient header with bad recipient key", func(t *testing.T) {
   364  		_, err := packer2.buildRecipient(&[32]byte{}, base58.Decode(senderPub), base58.Decode("AAAA"))
   365  		require.EqualError(t, err, "buildRecipient: failed to convert public Ed25519 to Curve25519: "+
   366  			"3-byte key size is invalid")
   367  	})
   368  }
   369  
   370  func TestDecrypt(t *testing.T) {
   371  	testingKMS, _ := newKMS(t)
   372  	_, senderKey, err := testingKMS.CreateAndExportPubKeyBytes(kms.ED25519Type)
   373  	require.NoError(t, err)
   374  
   375  	_, recKey, err := testingKMS.CreateAndExportPubKeyBytes(kms.ED25519Type)
   376  	require.NoError(t, err)
   377  
   378  	t.Run("Success: pack then unpack, same packer", func(t *testing.T) {
   379  		packer := newWithKMSAndCrypto(t, testingKMS)
   380  		msgIn := []byte("Junky qoph-flags vext crwd zimb.")
   381  
   382  		var (
   383  			enc []byte
   384  			env *transport.Envelope
   385  		)
   386  
   387  		enc, err = packer.Pack("", msgIn, senderKey, [][]byte{recKey})
   388  		require.NoError(t, err)
   389  		env, err = packer.Unpack(enc)
   390  		require.NoError(t, err)
   391  
   392  		require.ElementsMatch(t, msgIn, env.Message)
   393  		require.Equal(t, senderKey, env.FromKey)
   394  		require.Equal(t, recKey, env.ToKey)
   395  	})
   396  
   397  	t.Run("Success: pack and unpack, different packers, including fail recipient who wasn't sent the message", func(t *testing.T) { // nolint: lll
   398  		rec1KMS, _ := newKMS(t)
   399  		rec1Key := createKey(t, rec1KMS)
   400  
   401  		rec2KMS, _ := newKMS(t)
   402  		rec2Key := createKey(t, rec2KMS)
   403  
   404  		rec3KMS, _ := newKMS(t)
   405  		rec3Key := createKey(t, rec3KMS)
   406  
   407  		require.NoError(t, err)
   408  
   409  		sendPacker := newWithKMSAndCrypto(t, testingKMS)
   410  		rec2Packer := newWithKMSAndCrypto(t, rec2KMS)
   411  
   412  		msgIn := []byte("Junky qoph-flags vext crwd zimb.")
   413  
   414  		var (
   415  			enc []byte
   416  			env *transport.Envelope
   417  		)
   418  
   419  		enc, err = sendPacker.Pack("", msgIn, senderKey, [][]byte{rec1Key, rec2Key, rec3Key})
   420  		require.NoError(t, err)
   421  		env, err = rec2Packer.Unpack(enc)
   422  		require.NoError(t, err)
   423  		require.ElementsMatch(t, msgIn, env.Message)
   424  		require.Equal(t, senderKey, env.FromKey)
   425  		require.Equal(t, rec2Key, env.ToKey)
   426  
   427  		emptyKMS, _ := newKMS(t)
   428  		rec4Packer := newWithKMSAndCrypto(t, emptyKMS)
   429  
   430  		_, err = rec4Packer.Unpack(enc)
   431  		require.NotNil(t, err)
   432  		require.Contains(t, err.Error(), "no key accessible")
   433  	})
   434  
   435  	t.Run("Test unpacking python envelope", func(t *testing.T) {
   436  		env := `{"protected": "eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMCIsICJhbGciOiAiQXV0aGNyeXB0IiwgInJlY2lwaWVudHMiOiBbeyJlbmNyeXB0ZWRfa2V5IjogIkVhTVl4b3RKYjg4Vmt2ZmxNN1htajdFUzdvVVVSOEJSWWZ1akJGS1FGT3Y4Q2o3c0F2RndVWE5QdWVWanZ0SkEiLCAiaGVhZGVyIjogeyJraWQiOiAiRjdtTnRGMmZyTHVSdTJjTUVqWEJuV2RZY1RaQVhOUDlqRWtwclh4aWFaaTEiLCAic2VuZGVyIjogInJna1lWLUlxTWxlQUNkdE1qYXE4YnpwQXBKLXlRbjdWdzRIUnFZODNJVFozNzJkc0Y5RzV6bTVKMGhyNDVuSzBnS2JUYzRRYk5VZ1NreUExUlpZbEl6WHBwanN5eGdZUkU5ek9IbUFDcF9ldWZzejZ4YUxFOVRxN01KVT0iLCAiaXYiOiAiQ04wZWd4TFM2R19oUThDVXBjZkdZWmxzNjFtMm9YUVQifX1dfQ==", "iv": "Y4osZIg1IWaa1kFb", "ciphertext": "m9otQmcqYHOxZh4XfLbdCNouqnuPz7lGtcL5ga_1PZcPZDrhnGWPyLW2rPN2lRTftyYGPPT3tOlu4GFecZIz4zXI9kdz", "tag": "CoV9tCdrFnBbVe2h-pYyhQ=="}` // nolint: lll
   437  
   438  		msg := "Yvgu yrf vy jgbuffi tvjc hgsj fhlusfm hsuf tiw fun s kb si kfuh bssnc"
   439  
   440  		recPub := "F7mNtF2frLuRu2cMEjXBnWdYcTZAXNP9jEkprXxiaZi1"
   441  		recPriv := "2nYsWTQ1ZguQ7G2HYfMWjMNqWagBQfaKB9GLbsFk7Z7tKVBEr2arwpVKDwgLUbaxguUzQuf7o67aWKzgtHmKaypM"
   442  
   443  		recKMS, _ := newKMS(t)
   444  		require.NoError(t, persistKey(t, recPub, recPriv, recKMS))
   445  
   446  		recPacker := newWithKMSAndCrypto(t, recKMS)
   447  
   448  		var envOut *transport.Envelope
   449  		envOut, err = recPacker.Unpack([]byte(env))
   450  		require.NoError(t, err)
   451  		require.ElementsMatch(t, []byte(msg), envOut.Message)
   452  		require.NotEmpty(t, envOut.FromKey)
   453  		require.NotEmpty(t, envOut.ToKey)
   454  		require.Equal(t, recPub, base58.Encode(envOut.ToKey))
   455  	})
   456  
   457  	t.Run("Test unpacking python envelope with multiple recipients", func(t *testing.T) {
   458  		env := `{"protected": "eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMCIsICJhbGciOiAiQXV0aGNyeXB0IiwgInJlY2lwaWVudHMiOiBbeyJlbmNyeXB0ZWRfa2V5IjogImd4X3NySTljSEtNTEJnaktNOTlybUx3alFZUjJxVTdMOXc0QWo3Z1lTbDJvUTRubE5WN2tZSmJ0bVFlaWVueE8iLCAiaGVhZGVyIjogeyJraWQiOiAiQ2ZGUmluZDh0eGYxOHJmVHl1aE1pZ2t4UVBhbVNUb3hVM2prdW5ldjR5dnUiLCAic2VuZGVyIjogImFWRW03ak5Kajg2Zm9NM0VYaXZjYWpOWlFnN3pGUm0wTnk5ZzdZTzFueUpvblI2bmNVaV9EZWZzWVBHa25KcG1ZbFhuRDIzVU5nLXNBN1lWUnh5WW15aFZBSm5XNWZwdjBuNE5jaFdBTjl5S3pIMTd3NjZQLVV2WjVDcz0iLCAiaXYiOiAieVB0NGhHZVpObWFLN0hMMGtoWjhreFJzQjc3c3BOX2UifX0sIHsiZW5jcnlwdGVkX2tleSI6ICJ3a3RrWjY3VDR4R2NjTW1GZnRIRmNEV2FZMVQxRFQ3YURhMHBPeUpqTHU2REU2UGVKMUhuVXlRWXlOZ2VPR3ExIiwgImhlYWRlciI6IHsia2lkIjogIko1c2hTVlo2QW9DWHFxWWROR2tVdjFDTWZRYWVLRnNGRU4zaFdwNVBLVEN3IiwgInNlbmRlciI6ICJWdEQtakZfZFNDbmVxOUtTcVB0SUtHbHdHb0FzVHB0UkhzMTRYaWhNR0U4LUh4SjU5aVhtSnVLellxTjM2b19ZOWxfYmRFT1pRSjN0R2tRX1BqbTJyQ3VqWkRIbjdDS3Fsd3N4QlNVemYweW43aWliaDFQazJ6R0wyb2M9IiwgIml2IjogIm5acW1CbzBfT2QyTHlXejlHclJJMUlhWlRXUk4zbGVBIn19LCB7ImVuY3J5cHRlZF9rZXkiOiAiUlBsQWtTS1NsdFpGeEFJc1VzbWNiUVVMUTJWWHhRT2kzUEIxelhTbGs3TlBtMkZ2TE9zVDdQSEFHQU5Hem5oNiIsICJoZWFkZXIiOiB7ImtpZCI6ICJCS3ZqbUZFYkMyYjF3YkVycUN4R2syYmdxdkc5dUx3UlU5cWdOS3lINXRURiIsICJzZW5kZXIiOiAiTVhvRXl0NlZULXVFQnFzWEM1SWF1VXdZYXFxakxIYTdWWlF0NGRJX3FBaFZHVWhUTi01c004cXB6TnBnQlpUUHJrazFSMlBnbjlraU4waEpTUXk1T0FmOGdkSE43YXRTVDhUWEtMSHJNdm4wcDcyNUNUd3pZVnZFVnlNPSIsICJpdiI6ICJPb2FTVWgycVdOVk5qWVV6ZnZTNTdCQ1RnY3ZQYVhMeCJ9fSwgeyJlbmNyeXB0ZWRfa2V5IjogImY1cXV2amt1c2l6TmtRcm9HMk51akFsa0NzbllleUF1R1pMWDZmXy1DeG4taUNENjI2akp0aEk4OFBSei1TWWUiLCAiaGVhZGVyIjogeyJraWQiOiAiRWZ3cFR3aFVSU0QzY3lxanNWYlNWU0VMeU4yN250Tlk4V3dhZHNnVUNEOW0iLCAic2VuZGVyIjogImlOMDJNRzllSEpZZmQ3V3pGd1VFeWJBNmFWeU1Ma1JHcXVhYlJGQnJobFU3Q29EMzFHdW5yTWhEWTZETGFJV0FoX2dPMVRLMWtpMzYtTzQ4TlEyZGdOLU1RdS0wZTV5V2dQS1dzV1MtQ2xPbllEQ0RpVkc1VHBJS2dpVT0iLCAiaXYiOiAiZUg0cDZOX0dGNnpzU2trQk5nY0dWN3RRQkxfRl93MS0ifX0sIHsiZW5jcnlwdGVkX2tleSI6ICJqa3FnbHlmUlNWSXZqVnpkZ04wSGN4SGVzMTBoTjE3ckJLejZhcUtlczR3UTRLWGNGYjNpa3pNSmFSWHAwblVSIiwgImhlYWRlciI6IHsia2lkIjogIkFROW5IdExubXVHODFweTY0WUc1Z2VGMnZkNWhRQ0tIaTVNcnFRMUxZQ1hFIiwgInNlbmRlciI6ICJpSXJFOVUyOUVUbTRWa045aFdvYy1UN0dGYjVrdHB4SGtGeWp6d3BLcDJ5MWh2WWQ0NDF0SzdFUXlhTXhHeG9KNklMaWFHNnNpbTF4WS05UHV2Ny03clB4QTFCb3FxMTY0VzJZZU9FRjFwbnBOV2VmYmdTc1dtQUk0QlU9IiwgIml2IjogIm03S2h3THJ1OGtyQ1VXN1BiNTczZWpGblI3Ymlod3lNIn19XX0=", "iv": "1_pOOQhySyaYcVxi", "ciphertext": "CYHrOg1HeNxhUECoRIQRLNAOXwAjagUYf0xLp0Knnj6mEALg8lFbfmoh_oDptJ4El8jVbgDLiBExaEXIxYVnR7DR-hZjxjdbOBQAOAMUYnnvAk0lHJM0KBWlhE0AWrek1JlAfTnq-L6VsCXEqGYHg1uvpBIJicE=", "tag": "l1KfDt-VQIAImCTl7SA2og=="}` // nolint: lll
   459  
   460  		msg := "Iiwufh utiweuop fji olioy pio omlim, om kutxrwu gvgbkn kutxr " +
   461  			"w srt luhsnehim. Igywenomwe fji omwuie fnomhwuie, fjimwef."
   462  
   463  		recPub := "AQ9nHtLnmuG81py64YG5geF2vd5hQCKHi5MrqQ1LYCXE"
   464  		recPriv := "2YbSVZzSVaim41bWDdsBzamrhXrPFKKEpzXZRmgDuoFJco5VQELRSj1oWFR9aRdaufsdUyw8sozTtZuX8Mzsqboz"
   465  
   466  		recKMS, _ := newKMS(t)
   467  		require.NoError(t, persistKey(t, recPub, recPriv, recKMS))
   468  
   469  		recPacker := newWithKMSAndCrypto(t, recKMS)
   470  
   471  		var envOut *transport.Envelope
   472  		envOut, err = recPacker.Unpack([]byte(env))
   473  		require.NoError(t, err)
   474  		require.ElementsMatch(t, []byte(msg), envOut.Message)
   475  		require.NotEmpty(t, envOut.FromKey)
   476  		require.NotEmpty(t, envOut.ToKey)
   477  		require.Equal(t, recPub, base58.Encode(envOut.ToKey))
   478  	})
   479  
   480  	t.Run("Test unpacking python envelope with invalid recipient", func(t *testing.T) {
   481  		env := `{"protected": "eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMCIsICJhbGciOiAiQXV0aGNyeXB0IiwgInJlY2lwaWVudHMiOiBbeyJlbmNyeXB0ZWRfa2V5IjogIjdzN0ZTRXR6Sy1vTzdSWmdISklsSTlzX1lVU2xkMUpnRldPeUNhYUdGY1Y0aHBSTWxQbG0wNDBFcUJXRWVwY3oiLCAiaGVhZGVyIjogeyJraWQiOiAiN0RLbk56TWJHRWNYODYxOGp2WWtiNlhQTFR6eXU2YnhSbTh3RnhZb0d3SHEiLCAic2VuZGVyIjogInFLYTRDeXV1OXZOcmJzX1RCLXhQWXI2aFg2cXJZLTM4Vjd4VXdOQjFyd0J1TjVNTUVJYmRERDFvRElhV2o0QUpSYUZDTEVhSzMtakFSZHBsR1UtM2d4TWY2dkpRZWhiZkZhZHNwemdxRE9iWFZDWUJONGxrVXZLZWhvND0iLCAiaXYiOiAiSWFqeVdudFdSMENxS1BYUWJpWWptbWJRWFNNTEp2X1UifX0sIHsiZW5jcnlwdGVkX2tleSI6ICJZa05vVGh2ZUlIcC13NGlrRW1kQU51VHdxTEx1ZjBocVlVbXRJc2c5WlJMd1BKaUZHWVZuTXl1ZktKZWRvcmthIiwgImhlYWRlciI6IHsia2lkIjogIjdDRURlZUpZTnlRUzhyQjdNVHpvUHhWYXFIWm9ZZkQxNUVIVzhaVVN3VnVhIiwgInNlbmRlciI6ICJ3ZEhjc1hDemdTSjhucDRFU0pDcmJ5OWNrNjJaUEFFVjhJRjYwQmotaUhhbXJLRnBKOTJpZVNTaE1JcTdwdTNmQWZQLWo5S3J6ajAwMEV0SXB5cm05SmNrM0QwSnRBcmtYV2VsSzBoUF9ZeDR4Vlc5dW43MWlfdFBXNWM9IiwgIml2IjogIkRlbUlJbHRKaXd5TU1faGhIS29kcTZpQkx4Q1J5Z2Z3In19XX0=", "iv": "BKWHs6z0UHxGddwg", "ciphertext": "YC2eQQPYVjPHj3wIxUXxBj0yXFLuRN5Lc-9WM8hY6TXoekh-ca9-UWbHasikbcxyukTT3e-QiteOilG-6X7e9x4wiQmWn_NFLOLrqoFe669JIbkgvjHYwuQEQkIVfbD-2woSxsMUl9yln5RS-NssI5cEIVH_C1w=", "tag": "M8GPexbguDoZk5L51AvLjA=="}` // nolint: lll
   482  
   483  		recPub := "A3KnccxQu27yWQrSLwA2YFbfoSs4CHo3q6LjvhmpKz9h"
   484  		recPriv := "49Y63zwonNoj2jEhMYE22TDwQCn7RLKMqNeSkSoBBucbAWceJuXXNCACXfpbXD7PHKM13SWaySyDukEakPVn5sWs"
   485  
   486  		recKMS, _ := newKMS(t)
   487  		require.NoError(t, persistKey(t, recPub, recPriv, recKMS))
   488  
   489  		recPacker := newWithKMSAndCrypto(t, recKMS)
   490  
   491  		_, err = recPacker.Unpack([]byte(env))
   492  		require.NotNil(t, err)
   493  		require.Contains(t, err.Error(), "no key accessible")
   494  	})
   495  }
   496  
   497  func unpackComponentFailureTest(t *testing.T, protectedHeader, msg, recKeyPub, recKeyPriv, errString string) {
   498  	t.Helper()
   499  
   500  	fullMessage := `{"protected": "` + base64.URLEncoding.EncodeToString([]byte(protectedHeader)) + "\", " + msg
   501  
   502  	w, _ := newKMS(t)
   503  
   504  	err := persistKey(t, recKeyPub, recKeyPriv, w)
   505  
   506  	if errString == "createKID: empty key" {
   507  		require.EqualError(t, err, errString)
   508  		return
   509  	}
   510  
   511  	require.NoError(t, err)
   512  
   513  	recPacker := newWithKMSAndCrypto(t, w)
   514  	_, err = recPacker.Unpack([]byte(fullMessage))
   515  	require.NotNil(t, err)
   516  	require.Contains(t, err.Error(), errString)
   517  }
   518  
   519  func TestUnpackComponents(t *testing.T) {
   520  	recKeyPub := "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v"
   521  	recKeyPriv := "5pG8rLcp9WqPXQLSyQetPiyTEnLuanjS2TGd7h4DqutY6gNbLD6pnvT3H8nC5K9vEjy1UJdTtwaejf1xqDyhCrzr"
   522  
   523  	t.Run("Fail: non-JSON envelope", func(t *testing.T) {
   524  		msg := `ed": "eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEu"}`
   525  
   526  		w, _ := newKMS(t)
   527  		require.NoError(t, persistKey(t, recKeyPub, recKeyPriv, w))
   528  
   529  		recPacker := newWithKMSAndCrypto(t, w)
   530  
   531  		_, err := recPacker.Unpack([]byte(msg))
   532  		require.EqualError(t, err, "invalid character 'e' looking for beginning of value")
   533  	})
   534  
   535  	t.Run("Fail: non-base64 protected header", func(t *testing.T) {
   536  		msg := `{"protected": "&**^(&^%", "iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}` // nolint: lll
   537  
   538  		w, _ := newKMS(t)
   539  		require.NoError(t, persistKey(t, recKeyPub, recKeyPriv, w))
   540  
   541  		recPacker := newWithKMSAndCrypto(t, w)
   542  
   543  		_, err := recPacker.Unpack([]byte(msg))
   544  		require.EqualError(t, err, "illegal base64 data at input byte 0")
   545  	})
   546  
   547  	t.Run("Fail: header not json", func(t *testing.T) {
   548  		unpackComponentFailureTest(t,
   549  			`}eyJlbmMiOiAieGNoYWNoYTIwcG9seTEzMDVfaWV0ZiIsICJ0eXAiOiAiSldNLzEuMC`,
   550  			`"not important":[]}`,
   551  			recKeyPub, recKeyPriv,
   552  			"invalid character '}' looking for beginning of value")
   553  	})
   554  
   555  	t.Run("Fail: bad 'typ' field", func(t *testing.T) {
   556  		unpackComponentFailureTest(t,
   557  			`{"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
   558  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                                                                                     // nolint: lll
   559  			recKeyPub, recKeyPriv,
   560  			"message type JSON not supported")
   561  	})
   562  
   563  	t.Run("Fail: anoncrypt not supported", func(t *testing.T) {
   564  		unpackComponentFailureTest(t,
   565  			`{"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
   566  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                                                                                        //nolint: lll
   567  			recKeyPub, recKeyPriv,
   568  			"message format Anoncrypt not supported")
   569  	})
   570  
   571  	t.Run("Fail: no recipients in header", func(t *testing.T) {
   572  		unpackComponentFailureTest(t,
   573  			`{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": []}`,
   574  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll
   575  			recKeyPub, recKeyPriv,
   576  			"no key accessible")
   577  	})
   578  
   579  	t.Run("Fail: invalid public key", func(t *testing.T) {
   580  		recPub := "6ZAQ7QpmR9EqhJdwx1jQsjq6nnpehwVqUbhVxiEiYEV7" // invalid key, won't convert
   581  
   582  		unpackComponentFailureTest(t,
   583  			`{"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
   584  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                                                                                        // nolint: lll
   585  			recPub, recKeyPriv,
   586  			"sealOpen: failed to convert pub Ed25519 to X25519 key: error converting public key")
   587  	})
   588  
   589  	t.Run("Fail: invalid public key", func(t *testing.T) {
   590  		recPub := "57N4aoQKaxUGNeEn3ETnTKgeD1L5Wm3U3Vb8qi3hupLn" // mismatched keypair, won't decrypt
   591  
   592  		unpackComponentFailureTest(t,
   593  			`{"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
   594  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                                                                                        // nolint: lll
   595  			recPub, recKeyPriv,
   596  			"failed to unpack")
   597  	})
   598  
   599  	t.Run("Sender is invalid base64 data", func(t *testing.T) {
   600  		unpackComponentFailureTest(t,
   601  			`{"enc": "xchacha20poly1305_ietf", "typ": "JWM/1.0", "alg": "Authcrypt", "recipients": [{"encrypted_key": "DaZGim_WCyntSdziFgnQanpQlR_tVHzHznGbW-yhTYDVgGuc5nr6J5svu7dQbBg3", "header": {"kid": "Ak528pLhb6DNFrGWY6HjMUjpNV613h2qtAJ47j1FYe8v", "sender": "*^&", "iv": "A818WMvddPrZ8mmYqp2iuu8gqoZZC2Hx"}}]}`, // nolint: lll
   602  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                               // nolint: lll
   603  			recKeyPub, recKeyPriv,
   604  			"illegal base64 data at input byte 0")
   605  	})
   606  
   607  	t.Run("Sender is invalid public key", func(t *testing.T) {
   608  		unpackComponentFailureTest(t,
   609  			`{"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
   610  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                                                                                        // nolint: lll
   611  			recKeyPub, recKeyPriv,
   612  			"error converting public key")
   613  	})
   614  
   615  	t.Run("Message auth fail, protected header has extra whitespace", func(t *testing.T) {
   616  		unpackComponentFailureTest(t,
   617  			` {"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
   618  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                                                                                         // nolint: lll
   619  			recKeyPub, recKeyPriv,
   620  			"chacha20poly1305: message authentication failed")
   621  	})
   622  
   623  	t.Run("Nonce is invalid base64 data", func(t *testing.T) {
   624  		unpackComponentFailureTest(t,
   625  			`{"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
   626  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                                                             // nolint: lll
   627  			recKeyPub, recKeyPriv,
   628  			"illegal base64 data at input byte 0")
   629  	})
   630  
   631  	t.Run("Encrypted CEK is invalid base64 data", func(t *testing.T) {
   632  		unpackComponentFailureTest(t,
   633  			`{"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
   634  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                          // nolint: lll
   635  			recKeyPub, recKeyPriv,
   636  			"illegal base64 data at input byte 0")
   637  	})
   638  
   639  	t.Run("Bad encrypted key cannot be decrypted", func(t *testing.T) {
   640  		unpackComponentFailureTest(t,
   641  			`{"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
   642  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,                                                                                                                                // nolint: lll
   643  			recKeyPub, recKeyPriv,
   644  			"failed to decrypt CEK")
   645  	})
   646  
   647  	// valid protected header for envelope being used
   648  	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
   649  
   650  	t.Run("Ciphertext nonce not valid b64 data", func(t *testing.T) {
   651  		unpackComponentFailureTest(t,
   652  			prot,
   653  			`"iv": "!!!!!", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll
   654  			recKeyPub, recKeyPriv,
   655  			"illegal base64 data at input byte 0")
   656  	})
   657  
   658  	t.Run("Ciphertext not valid b64 data", func(t *testing.T) {
   659  		unpackComponentFailureTest(t,
   660  			prot, `"iv": "oDZpVO648Po3UcoW", "ciphertext": "=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`,
   661  			recKeyPub, recKeyPriv,
   662  			"illegal base64 data at input byte 0")
   663  	})
   664  
   665  	t.Run("Ciphertext tag not valid b64 data", func(t *testing.T) {
   666  		unpackComponentFailureTest(t,
   667  			prot,
   668  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "123"}`, // nolint: lll
   669  			recKeyPub, recKeyPriv,
   670  			"illegal base64 data at input byte 0")
   671  	})
   672  
   673  	badKeyPriv := "badkeyabcdefghijklmnopqrstuvwxyzbadkeyabcdefghijklmnopqrstuvwxyz"
   674  	badKeyPub := "badkeyabcdefghijklmnopqrstuvwxyz"
   675  
   676  	t.Run("Recipient Key not valid key", func(t *testing.T) {
   677  		unpackComponentFailureTest(t,
   678  			prot,
   679  			`"iv": "oDZpVO648Po3UcoW", "ciphertext": "pLrFQ6dND0aB4saHjSklcNTDAvpFPmIvebCis7S6UupzhhPOHwhp6o97_EphsWbwqqHl0HTiT7W9kUqrvd8jcWgx5EATtkx5o3PSyHfsfm9jl0tmKsqu6VG0RML_OokZiFv76ZUZuGMrHKxkCHGytILhlpSwajg=", "tag": "6GigdWnW59aC9Y8jhy76rA=="}`, // nolint: lll
   680  			badKeyPub, badKeyPriv,
   681  			"createKID: empty key")
   682  	})
   683  }
   684  
   685  func Test_getCEK(t *testing.T) {
   686  	k := mockkms.KeyManager{
   687  		GetKeyValue: nil,
   688  		GetKeyErr:   fmt.Errorf("mock error"),
   689  	}
   690  
   691  	recs := []recipient{
   692  		{
   693  			EncryptedKey: "",
   694  			Header: recipientHeader{
   695  				KID: "BADKEY",
   696  			},
   697  		},
   698  	}
   699  
   700  	_, err := getCEK(recs, &k)
   701  	require.EqualError(t, err, "getCEK: no key accessible none of the recipient keys were found in kms: "+
   702  		"[mock error]")
   703  }
   704  
   705  func Test_newCryptoBox(t *testing.T) {
   706  	_, err := newCryptoBox(&mockkms.KeyManager{})
   707  	require.EqualError(t, err, "cannot use parameter argument as KMS")
   708  
   709  	_, err = newCryptoBox(&webkms.RemoteKMS{})
   710  	require.NoError(t, err)
   711  }