Inconsistencies in encryption between Java and Node

262 views Asked by At

I'm trying to replicate a Java-based encryption scheme in Node.js but unfortunately I'm getting inconsistent results.

Here's the Java method:

private Transfer encrypt(byte[] salt, String ticketNumber, String data) throws Exception {
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(ticketNumber.toCharArray(), salt, 1000, 128);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
    String encoded = java.util.Base64.getEncoder().encodeToString(secret.getEncoded());
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    IvParameterSpec ips = new IvParameterSpec(iv);
    cipher.init(Cipher.ENCRYPT_MODE, secret, ips);
    AlgorithmParameters params = cipher.getParameters();
    Transfer myRetVal =  new Transfer();
    byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();

    //Set some decrypt information
    myRetVal.setIv(Base64.encodeBase64String(ivBytes));
    //Set the attendee data
    myRetVal.setData(Base64.encodeBase64String(cipher.doFinal(data.getBytes())));
    //Set the hashed Ticket number
    myRetVal.setTicketNumberHashed(Base64.encodeBase64String(getHash(hashIterations, ticketNumber, salt)));
    return myRetVal;
}

And my Node version:

exports.getEncryptedString = function(salt, password, data) {
  var iv = new Buffer('0000000000000000');
  var key = crypto.pbkdf2Sync(password, salt, 1000, 16, 'sha1');
  var cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
  return cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
};

When I pass both functions the string "SomeJSON" and the same key I get different encrypted results.

From Java: ENnQzWowzrl7LQchRmL7sA== From Node: TGreJNmQH92gHb1bSy4xAA==

I can't figure out what is different in my Node implementation.

1

There are 1 answers

0
Artjom B. On BEST ANSWER

new Buffer('0000000000000000') uses utf8 encoding by default, but "0" in UTF-8 is the byte 0x30 whereas in Java you're using 0x00 bytes for the IV. What you want is either

var iv = new Buffer('00000000000000000000000000000000', 'hex');

or

var iv = new Buffer(16);
iv.fill(0);

After you've done your tests, you should change the procedure to generate a new IV for every encryption. The IV doesn't have to be secret, so you can simply prepend it to the ciphertext. When you want to decrypt it later, you can slice the IV off (16 bytes for AES) and use it during decryption.