@@ -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' )
@@ -498,4 +496,80 @@ def test_encrypt_aes_256_cbc_invalid_buffer
498
496
assert_raise ( TypeError ) { cipher . update ( 'bar' * 10 , buffer ) }
499
497
end
500
498
499
+ def test_aes_gcm
500
+ # GCM spec Appendix B Test Case 4
501
+ key = [ "feffe9928665731c6d6a8f9467308308" ] . pack ( "H*" )
502
+ iv = [ "cafebabefacedbaddecaf888" ] . pack ( "H*" )
503
+ aad = [ "feedfacedeadbeeffeedfacedeadbeef" \
504
+ "abaddad2" ] . pack ( "H*" )
505
+ pt = [ "d9313225f88406e5a55909c5aff5269a" \
506
+ "86a7a9531534f7da2e4c303d8a318a72" \
507
+ "1c3c0c95956809532fcf0e2449a6b525" \
508
+ "b16aedf5aa0de657ba637b39" ] . pack ( "H*" )
509
+ ct = [ "42831ec2217774244b7221b784d0d49c" \
510
+ "e3aa212f2c02a4e035c17e2329aca12e" \
511
+ "21d514b25466931c7d8f6a5aac84aa05" \
512
+ "1ba30b396a0aac973d58e091" ] . pack ( "H*" )
513
+ tag = [ "5bc94fbc3221a5db94fae95ae7121a47" ] . pack ( "H*" )
514
+
515
+ cipher = new_encryptor ( "aes-128-gcm" , key : key , iv : iv , auth_data : aad )
516
+ # TODO JOpenSSL should raise
517
+ # assert_raise(OpenSSL::Cipher::CipherError, 'unable to set authentication tag length: failed to get parameter') do
518
+ # cipher.auth_tag_len = 16
519
+ # end
520
+ assert_equal ct , cipher . update ( pt ) << cipher . final
521
+ assert_equal tag , cipher . auth_tag
522
+ cipher = new_decryptor ( "aes-128-gcm" , key : key , iv : iv , auth_tag : tag , auth_data : aad )
523
+ # TODO JOpenSSL should raise
524
+ # assert_raise(OpenSSL::Cipher::CipherError, 'unable to set authentication tag length: failed to get parameter') do
525
+ # cipher.auth_tag_len = 16
526
+ # end
527
+ assert_equal pt , cipher . update ( ct ) << cipher . final
528
+
529
+ # truncated tag is accepted
530
+ cipher = new_encryptor ( "aes-128-gcm" , key : key , iv : iv , auth_data : aad )
531
+ assert_equal ct , cipher . update ( pt ) << cipher . final
532
+ assert_equal tag [ 0 , 8 ] , cipher . auth_tag ( 8 )
533
+ assert_equal tag , cipher . auth_tag
534
+
535
+ # NOTE: MRI seems to just ignore the invalid tag?!
536
+ # cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag[0, 8], auth_data: aad)
537
+ # assert_equal pt, cipher.update(ct) << cipher.final
538
+
539
+ # wrong tag is rejected
540
+ tag2 = tag . dup
541
+ tag2 . setbyte ( -1 , ( tag2 . getbyte ( -1 ) + 1 ) & 0xff )
542
+ cipher = new_decryptor ( "aes-128-gcm" , key : key , iv : iv , auth_tag : tag2 , auth_data : aad )
543
+ cipher . update ( ct )
544
+ assert_raise ( OpenSSL ::Cipher ::CipherError ) { cipher . final }
545
+
546
+ # wrong aad is rejected
547
+ aad2 = aad [ 0 ..-2 ] << aad [ -1 ] . succ
548
+ cipher = new_decryptor ( "aes-128-gcm" , key : key , iv : iv , auth_tag : tag , auth_data : aad2 )
549
+ cipher . update ( ct )
550
+ assert_raise ( OpenSSL ::Cipher ::CipherError ) { cipher . final }
551
+
552
+ # wrong ciphertext is rejected
553
+ ct2 = ct [ 0 ..-2 ] << ct [ -1 ] . succ
554
+ cipher = new_decryptor ( "aes-128-gcm" , key : key , iv : iv , auth_tag : tag , auth_data : aad )
555
+ cipher . update ( ct2 )
556
+ assert_raise ( OpenSSL ::Cipher ::CipherError ) { cipher . final }
557
+ end
558
+
559
+ private
560
+
561
+ def new_encryptor ( algo , **kwargs )
562
+ OpenSSL ::Cipher . new ( algo ) . tap do |cipher |
563
+ cipher . encrypt
564
+ kwargs . each { |k , v | cipher . send ( :"#{ k } =" , v ) }
565
+ end
566
+ end
567
+
568
+ def new_decryptor ( algo , **kwargs )
569
+ OpenSSL ::Cipher . new ( algo ) . tap do |cipher |
570
+ cipher . decrypt
571
+ kwargs . each { |k , v | cipher . send ( :"#{ k } =" , v ) }
572
+ end
573
+ end
574
+
501
575
end
0 commit comments