Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encrypt in Ruby and Decrypt in Java - Why is it not working?

What am I doing wrong? I expected the Java program to print "private". My goal is to try to write the MessageEncryptor.decrypt ruby method in Java.

Ruby encryption (most code was taken from MessageEncryptor, but modified not to Marshal), but I've extracted it so that it's easier to see what's going on:

require 'openssl'
require 'active_support/base64'

@cipher = 'aes-256-cbc'
d = OpenSSL::Cipher.new(@cipher)
@secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "some salt", 1024, d.key_len)
cipher = OpenSSL::Cipher::Cipher.new(@cipher)

iv = cipher.random_iv

cipher.encrypt
cipher.key = @secret
cipher.iv = iv

encrypted_data = cipher.update("private")
encrypted_data << cipher.final

puts [encrypted_data, iv].map {|v| ::Base64.strict_encode64(v)}.join("--")

Which printed:

tzFUIVllG2FcYD7xqGPmHQ==--UAPvdm3oN3Hog9ND9HrhEA==

Java code:

package decryptruby;

import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class DecryptRuby {    
    public static String decrypt(String encrypted, String pwd, byte[] salt)
            throws Exception {

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

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

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(pwd.toCharArray(), salt, 1024, 256);
        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 result.toString();
    }


    public static void main(String[] args) throws Exception {
        String encrypted = "tzFUIVllG2FcYD7xqGPmHQ==--UAPvdm3oN3Hog9ND9HrhEA==";

        System.out.println("Decrypted: " + decrypt(encrypted, "password", "some salt".getBytes()));
    }
}

Which printed

Decrypted: [B@432a0f6c

like image 469
Bradford Avatar asked Jun 29 '12 17:06

Bradford


1 Answers

This is the problem - or at least a problem:

byte[] result = cipher.doFinal(encryptedData);
return result.toString();

You're calling toString() on a byte array. Arrays don't override toString(). That won't give you what you want at all - as you can see. Instead, you need to write something like:

return new String(result, "UTF-8");

... but you need to know what encoding was used to turn the original string into bytes before encryption. It's not clear to me from the Ruby code what encoding is used, but if you can be explicit about it (ideally using UTF-8) it'll make your life a lot easier.

In short, I suspect this problem has nothing to do with encryption at all - it has everything to do with converting text to bytes in Ruby and then converting the same sequence of bytes back into a string in Java.

Of course the encryption may be failing as well but that's a different matter.

like image 166
Jon Skeet Avatar answered Oct 06 '22 01:10

Jon Skeet