High severity7.5NVD Advisory· Published Jan 30, 2017· Updated May 13, 2026
CVE-2016-7798
CVE-2016-7798
Description
The openssl gem for Ruby uses the same initialization vector (IV) in GCM Mode (aes-*-gcm) when the IV is set before the key, which makes it easier for context-dependent attackers to bypass the encryption protection mechanism.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
opensslRubyGems | < 2.0.0 | 2.0.0 |
Patches
18108e0a6db13cipher: don't set dummy encryption key in Cipher#initialize
2 files changed · +36 −18
ext/openssl/ossl_cipher.c+13 −12 modified@@ -36,7 +36,7 @@ */ VALUE cCipher; VALUE eCipherError; -static ID id_auth_tag_len; +static ID id_auth_tag_len, id_key_set; static VALUE ossl_cipher_alloc(VALUE klass); static void ossl_cipher_free(void *ptr); @@ -118,7 +118,6 @@ ossl_cipher_initialize(VALUE self, VALUE str) EVP_CIPHER_CTX *ctx; const EVP_CIPHER *cipher; char *name; - unsigned char dummy_key[EVP_MAX_KEY_LENGTH] = { 0 }; name = StringValueCStr(str); GetCipherInit(self, ctx); @@ -129,16 +128,7 @@ ossl_cipher_initialize(VALUE self, VALUE str) if (!(cipher = EVP_get_cipherbyname(name))) { ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str); } - /* - * EVP_CipherInit_ex() allows to specify NULL to key and IV, however some - * ciphers don't handle well (OpenSSL's bug). [Bug #2768] - * - * 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. - */ - if (EVP_CipherInit_ex(ctx, cipher, NULL, dummy_key, NULL, -1) != 1) + if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) ossl_raise(eCipherError, NULL); return self; @@ -251,6 +241,9 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode) ossl_raise(eCipherError, NULL); } + if (p_key) + rb_ivar_set(self, id_key_set, Qtrue); + return self; } @@ -337,6 +330,8 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) OPENSSL_cleanse(key, sizeof key); OPENSSL_cleanse(iv, sizeof iv); + rb_ivar_set(self, id_key_set, Qtrue); + return Qnil; } @@ -387,6 +382,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) 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) @@ -488,6 +486,8 @@ ossl_cipher_set_key(VALUE self, VALUE key) 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; } @@ -1082,4 +1082,5 @@ Init_ossl_cipher(void) rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1); id_auth_tag_len = rb_intern_const("auth_tag_len"); + id_key_set = rb_intern_const("key_set"); }
test/test_cipher.rb+23 −6 modified@@ -90,6 +90,7 @@ def test_key_iv_set def test_empty_data @c1.encrypt + @c1.random_key assert_raise(ArgumentError){ @c1.update("") } end @@ -136,12 +137,10 @@ def test_AES } 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 @@ -317,6 +316,24 @@ def test_aes_ocb_tag_len } end if has_cipher?("aes-128-ocb") + def test_aes_gcm_key_iv_order_issue + pt = "[ruby/openssl#49]" + 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") + private def new_encryptor(algo)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
12- www.openwall.com/lists/oss-security/2016/09/30/6nvdMailing ListPatchThird Party AdvisoryWEB
- github.com/ruby/openssl/commit/8108e0a6db133f3375608303fdd2083eb5115062nvdPatchThird Party AdvisoryWEB
- github.com/ruby/openssl/issues/49nvdExploitThird Party AdvisoryWEB
- www.openwall.com/lists/oss-security/2016/09/19/9nvdMailing ListThird Party AdvisoryWEB
- www.openwall.com/lists/oss-security/2016/10/01/2nvdMailing ListThird Party AdvisoryWEB
- www.securityfocus.com/bid/93031nvdThird Party AdvisoryVDB Entry
- github.com/advisories/GHSA-6h88-qjpv-p32mghsaADVISORY
- lists.debian.org/debian-lts-announce/2018/07/msg00012.htmlnvdMailing ListThird Party AdvisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2016-7798ghsaADVISORY
- www.debian.org/security/2017/dsa-3966nvdThird Party AdvisoryWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/openssl/CVE-2016-7798.ymlghsaWEB
- web.archive.org/web/20210121065227/https://www.securityfocus.com/bid/93031/infoghsaWEB
News mentions
0No linked articles in our index yet.