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]