AES encryption in Ruby and Decryption in Java

9 years ago
This one is precious, as it took me a long time to figure out. As a side-note, Java apparently only supports 128bit AES.

Here's the Ruby code:

def encrypt(string, pwd)
    salt = OpenSSL::Random.random_bytes(16)

    # prepare cipher for encryption
    e = OpenSSL::Cipher.new('AES-128-CBC')
    e.encrypt

    # next, generate a PKCS5-based string for your key + initialization vector
    key_iv = OpenSSL::PKCS5.pbkdf2_hmac_sha1(pwd, salt, 1024, e.key_len+e.iv_len)
    key = key_iv[0, e.key_len]
    iv  = key_iv[e.key_len, e.iv_len]

    # now set the key and iv for the encrypting cipher
    e.key = key
    e.iv  = iv

    # encrypt the data!
    encrypted = '' << e.update(string) << e.final
    [encrypted, iv, salt].map {|v| ::Base64.strict_encode64(v)}.join("--")   
 end

And the Java part:

public static String decrypt(String encrypted, String pwd) throws Exception {

        String[] parts = encrypted.split("--");
        if (parts.length != 3) return null;

        byte[] encryptedData = Base64.decodeBase64(parts[0]);
        byte[] iv = Base64.decodeBase64(parts[1]);
        byte[] salt = Base64.decodeBase64(parts[2]);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(pwd.toCharArray(), salt, 1024, 128);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey aesKey = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv));

        byte[] result = cipher.doFinal(encryptedData);
        return new String(result, "UTF-8");
}