@@ -36,7 +36,7 @@ import {
36
36
SignatureKey ,
37
37
VerificationKey
38
38
} from '@aws-crypto/material-management'
39
- import { synchronousRandomValues , getWebCryptoBackend , getZeroByteSubtle } from '@aws-crypto/web-crypto-backend'
39
+ import { synchronousRandomValues , getWebCryptoBackend , getZeroByteSubtle , getNonZeroByteBackend } from '@aws-crypto/web-crypto-backend'
40
40
41
41
chai . use ( chaiAsPromised )
42
42
const { expect } = chai
@@ -288,6 +288,93 @@ describe('getSubtleFunction', () => {
288
288
expect ( ( ) => testIvAad ( iv , aad ) ) . to . throw ( )
289
289
} )
290
290
291
+ it ( 'can encrypt/decrypt 0 bytes' , async ( ) => {
292
+ const suite = new WebCryptoAlgorithmSuite ( AlgorithmSuiteIdentifier . ALG_AES128_GCM_IV12_TAG16 )
293
+ const material = new WebCryptoEncryptionMaterial ( suite , { } )
294
+ const udk = synchronousRandomValues ( suite . keyLengthBytes )
295
+ const trace = { keyName : 'keyName' , keyNamespace : 'keyNamespace' , flags : KeyringTraceFlag . WRAPPING_KEY_GENERATED_DATA_KEY }
296
+ material . setUnencryptedDataKey ( udk , trace )
297
+
298
+ const backend = await getWebCryptoBackend ( )
299
+ /* All of this _only_ matters in the case of a mixed backend.
300
+ * So I force the issue.
301
+ */
302
+ const mixedBackend = {
303
+ nonZeroByteSubtle : getZeroByteSubtle ( backend ) ,
304
+ zeroByteSubtle : getNonZeroByteBackend ( backend ) ,
305
+ randomValues : backend . randomValues
306
+ }
307
+
308
+ const cryptoKey = await importCryptoKey ( mixedBackend , material , [ 'encrypt' , 'decrypt' ] )
309
+ material . setCryptoKey ( cryptoKey , trace )
310
+
311
+ const iv = new Uint8Array ( suite . ivLength )
312
+ const aad = new Uint8Array ( 1 )
313
+ const tagLengthBytes = suite . tagLength / 8
314
+
315
+ // Encrypt
316
+ const testEncryptInfo = getSubtleFunction ( material , mixedBackend , 'encrypt' )
317
+ const testEncryptIvAad = testEncryptInfo ( new Uint8Array ( 1 ) )
318
+ const testEncryptFunction = testEncryptIvAad ( iv , aad )
319
+ const testEncryptedData = await testEncryptFunction ( new Uint8Array ( 0 ) )
320
+ // Because I encrypted 0 bytes, the data should _only_ be tagLength
321
+ expect ( testEncryptedData . byteLength ) . to . equal ( tagLengthBytes )
322
+
323
+ // Decrypt
324
+ const testDecryptInfo = getSubtleFunction ( material , mixedBackend , 'decrypt' )
325
+ const testDecryptIvAad = testDecryptInfo ( new Uint8Array ( 1 ) )
326
+ const testDecryptFunction = testDecryptIvAad ( iv , aad )
327
+ const testDecryptedData = await testDecryptFunction ( new Uint8Array ( testEncryptedData ) )
328
+
329
+ // Because I encrypted 0 bytes, the data should be 0 length
330
+ expect ( testDecryptedData . byteLength ) . to . equal ( 0 )
331
+ } )
332
+
333
+ it ( 'Precondition: The WebCrypto AES-GCM decrypt API expects the data *and* tag together.' , async ( ) => {
334
+ const suite = new WebCryptoAlgorithmSuite ( AlgorithmSuiteIdentifier . ALG_AES128_GCM_IV12_TAG16 )
335
+ const material = new WebCryptoEncryptionMaterial ( suite , { } )
336
+ const udk = synchronousRandomValues ( suite . keyLengthBytes )
337
+ const trace = { keyName : 'keyName' , keyNamespace : 'keyNamespace' , flags : KeyringTraceFlag . WRAPPING_KEY_GENERATED_DATA_KEY }
338
+ material . setUnencryptedDataKey ( udk , trace )
339
+
340
+ const backend = await getWebCryptoBackend ( )
341
+ /* All of this _only_ matters in the case of a mixed backend.
342
+ * So I force the issue.
343
+ */
344
+ const mixedBackend = {
345
+ nonZeroByteSubtle : getZeroByteSubtle ( backend ) ,
346
+ zeroByteSubtle : getNonZeroByteBackend ( backend ) ,
347
+ randomValues : backend . randomValues
348
+ }
349
+
350
+ const cryptoKey = await importCryptoKey ( mixedBackend , material , [ 'encrypt' , 'decrypt' ] )
351
+ material . setCryptoKey ( cryptoKey , trace )
352
+
353
+ const iv = new Uint8Array ( suite . ivLength )
354
+ const aad = new Uint8Array ( 1 )
355
+ const tagLengthBytes = suite . tagLength / 8
356
+
357
+ // Encrypt
358
+ const testEncryptInfo = getSubtleFunction ( material , mixedBackend , 'encrypt' )
359
+ const testEncryptIvAad = testEncryptInfo ( new Uint8Array ( 1 ) )
360
+ const testEncryptFunction = testEncryptIvAad ( iv , aad )
361
+ const testEncryptedData = await testEncryptFunction ( new Uint8Array ( 0 ) )
362
+
363
+ // Because I encrypted 0 bytes, the data should _only_ be tagLength
364
+ expect ( testEncryptedData . byteLength ) . to . equal ( tagLengthBytes )
365
+
366
+ // Decrypt
367
+ const testDecryptInfo = getSubtleFunction ( material , mixedBackend , 'decrypt' )
368
+ const testDecryptIvAad = testDecryptInfo ( new Uint8Array ( 1 ) )
369
+ const testDecryptFunction = testDecryptIvAad ( iv , aad )
370
+
371
+ for ( let i = 0 ; tagLengthBytes > i ; i ++ ) {
372
+ console . log ( i )
373
+ await expect ( testDecryptFunction ( new Uint8Array ( testEncryptedData . slice ( 0 , i ) ) ) )
374
+ . to . eventually . rejectedWith ( Error , 'Invalid data length.' )
375
+ }
376
+ } )
377
+
291
378
it ( 'no kdf, simple backend, can encrypt/decrypt' , async ( ) => {
292
379
const suite = new WebCryptoAlgorithmSuite ( AlgorithmSuiteIdentifier . ALG_AES128_GCM_IV12_TAG16 )
293
380
const encryptionMaterial = new WebCryptoEncryptionMaterial ( suite , { } )
0 commit comments