From: T P Date: 2012-06-11T06:52:34+09:00 Subject: OpenSSL: Determining initialization vector (IV) created using OpenSSL::Cipher::Cipher#pkcs5_keyivgen with one argument --14dae9340e05cfd25f04c2253f71 Content-Type: text/plain; charset=ISO-8859-1 Hi, I am attempting to understand some legacy Ruby code that I must write a service to interact on the backend (my service will be in Scala, but I am very handy with Ruby generally). The Ruby code in question uses the encrypted_strings gem which was used to populate a large database of encrypted fields in a database (running in production). My goal is to send the encrypted values to the new Scala/JVM-based service so that it can establish connections after decrypting the fields to another service. Under the covers encrypted_strings Ruby gem calls OpenSSL::Cipher::Cipher#pkcs5_keyivgen with just the password. This is a Ruby/C function[1] that is essentially called. ----- start source static VALUEossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self){ EVP_CIPHER_CTX *ctx; const EVP_MD *digest; VALUE vpass, vsalt, viter, vdigest; unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL; int iter; rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest); StringValue(vpass); if(!NIL_P(vsalt)){ StringValue(vsalt); if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN) ossl_raise(eCipherError, "salt must be an 8-octet string"); salt = (unsigned char *)RSTRING_PTR(vsalt); } iter = NIL_P(viter) ? 2048 : NUM2INT(viter); digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest); GetCipher(self, ctx); EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt, (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv); if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1) ossl_raise(eCipherError, NULL); OPENSSL_cleanse(key, sizeof key); OPENSSL_cleanse(iv, sizeof iv); return Qnil;} ----- end source I realize this method is only PKCS5 v1.5 compliant (rather than 2.0 compliant) and that we should not be using it, but the conversion to setting a known random initialization vector (IV) is in a medium/long term phase. What I would like to be able to figure out in the near-term is: (a) how to read the C code above. From my rusty understanding of general C and virtually zero understanding (despite attempting to find Ruby/C docs but they appear to be out of date?) of Ruby/C APIs The salt variable should still be NULL since now vsalt (second argument) was created. (b) at some point I would love to learn how to debug this myself. i.e. setup my environment to trace the C code in the Ruby MRI runtime so I can fish for myself next time. If the salt variable is NULL then what is the IV used in this case? I need th IV for the Scala code otherwise I cannot decrypt what the Ruby code is encrypting. Also I found a highly related StackOverflow question on this [2], but the solution involves not using pkcs5_keyivgen method at all and setting a known random IV on the OpenSSL::Cipher::Cipher object so it doesn't answer my question sadly as I am not in a position to do this migration yet. Any pointers on this would be much appreciated. Cheers, Susan [1] https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_cipher.c#L302-330 [2] http://stackoverflow.com/questions/10909871/encrypt-by-des-ede3-cbc-in-ruby-and-decrypt-in-java --14dae9340e05cfd25f04c2253f71 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
Hi,

I am attempting to understand some le= gacy Ruby code that I must write a service to interact on the backend (my s= ervice will be in Scala, but I am very handy with Ruby generally). The Ruby= code in question uses the encrypted_strings gem which was used to populate= a large database of encrypted fields in a database (running in production)= . My goal is to send the encrypted values to the new Scala/JVM-based servic= e so that it can establish connections after decrypting the fields to anoth= er service.

Under the covers encrypted_strings Ruby gem calls OpenS= SL::Cipher::Cipher#pkcs5_keyivgen with just the password. This is a Ruby/C = function[1] that is essentially called.=A0

----- s= tart source
static VALUE
ossl_cipher_pkcs5_keyivge=
n(int argc, VALUE *argv, VALUE self)
{
    EVP_CIPHER_CTX<=
/span> *ctx;
    const EVP_MD *digest;
    VALUE vpass, vsalt, viter, vdigest;
    unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt =3D NULL;
    int iter;

    rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
    StringValue(<=
/span>vpass);
    i=
f(!NIL_P=
(vsalt)){
        StringValue=
(vsalt);
        if(RSTR=
ING_LEN(vsalt)=
 !=3D PKCS=
5_SALT_LEN)
            ossl_raise(=
eCipherError, =
"salt must be an=
 8-octet string");
        salt =3D=
 (unsigned char *)RSTRING_PTR(vsalt);
    }=

    iter =3D NIL_P(viter) ? 2048 : NUM2INT(viter);
    digest =3D <=
span class=3D"constant" style=3D"color:rgb(0,119,255)">NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest);
    GetCipher(self, =
ctx);
    EVP_BytesToKey<=
/span>(EVP_CIPHER=
_CTX_cipher(ctx<=
/span>), digest<=
span class=3D"punct" style=3D"color:rgb(68,68,119);font-weight:bold">, salt,
                   (uns=
igned char =
*)RSTRING_PTR(<=
/span>vpass), RSTRING_LENINT=
(vpass), iter, key, iv);
    i=
f (EVP_Cip=
herInit_ex(ctx=
, NULL, NULL,=
 key, iv, -1) !=3D 1)
        ossl_raise=
(eCipherError,=
 NULL);
    OPENSSL_cleanse=
(key, <=
span class=3D"ident" style=3D"color:rgb(0,0,68)">sizeof key);
    OPENSSL_cleanse=
(iv, sizeof iv);

    r=
eturn Qnil=
;
}
=
----- end source

I realize= this method is only PKCS5 v1.5 compliant (rather than 2.0 compliant) and t= hat we should not be using it, but the conversion to setting a known random= initialization vector (IV) is in a medium/long term phase. What I would li= ke to be able to figure out in the near-term is:

(a) how to read the C code above. From my rusty underst= anding of general C and virtually zero understanding (despite attempting to= find Ruby/C docs but they appear to be out of date?) of Ruby/C APIs The sa= lt variable should still be NULL since now vsalt (second argument) was crea= ted.
(b) at some point I would love to learn how to debug this myself. i.e.= setup my environment to trace the C code in the Ruby MRI runtime so I can = fish for myself next time.

If the salt variable is= NULL then what is the IV used in this case? I need th IV for the Scala cod= e otherwise I cannot decrypt what the Ruby code is encrypting. Also I found= a highly related StackOverflow question on this [2], but the solution invo= lves not using pkcs5_keyivgen method at all and setting a known random IV o= n the OpenSSL::Cipher::Cipher object so it doesn't answer my question s= adly as I am not in a position to do this migration yet.

Any pointers on this would be much appreciated.

Cheers,
Susan


[1]=A0https://github.com/ruby/ruby/blob/trunk/ext/openss= l/ossl_cipher.c#L302-330
[2]=A0http://stackoverflow.com/questi= ons/10909871/encrypt-by-des-ede3-cbc-in-ruby-and-decrypt-in-java
--14dae9340e05cfd25f04c2253f71--