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 }