This weekend I started work on OpenSSL in JRuby. It’s a pretty big undertaking, and it’s actually worse than I suspected from the beginning, so I’m going to tell a bit about my endeavours and have far I’ve gotten right now. First of all, if someone is interested in the work, I have set up a branch for this, since it will take time and be very big. The branch is called svn://svn.codehaus.org/jruby/branches/openssl.
The approach
I have investigated several variants of implementing OpenSSL in JRuby. One that seemed easy was to find a JNI-library that wraps OpenSSL in Java. But it seems there are no full scale versions implemented anywhere. I also checked around other script-on-JVM-languages to see how they had solved it, but I didn’t find anything close to OpenSSL functionality. Which left me with the approach I’ve decided to try out: implement as OpenSSL compatible Java code as possible with JCE and JSSE. I’m convinced this is doable, but right now it feels quite hard.
The progress
So, how far have I gotten these last days? Pretty far, but not far enough. I’m basing the work on MRI’s test suite for OpenSSL. From those I have test_digest.rb and test_cipher.rb passing all tests. This doesn’t sound like much, but especially test_cipher was a pain to get running.
The plan from hereon is to get the utils.rb-file to load, which means implementing OpenSSL::PKey::RSA and OpenSSL::PKey::DSA, getting the basics of OpenSSL::X509 in place and also find a way to fix OpenSSL::ASN1. Oh well, I’ve got loads of time for this. Or not. =)
The problem
The real problem when implementing this, is the fact that Ruby’s OpenSSL support is… Well, how shall I put it? Thin, you might say. It’s basically a a wrapper around the C-library, which means that the disconnect when implementing this functionality with JCE is quite large. Just translating OpenSSL cipher names to the JCE equivalent is a challenge. But the big problem with the ciphers was initiating the key and IV (initialization vector). I have tried all the PBE solutions available, including the versions in BouncyCastle ending with “-OPENSSL”. No luck.
The problem is that Ruby uses the function called EVP_BytesToKey, which, according to the documentation implements PKCS#5 1.5 with a few tricks up its sleeve. Not very nice. In the end I had to implement my own version of this to generate keys. And since I had to look like mad for this information, I will here give you the implementation to this function in Java. Just use the return value to initialize your own SecretKey-implementation and instantiate an IvParameterSpec and you should be set to go: (note, I release this into the public domain. And note, this is just quick, ported code to show the concept.)
public byte[][] EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data, int count) { byte[][] both = new byte[2][]; byte[] key = new byte[key_len]; int key_ix = 0; byte[] iv = new byte[iv_len]; int iv_ix = 0; both[0] = key; both[1] = iv; byte[] md_buf = null; int nkey = key_len; int niv = iv_len; int i = 0; if(data == null) { return both; } int addmd = 0; for(;;) { md.reset(); if(addmd++ > 0) { md.update(md_buf); } md.update(data); if(null != salt) { md.update(salt,0,8); } md_buf = md.digest(); for(i=1;i<count;i++) { md.reset(); md.update(md_buf); md_buf = md.digest(); } i=0; if(nkey > 0) { for(;;) { if(nkey == 0) break; if(i == md_buf.length) break; key[key_ix++] = md_buf[i]; nkey--; i++; } } if(niv > 0 && i != md_buf.length) { for(;;) { if(niv == 0) break; if(i == md_buf.length) break; iv[iv_ix++] = md_buf[i]; niv--; i++; } } if(nkey == 0 && niv == 0) { break; } } for(i=0;i<md_buf.length;i++) { md_buf[i] = 0; } return both; }

No Comments, Comment or Ping
Reply to “OpenSSL in JRuby”