1require_relative 'utils' 2 3if defined?(OpenSSL) 4 5class OpenSSL::TestCipher < Test::Unit::TestCase 6 7 class << self 8 9 def has_cipher?(name) 10 ciphers = OpenSSL::Cipher.ciphers 11 # redefine method so we can use the cached ciphers value from the closure 12 # and need not recompute the list each time 13 define_singleton_method :has_cipher? do |name| 14 ciphers.include?(name) 15 end 16 has_cipher?(name) 17 end 18 19 def has_ciphers?(list) 20 list.all? { |name| has_cipher?(name) } 21 end 22 23 end 24 25 def setup 26 @c1 = OpenSSL::Cipher::Cipher.new("DES-EDE3-CBC") 27 @c2 = OpenSSL::Cipher::DES.new(:EDE3, "CBC") 28 @key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 29 @iv = "\0\0\0\0\0\0\0\0" 30 @hexkey = "0000000000000000000000000000000000000000000000" 31 @hexiv = "0000000000000000" 32 @data = "DATA" 33 end 34 35 def teardown 36 @c1 = @c2 = nil 37 end 38 39 def test_crypt 40 @c1.encrypt.pkcs5_keyivgen(@key, @iv) 41 @c2.encrypt.pkcs5_keyivgen(@key, @iv) 42 s1 = @c1.update(@data) + @c1.final 43 s2 = @c2.update(@data) + @c2.final 44 assert_equal(s1, s2, "encrypt") 45 46 @c1.decrypt.pkcs5_keyivgen(@key, @iv) 47 @c2.decrypt.pkcs5_keyivgen(@key, @iv) 48 assert_equal(@data, @c1.update(s1)+@c1.final, "decrypt") 49 assert_equal(@data, @c2.update(s2)+@c2.final, "decrypt") 50 end 51 52 def test_info 53 assert_equal("DES-EDE3-CBC", @c1.name, "name") 54 assert_equal("DES-EDE3-CBC", @c2.name, "name") 55 assert_kind_of(Fixnum, @c1.key_len, "key_len") 56 assert_kind_of(Fixnum, @c1.iv_len, "iv_len") 57 end 58 59 def test_dup 60 assert_equal(@c1.name, @c1.dup.name, "dup") 61 assert_equal(@c1.name, @c1.clone.name, "clone") 62 @c1.encrypt 63 @c1.key = @key 64 @c1.iv = @iv 65 tmpc = @c1.dup 66 s1 = @c1.update(@data) + @c1.final 67 s2 = tmpc.update(@data) + tmpc.final 68 assert_equal(s1, s2, "encrypt dup") 69 end 70 71 def test_reset 72 @c1.encrypt 73 @c1.key = @key 74 @c1.iv = @iv 75 s1 = @c1.update(@data) + @c1.final 76 @c1.reset 77 s2 = @c1.update(@data) + @c1.final 78 assert_equal(s1, s2, "encrypt reset") 79 end 80 81 def test_empty_data 82 @c1.encrypt 83 assert_raise(ArgumentError){ @c1.update("") } 84 end 85 86 def test_initialize 87 assert_raise(RuntimeError) {@c1.__send__(:initialize, "DES-EDE3-CBC")} 88 assert_raise(RuntimeError) {OpenSSL::Cipher.allocate.final} 89 end 90 91 def test_ctr_if_exists 92 begin 93 cipher = OpenSSL::Cipher.new('aes-128-ctr') 94 cipher.encrypt 95 cipher.pkcs5_keyivgen('password') 96 c = cipher.update('hello,world') + cipher.final 97 cipher.decrypt 98 cipher.pkcs5_keyivgen('password') 99 assert_equal('hello,world', cipher.update(c) + cipher.final) 100 end 101 end if has_cipher?('aes-128-ctr') 102 103 if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00907000 104 def test_ciphers 105 OpenSSL::Cipher.ciphers.each{|name| 106 next if /netbsd/ =~ RUBY_PLATFORM && /idea|rc5/i =~ name 107 assert(OpenSSL::Cipher::Cipher.new(name).is_a?(OpenSSL::Cipher::Cipher)) 108 } 109 end 110 111 def test_AES 112 pt = File.read(__FILE__) 113 %w(ECB CBC CFB OFB).each{|mode| 114 c1 = OpenSSL::Cipher::AES256.new(mode) 115 c1.encrypt 116 c1.pkcs5_keyivgen("passwd") 117 ct = c1.update(pt) + c1.final 118 119 c2 = OpenSSL::Cipher::AES256.new(mode) 120 c2.decrypt 121 c2.pkcs5_keyivgen("passwd") 122 assert_equal(pt, c2.update(ct) + c2.final) 123 } 124 end 125 126 def test_AES_crush 127 500.times do 128 assert_nothing_raised("[Bug #2768]") do 129 # it caused OpenSSL SEGV by uninitialized key 130 OpenSSL::Cipher::AES128.new("ECB").update "." * 17 131 end 132 end 133 end 134 end 135 136 if has_ciphers?(['aes-128-gcm', 'aes-192-gcm', 'aes-128-gcm']) 137 138 def test_authenticated 139 cipher = OpenSSL::Cipher.new('aes-128-gcm') 140 assert(cipher.authenticated?) 141 cipher = OpenSSL::Cipher.new('aes-128-cbc') 142 refute(cipher.authenticated?) 143 end 144 145 def test_aes_gcm 146 ['aes-128-gcm', 'aes-192-gcm', 'aes-128-gcm'].each do |algo| 147 pt = "You should all use Authenticated Encryption!" 148 cipher, key, iv = new_encryptor(algo) 149 150 cipher.auth_data = "aad" 151 ct = cipher.update(pt) + cipher.final 152 tag = cipher.auth_tag 153 assert_equal(16, tag.size) 154 155 decipher = new_decryptor(algo, key, iv) 156 decipher.auth_tag = tag 157 decipher.auth_data = "aad" 158 159 assert_equal(pt, decipher.update(ct) + decipher.final) 160 end 161 end 162 163 def test_aes_gcm_short_tag 164 ['aes-128-gcm', 'aes-192-gcm', 'aes-128-gcm'].each do |algo| 165 pt = "You should all use Authenticated Encryption!" 166 cipher, key, iv = new_encryptor(algo) 167 168 cipher.auth_data = "aad" 169 ct = cipher.update(pt) + cipher.final 170 tag = cipher.auth_tag(8) 171 assert_equal(8, tag.size) 172 173 decipher = new_decryptor(algo, key, iv) 174 decipher.auth_tag = tag 175 decipher.auth_data = "aad" 176 177 assert_equal(pt, decipher.update(ct) + decipher.final) 178 end 179 end 180 181 def test_aes_gcm_wrong_tag 182 pt = "You should all use Authenticated Encryption!" 183 cipher, key, iv = new_encryptor('aes-128-gcm') 184 185 cipher.auth_data = "aad" 186 ct = cipher.update(pt) + cipher.final 187 tag = cipher.auth_tag 188 189 decipher = new_decryptor('aes-128-gcm', key, iv) 190 tag.setbyte(-1, (tag.getbyte(-1) + 1) & 0xff) 191 decipher.auth_tag = tag 192 decipher.auth_data = "aad" 193 194 assert_raise OpenSSL::Cipher::CipherError do 195 decipher.update(ct) + decipher.final 196 end 197 end 198 199 def test_aes_gcm_wrong_auth_data 200 pt = "You should all use Authenticated Encryption!" 201 cipher, key, iv = new_encryptor('aes-128-gcm') 202 203 cipher.auth_data = "aad" 204 ct = cipher.update(pt) + cipher.final 205 tag = cipher.auth_tag 206 207 decipher = new_decryptor('aes-128-gcm', key, iv) 208 decipher.auth_tag = tag 209 decipher.auth_data = "daa" 210 211 assert_raise OpenSSL::Cipher::CipherError do 212 decipher.update(ct) + decipher.final 213 end 214 end 215 216 def test_aes_gcm_wrong_ciphertext 217 pt = "You should all use Authenticated Encryption!" 218 cipher, key, iv = new_encryptor('aes-128-gcm') 219 220 cipher.auth_data = "aad" 221 ct = cipher.update(pt) + cipher.final 222 tag = cipher.auth_tag 223 224 decipher = new_decryptor('aes-128-gcm', key, iv) 225 decipher.auth_tag = tag 226 decipher.auth_data = "aad" 227 228 assert_raise OpenSSL::Cipher::CipherError do 229 decipher.update(ct[0..-2] << ct[-1].succ) + decipher.final 230 end 231 end 232 233 end 234 235 private 236 237 def new_encryptor(algo) 238 cipher = OpenSSL::Cipher.new(algo) 239 cipher.encrypt 240 key = cipher.random_key 241 iv = cipher.random_iv 242 [cipher, key, iv] 243 end 244 245 def new_decryptor(algo, key, iv) 246 OpenSSL::Cipher.new(algo).tap do |cipher| 247 cipher.decrypt 248 cipher.key = key 249 cipher.iv = iv 250 end 251 end 252 253end 254 255end 256