Your encrypt java version doesn't use the same logic as the javascript version.
The encrypt javascript function takes a password (the argument name key is misleading) and then passes it to createCipher. createCipher doesn't use the password directly, but derives a key from it. It's the derived key that is used to encrypt the message. From NodeJs documentation :
The password is used to derive the cipher key and initialization vector (IV). The value must be either a 'latin1' encoded string, a Buffer, a TypedArray, or a DataView.
The encrypt java function, on the other hand, expects a ready to use key, so you have to do the key derivation from the password yourself.
AES keys have a fixed size. They can only be 128, 192 or 256 bits long. (in bytes 8, 16, 32 bytes long). If you use a key with a different size, you'll get the exception InvalidKeyException. NodeJS didn't complain about an "invalid key length" because in actuality you were using a password, not a key. NodeJS derives a key from the password before encrypting the data.
(as mentioned in the docs) NodeJs uses OpenSSL to encrypt the data and derives the key using a function specific to OpenSSL : EVP_BytesToKey.
Luckily this SO answer has an implementation of EVP_BytesToKey in Java. (The code is originally from this blog entry)
I adapted your code to use it. I added the final result to the end of the answer. I rarely write security code, and in this case I just adapted an existing solution, so you should review the code (or have someone else review it if you have a security team in your company) if you decide to use it.
One final comment : createCipher is deprecated. But you said in your question that you can't change the implementation of the javascript encrypt version. (If you're not the maintainer of encrypt) You should discuss the deprecation issue with the maintainer to understand their reasons for still using createCipher (which uses EVP_BytesToKey). EVP_BytesToKey is considered a weak key derivation function and OpenSSL recommends using more modern functions for newer applications.
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.security.crypto.codec.Hex;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class Main {
public static void main(String[] args){
System.out.println("Result : " + encrypt("my secret message","pass"));
}
public static 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;
}
public static String encrypt(String data, String password) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
var cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
var keySizeBits = 192 / Byte.SIZE; //AES with 192 bits key = 16 bytes
var ivSize = cipher.getBlockSize();
final byte[][] keyAndIV = EVP_BytesToKey(keySizeBits, ivSize, md5, null, password.getBytes(StandardCharsets.US_ASCII), 1);
SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
var cipherText = cipher.update(data.getBytes());
cipherText = ArrayUtils.addAll(cipherText, cipher.doFinal());
return new String(Hex.encode(cipherText));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}