@@ -363,41 +363,39 @@ def test_aes_128_gcm
363
363
#assert_equal "", cipher.final
364
364
end
365
365
366
- def test_aes_gcm
366
+ def test_aes_gcm_custom
367
367
[ 'aes-128-gcm' , 'aes-192-gcm' , 'aes-256-gcm' ] . each do |algo |
368
368
pt = "You should all use Authenticated Encryption!"
369
- cipher , key , iv = new_encryptor ( algo )
369
+ cipher , key , iv = new_random_encryptor ( algo )
370
370
371
371
cipher . auth_data = "aad"
372
372
ct = cipher . update ( pt ) + cipher . final
373
373
tag = cipher . auth_tag
374
374
assert_equal ( 16 , tag . size )
375
375
376
- decipher = new_decryptor ( algo , key , iv )
376
+ decipher = new_decryptor ( algo , key : key , iv : iv )
377
377
decipher . auth_tag = tag
378
378
decipher . auth_data = "aad"
379
379
380
380
assert_equal ( pt , decipher . update ( ct ) + decipher . final )
381
381
end
382
382
end
383
383
384
- def new_encryptor ( algo )
384
+ def test_authenticated
385
+ cipher = OpenSSL ::Cipher . new ( 'aes-128-gcm' )
386
+ assert_predicate ( cipher , :authenticated? )
387
+ cipher = OpenSSL ::Cipher . new ( 'aes-128-cbc' )
388
+ assert_not_predicate ( cipher , :authenticated? )
389
+ end
390
+
391
+ def new_random_encryptor ( algo )
385
392
cipher = OpenSSL ::Cipher . new ( algo )
386
393
cipher . encrypt
387
394
key = cipher . random_key
388
395
iv = cipher . random_iv
389
396
[ cipher , key , iv ]
390
397
end
391
- private :new_encryptor
392
-
393
- def new_decryptor ( algo , key , iv )
394
- OpenSSL ::Cipher . new ( algo ) . tap do |cipher |
395
- cipher . decrypt
396
- cipher . key = key
397
- cipher . iv = iv
398
- end
399
- end
400
- private :new_decryptor
398
+ private :new_random_encryptor
401
399
402
400
def test_aes_128_gcm_with_auth_tag
403
401
cipher = OpenSSL ::Cipher . new ( 'aes-128-gcm' )
@@ -496,6 +494,81 @@ def test_encrypt_aes_256_cbc_invalid_buffer
496
494
cipher . encrypt
497
495
buffer = Object . new
498
496
assert_raise ( TypeError ) { cipher . update ( 'bar' * 10 , buffer ) }
497
+
498
+ def test_aes_gcm
499
+ # GCM spec Appendix B Test Case 4
500
+ key = [ "feffe9928665731c6d6a8f9467308308" ] . pack ( "H*" )
501
+ iv = [ "cafebabefacedbaddecaf888" ] . pack ( "H*" )
502
+ aad = [ "feedfacedeadbeeffeedfacedeadbeef" \
503
+ "abaddad2" ] . pack ( "H*" )
504
+ pt = [ "d9313225f88406e5a55909c5aff5269a" \
505
+ "86a7a9531534f7da2e4c303d8a318a72" \
506
+ "1c3c0c95956809532fcf0e2449a6b525" \
507
+ "b16aedf5aa0de657ba637b39" ] . pack ( "H*" )
508
+ ct = [ "42831ec2217774244b7221b784d0d49c" \
509
+ "e3aa212f2c02a4e035c17e2329aca12e" \
510
+ "21d514b25466931c7d8f6a5aac84aa05" \
511
+ "1ba30b396a0aac973d58e091" ] . pack ( "H*" )
512
+ tag = [ "5bc94fbc3221a5db94fae95ae7121a47" ] . pack ( "H*" )
513
+
514
+ cipher = new_encryptor ( "aes-128-gcm" , key : key , iv : iv , auth_data : aad )
515
+ # TODO JOpenSSL should raise
516
+ # assert_raise(OpenSSL::Cipher::CipherError, 'unable to set authentication tag length: failed to get parameter') do
517
+ # cipher.auth_tag_len = 16
518
+ # end
519
+ assert_equal ct , cipher . update ( pt ) << cipher . final
520
+ assert_equal tag , cipher . auth_tag
521
+ cipher = new_decryptor ( "aes-128-gcm" , key : key , iv : iv , auth_tag : tag , auth_data : aad )
522
+ # TODO JOpenSSL should raise
523
+ # assert_raise(OpenSSL::Cipher::CipherError, 'unable to set authentication tag length: failed to get parameter') do
524
+ # cipher.auth_tag_len = 16
525
+ # end
526
+ assert_equal pt , cipher . update ( ct ) << cipher . final
527
+
528
+ # truncated tag is accepted
529
+ cipher = new_encryptor ( "aes-128-gcm" , key : key , iv : iv , auth_data : aad )
530
+ assert_equal ct , cipher . update ( pt ) << cipher . final
531
+ assert_equal tag [ 0 , 8 ] , cipher . auth_tag ( 8 )
532
+ assert_equal tag , cipher . auth_tag
533
+
534
+ # NOTE: MRI seems to just ignore the invalid tag?!
535
+ # cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag[0, 8], auth_data: aad)
536
+ # assert_equal pt, cipher.update(ct) << cipher.final
537
+
538
+ # wrong tag is rejected
539
+ tag2 = tag . dup
540
+ tag2 . setbyte ( -1 , ( tag2 . getbyte ( -1 ) + 1 ) & 0xff )
541
+ cipher = new_decryptor ( "aes-128-gcm" , key : key , iv : iv , auth_tag : tag2 , auth_data : aad )
542
+ cipher . update ( ct )
543
+ assert_raise ( OpenSSL ::Cipher ::CipherError ) { cipher . final }
544
+
545
+ # wrong aad is rejected
546
+ aad2 = aad [ 0 ..-2 ] << aad [ -1 ] . succ
547
+ cipher = new_decryptor ( "aes-128-gcm" , key : key , iv : iv , auth_tag : tag , auth_data : aad2 )
548
+ cipher . update ( ct )
549
+ assert_raise ( OpenSSL ::Cipher ::CipherError ) { cipher . final }
550
+
551
+ # wrong ciphertext is rejected
552
+ ct2 = ct [ 0 ..-2 ] << ct [ -1 ] . succ
553
+ cipher = new_decryptor ( "aes-128-gcm" , key : key , iv : iv , auth_tag : tag , auth_data : aad )
554
+ cipher . update ( ct2 )
555
+ assert_raise ( OpenSSL ::Cipher ::CipherError ) { cipher . final }
556
+ end
557
+
558
+ private
559
+
560
+ def new_encryptor ( algo , **kwargs )
561
+ OpenSSL ::Cipher . new ( algo ) . tap do |cipher |
562
+ cipher . encrypt
563
+ kwargs . each { |k , v | cipher . send ( :"#{ k } =" , v ) }
564
+ end
565
+ end
566
+
567
+ def new_decryptor ( algo , **kwargs )
568
+ OpenSSL ::Cipher . new ( algo ) . tap do |cipher |
569
+ cipher . decrypt
570
+ kwargs . each { |k , v | cipher . send ( :"#{ k } =" , v ) }
571
+ end
499
572
end
500
573
501
574
end
0 commit comments