--- ruby-2.0.0-p648/ext/openssl/ossl_cipher.c.0022 2015-01-14 07:25:48.000000000 +0000 +++ ruby-2.0.0-p648/ext/openssl/ossl_cipher.c 2016-10-03 21:47:10.496529244 +0100 @@ -35,6 +35,7 @@ */ VALUE cCipher; VALUE eCipherError; +static ID id_key_set; static VALUE ossl_cipher_alloc(VALUE klass); @@ -102,7 +103,6 @@ EVP_CIPHER_CTX *ctx; const EVP_CIPHER *cipher; char *name; - unsigned char key[EVP_MAX_KEY_LENGTH]; name = StringValuePtr(str); GetCipherInit(self, ctx); @@ -114,14 +114,7 @@ if (!(cipher = EVP_get_cipherbyname(name))) { ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%s)", name); } - /* - * The EVP which has EVP_CIPH_RAND_KEY flag (such as DES3) allows - * uninitialized key, but other EVPs (such as AES) does not allow it. - * Calling EVP_CipherUpdate() without initializing key causes SEGV so we - * set the data filled with "\0" as the key by default. - */ - memset(key, 0, EVP_MAX_KEY_LENGTH); - if (EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, -1) != 1) + if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) ossl_raise(eCipherError, NULL); return self; @@ -239,7 +232,8 @@ if (EVP_CipherInit_ex(ctx, NULL, NULL, p_key, p_iv, mode) != 1) { ossl_raise(eCipherError, NULL); } - + if (p_key) + rb_ivar_set(self, id_key_set, Qtrue); return self; } @@ -326,6 +320,7 @@ OPENSSL_cleanse(key, sizeof key); OPENSSL_cleanse(iv, sizeof iv); + rb_ivar_set(self, id_key_set, Qtrue); return Qnil; } @@ -379,6 +374,9 @@ rb_scan_args(argc, argv, "11", &data, &str); + if (!RTEST(rb_attr_get(self, id_key_set))) + ossl_raise(eCipherError, "key not set"); + StringValue(data); in = (unsigned char *)RSTRING_PTR(data); if ((in_len = RSTRING_LEN(data)) == 0) @@ -478,6 +476,7 @@ if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1) ossl_raise(eCipherError, NULL); + rb_ivar_set(self, id_key_set, Qtrue); return key; } @@ -996,5 +995,7 @@ rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0); rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0); rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1); + + id_key_set = rb_intern_const("key_set"); } --- ruby-2.0.0-p648/test/openssl/test_cipher.rb.0022 2015-02-17 08:59:14.000000000 +0000 +++ ruby-2.0.0-p648/test/openssl/test_cipher.rb 2016-10-03 21:44:11.051625297 +0100 @@ -128,12 +128,10 @@ } end - def test_AES_crush - 500.times do - assert_nothing_raised("[Bug #2768]") do - # it caused OpenSSL SEGV by uninitialized key - OpenSSL::Cipher::AES128.new("ECB").update "." * 17 - end + def test_update_raise_if_key_not_set + assert_raise(OpenSSL::Cipher::CipherError) do + # it caused OpenSSL SEGV by uninitialized key [Bug #2768] + OpenSSL::Cipher::AES128.new("ECB").update "." * 17 end end end @@ -235,6 +233,23 @@ end end + def test_aes_gcm_key_iv_order_issue + pt = "You should all use Authenticated Encryption!" + cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt + cipher.key = "x" * 16 + cipher.iv = "a" * 12 + ct1 = cipher.update(pt) << cipher.final + tag1 = cipher.auth_tag + + cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt + cipher.iv = "a" * 12 + cipher.key = "x" * 16 + ct2 = cipher.update(pt) << cipher.final + tag2 = cipher.auth_tag + + assert_equal ct1, ct2 + assert_equal tag1, tag2 + end if has_cipher?("aes-128-gcm") end private