-2

I have the following simple encryption code running in node.js:

var crypto = require('crypto');

var encKey = "FOO"; // Not the real key. Assume it works though.

var encrypt = function(str) {
  var cipher = crypto.createCipher('aes-256-cbc', encKey);
  var crypted = cipher.update(str, 'utf-8', 'hex');
  crypted += cipher.final('hex');
  return crypted;
};

Which I can also decrypt as below:

var crypto = require('crypto');

var encKey = "FOO"; // Not the real key. Assume it works though.

var decrypt = function(str) {
  var decipher = crypto.createDecipher('aes-256-cbc', encKey);
  var decrypted = decipher.update(str, 'hex', 'utf-8');
  decrypted += decipher.final('utf-8');
  return decrypted;
};

This all works fine. Strings are encrypting and decrypting as expected. But now I am faced with task of decrypting encrypted strings from this node.js code, in Java. And that is where things are going wrong and I am not sure why.

For decryption, My Java code looks like this:

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import java.security.MessageDigest;
import java.util.Arrays;

private static final String encKey = "FOO";
private static SecretKeySpec secretKey;
private static byte[] key;

public static String decrypt(String str) throws Exception {
  String hexDecodedStr = new String(Hex.decodeHex(str.toCharArray()));
  setKey(encKey);
  Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
  cipher.init(Cipher.DECRYPT_MODE, secretKey);
  return new String(cipher.doFinal(hexDecodedStr.getBytes()));
}

private static void setKey(String myKey) throws Exception {
  MessageDigest sha = null;
  try {
    key = myKey.getBytes("UTF-8");
    sha = MessageDigest.getInstance("SHA-1");
    key = sha.digest(key);
    key = Arrays.copyOf(key, 16); 
    secretKey = new SecretKeySpec(key, "AES");
  } 
  catch (Exception e) {
    throw e;
  } 
}

And it doesn't work. It seems like no matter what I try, I end up with some exception on the cipher.doFinal() call, or the String I get back is totally wrong. I know the node.js code is using aes-256-cbc, while the Java code is using AES/ECB/PKCS5Padding instead of AES/CBC/PKCS5Padding, but when I tried to use AES/CBC/PKCS5Padding, it was requiring an InitVector which I didn't have in node.js so I was unsure of how to proceed. Is node making an InitVector under the hood if not provided with one? Am I missing something totally obvious?

8
  • 1
    "I end up with some exception on the cipher.doFinal() call" -- well, share the COMPLETE stack trace please. Commented Jan 1, 2018 at 4:40
  • 1
    Your NodeJS code is so broken. You should probably fix that first. Commented Jan 1, 2018 at 5:01
  • @lukepark there are more things broken :/ Commented Jan 1, 2018 at 5:33
  • @lukepark I am curious to hear more about this broken code, since it is working properly for me. Perhaps I have omitted a line or two from the original source that would help? Commented Jan 1, 2018 at 6:08
  • I mean broken as in invoking undefined behavior. CBC mode should only be used with createCipheriv. What you are doing now is not actually defined anywhere, it could produce different outputs across versions and/or platforms. Not to mention encryption without an IV is insecure and vulnerable to a number of trivial attacks. You should make your NodeJS code secure and correct before translating elsewhere. Commented Jan 1, 2018 at 6:12

1 Answer 1

0

You seems to have the same issue as others OpenSSL encryption failing to decrypt C#

As far I understood the docs, the crypto libeary uses openssl. The openssl creates IV and key from the password using its EVP_BytesToKey function and random salt (not just hash). As dave pointed out, the crypto library uses no salt.

the output of openssl is Salted_{8 bytes salt}{ciphertext} so check what is output of the cipher ( I am unable to do it now)

I wrote a small article how to encrypt properly in Java

Sign up to request clarification or add additional context in comments.

2 Comments

nodejs crypto uses OpenSSL library, per the doc for createCipher including EVP_BytesToKey without salt, but not OpenSSL commandline and thus not the file format with Salted__.
@dave_thompson_085 thank you for pointing out. IMHO that's pretty dangerous (mainly for people who don't know what are they doing. Maybe createCipheriv would be safer to use

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.