简体   繁体   中英

decryptAES from Java to node.js

I have a Java algorithm for AES encryption and decryption and have to realize the decryption in JavaScript.

public String encryptWithAES(String value, String key, String encoding) throws NoSuchAlgorithmException, NoSuchPaddingException, DecoderException, UnsupportedEncodingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    byte[] keyBytes = Hex.decodeHex(key.toLowerCase().toCharArray());
    byte[] dataToSend = value.getBytes(encoding);
    Cipher c = Cipher.getInstance("AES");
    SecretKeySpec k = new SecretKeySpec(keyBytes, "AES");
    c.init(1, k);
    byte[] encryptedData = c.doFinal(dataToSend);
    return new String(Hex.encodeHex(encryptedData));
}

public String decryptAES(String encrypted, String key, String encoding) throws NoSuchAlgorithmException, NoSuchPaddingException, DecoderException, UnsupportedEncodingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    byte[] keyBytes = Hex.decodeHex(key.toCharArray());
    byte[] encryptedData = Hex.decodeHex(encrypted.toCharArray());
    Cipher c = Cipher.getInstance("AES");
    SecretKeySpec k = new SecretKeySpec(keyBytes, "AES");
    c.init(2, k);
    byte[] dencryptedData = c.doFinal(encryptedData);
    return new String(dencryptedData, encoding);
}

I have found many examples in the Internet, but no one gave me a proper result.

Now I try decrypt with that code:

var algos = ['aes-128-cbc', 'aes-128-cfb', 'aes-128-cfb1', 'aes-128-cfb8', 'aes-128-ctr', 'aes-128-ecb', 'aes-128-gcm', 'aes-128-ofb', 'aes-128-xts', 'aes-256-cbc', 'aes-256-cfb', 'aes-256-cfb1', 'aes-256-cfb8', 'aes-256-ctr', 'aes-256-ecb', 'aes-256-gcm', 'aes-256-ofb', 'aes-256-xts', 'aes128', 'aes256'];
//var masterData - string like 'c07abe96dde490b3aba7d2f21a43ba94960619ff110ffb53433f0ff39f4cf138e48511b1fb4030'
//const ENCRYPTION_KEY - string like '94960619ff110ffb53433f0ff39f4cf1' with 32 symbols

function decrypt(text, algorithm) {
    var decipher = crypto.createDecipher(algorithm, ENCRYPTION_KEY);

    var dec = decipher.update(text, 'hex', 'utf8');

    dec += decipher.final('utf8');
    return dec;
}

algos.map(algo => {
    try {
        const dec = decrypt(masterData, algo);

        console.log(algo, dec);
    } catch (error) {
        console.log(algo, 'error', error);
    }
});

Encoded string is a JSON.

This is really insecure code and should never be used.

Cipher.getInstance("AES"); is not fully specified and may result in different ciphers depending on the default security provider. It most likely results in "AES/ECB/PKCS5Padding" , but it doesn't have to be. If it changes, you'll lose compatibility between different JVMs.
Always use a fully qualified Cipher string.

So the first thing that you should try is to limit your cipher to those with ECB mode. Node.js' crypto module automatically applies PKCS#5/PKCS#7 padding, so you don't have to do anything special in that regard.

Next up is the key. Your example key is 32 characters long. Since it's supposed to be Hex-encoded if we look into the Java code, it means that the key is actually only 16 bytes (octets) or 128 bits long. You need to decode the key from Hex before you use it.

Another problem is that crypto.createDecipher expects a password as a parameter, but you seem to have a key. In that case, you need to use crypto.createDecipheriv . Please don't confuse passwords and keys. They have vastly different properties, but the good thing is that you can usually derive a key from a password. See this for more information: How to securely hash passwords?

As I said before, Java uses padding. Many modes of operation need padding in order to encrypt arbitrarily long plaintext. One of them is the ECB mode. Padding adds between 1 to 16 bytes (16 bytes is the block size of AES). This means that your ciphertext must have a multiple of 32 characters (Hex-encoded). If it doesn't it isn't valid ciphertext.

Untested code because the example ciphertext is invalid:

var crypto = require('crypto');

var masterData = '...'; // multiple of 32 characters!
var ENCRYPTION_KEY = '94960619ff110ffb53433f0ff39f4cf1';

function decrypt(text, key) {
    var decipher = crypto.createDecipheriv('aes-128-ecb', new Buffer(key, 'hex'), '');

    var dec = decipher.update(text, 'hex', 'utf8');

    dec += decipher.final('utf8');
    return dec;
}

console.log(decrypt(masterData, ENCRYPTION_KEY));

This code is really insecure: Uses ECB mode, not randomized, no authentication! You should not use this crypto code at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM