I'm trying to port the Java code for AES ECB encryption into node.js
The issues is that the output from java and node are not the same.
Here's the java code
public static final String DEFAULT_ENCODING = "UTF-8";
public static final String SEC_PROVIDER = "SunJCE";
public static final String AES_ALGORITHM = "AES";
public static final String RIJNDAEL_CIPHER = **"Rijndael/ECB/NoPadding"**;
public static final int **CIPHER_PAD_SIZE = 32**;
public static final String HEX_KEY = "3b6ce332ca3b6519eac769710f41ca5c";
public static String encryptData(String text, String hexKey) throws
Exception {
byte[] b1 = Hex.decodeHex(HEX_KEY.toCharArray());
SecretKey key = new SecretKeySpec(b1, AES_ALGORITHM);
Cipher cipher = Cipher.getInstance(RIJNDAEL_CIPHER, SEC_PROVIDER);
text = padRightToMod(text, CIPHER_PAD_SIZE);
byte[] buf = text.getBytes(DEFAULT_ENCODING);
cipher.init(Cipher.ENCRYPT_MODE, key);
buf = cipher.doFinal(buf);
String result = new String(Hex.encodeHex(buf));
result = result.toUpperCase();
return result;
}
// ensure block size of 32
public static String padRightToMod(String text, int mod) {
if (text == null || mod <= 0) {
return text;
}
final int len = text.length();
StringBuilder buf = new StringBuilder(512);
buf.append(text);
for (int i = len; i % mod > 0; i++) {
buf.append(" ");
}
String rs = buf.toString();
System.out.println(rs.length());
return rs;
}
// Call to the encrypt function
String encText = encryptData("Hello", HEX_KEY);
The result is CC0AC95B5FFD4758DBFA40F909C285F0F86A8F19ED1A12C1BFC098348A2AC683
And with this javascript code
crypto = require('crypto');
function encrypt(data,key) {
var cipher = crypto.createCipher('**aes-128-ecb**', key); //create aes cipher
var encrypted = cipher.update(data,'utf8', 'hex'); //output as hex
return encrypted;
}
function padRightTo32(str) // ensure block size of 32
{
len=str.length;
for(i=len; i%32>0; i++){
str=str +" ";
}
return str;
}
// call to encryption function
hexkey="3b6ce332ca3b6519eac769710f41ca5c"
encStr=encrypt(padRightTo32("Hello"),hexKey);
console.log(encStr);
The result is 1B928CF3C18D53BA5138DD1484D181939FD2B7BB2A17AE6A79664488B5C12652
==== Update ======
I tried https://github.com/Snack-X/rijndael-js implementaiton form github with this code
const Rijndael = require("./node_modules/node-rijndael-master");
function padRightTo32(str)
{
len=str.length;
for(i=len; i%32>0; i++){
str=str +" ";
}
console.log(str);
console.log(str.length);
return str;
}
let key = "3b6ce332ca3b6519eac769710f41ca5c";
let original = padRightTo32("Hello");
let cipher = new Rijndael(key, "ecb");
let ciphertext = cipher.encrypt(original, 128);
console.log(ciphertext.toString("hex"));
I get this result e97282fb5838a9c78e6df1f1b4aad108aa010418ec573d74b9c991f4e897e752 but not the encrypted text that Iget from in java. Trying the 256 block size doesn't help either.
what I'm missing that is resulting in a different output?
Concerning your key you have to convert your hex-string into binary data using a buffer (see e.g. Encrypt binary data with aes-ecb on node.js).
Moreover, you have to use the method crypto.createCipheriv
to instantiate the cipher (see e.g. https://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options).
The currently used (deprecated) method crypto.creataCipher
expects a password and generates the key from the password (see e.g. https://nodejs.org/api/crypto.html#crypto_crypto_createcipher_algorithm_password_options).
The following code
crypto = require('crypto');
function encrypt(data,key) {
var cipher = crypto.createCipheriv('aes-128-ecb', key,''); //create aes-128 cipher
var encrypted = cipher.update(data,'utf8', 'hex'); //output as hex
return encrypted;
}
function padRightTo32(str) { // ensure block size of 32
len=str.length;
for(i=len; i%32>0; i++) {
str=str +" ";
}
return str;
}
// call to encryption function
var hexKey = new Buffer('3b6ce332ca3b6519eac769710f41ca5c', 'hex'); // 16 Byte-key
encStr=encrypt(padRightTo32("Hello"),hexKey);
console.log(encStr);
has the output
cc0ac95b5ffd4758dbfa40f909c285f0f86a8f19ed1a12c1bfc098348a2ac683
which is equal to the output of the Java code.
In Java the length of the key defines the used AES-variant, e.g. if you choose a 16-Byte key AES-128 is used, if a 32-Byte key is chosen, AES-256 is used.
In the nodejs-code you have to explicitly specifiy the AES-variant, i.e. aes-128-ecb
for a 16-Byte key, and aes-256-ecb
for a 32-Byte key etc.
As already mentioned in the comments ECB
in't a secure mode (see e.g. https://crypto.stackexchange.com/questions/20941/why-shouldnt-i-use-ecb-encryption).
I don't know if there is really a difference between Rijndael/ECB/NoPadding
and AES/ECB/NoPadding
concerning the cipher-instantiation in Java. In my testcases at least the results are identical. Thus, for the nodejs-code the selection of aes-128-ecb
(for 16-Byte key) or aes-256-ecb
(for 32-Byte keys) should work.