@@ -363,41 +363,39 @@ def test_aes_128_gcm
363363 #assert_equal "", cipher.final
364364 end
365365
366- def test_aes_gcm
366+ def test_aes_gcm_custom
367367 [ 'aes-128-gcm' , 'aes-192-gcm' , 'aes-256-gcm' ] . each do |algo |
368368 pt = "You should all use Authenticated Encryption!"
369- cipher , key , iv = new_encryptor ( algo )
369+ cipher , key , iv = new_random_encryptor ( algo )
370370
371371 cipher . auth_data = "aad"
372372 ct = cipher . update ( pt ) + cipher . final
373373 tag = cipher . auth_tag
374374 assert_equal ( 16 , tag . size )
375375
376- decipher = new_decryptor ( algo , key , iv )
376+ decipher = new_decryptor ( algo , key : key , iv : iv )
377377 decipher . auth_tag = tag
378378 decipher . auth_data = "aad"
379379
380380 assert_equal ( pt , decipher . update ( ct ) + decipher . final )
381381 end
382382 end
383383
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 )
385392 cipher = OpenSSL ::Cipher . new ( algo )
386393 cipher . encrypt
387394 key = cipher . random_key
388395 iv = cipher . random_iv
389396 [ cipher , key , iv ]
390397 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
401399
402400 def test_aes_128_gcm_with_auth_tag
403401 cipher = OpenSSL ::Cipher . new ( 'aes-128-gcm' )
@@ -498,4 +496,80 @@ def test_encrypt_aes_256_cbc_invalid_buffer
498496 assert_raise ( TypeError ) { cipher . update ( 'bar' * 10 , buffer ) }
499497 end
500498
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+
501575end
0 commit comments