【问题标题】:decryptAES from Java to node.js从 Java 解密 AES 到 node.js
【发布时间】:2016-08-10 09:22:43
【问题描述】:

我有一个用于AES加密和解密的Java算法,必须在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);
}

我在网上找了很多例子,但没有人给我一个合适的结果。

现在我尝试使用该代码进行解密:

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);
    }
});

编码后的字符串是 JSON。

【问题讨论】:

标签: javascript java node.js encryption aes


【解决方案1】:

这是非常不安全的代码,不应该使用。

Cipher.getInstance("AES"); 未完全指定,可能会根据默认安全提供程序产生不同的密码。它最有可能导致"AES/ECB/PKCS5Padding",但并非必须如此。如果它发生变化,您将失去不同 JVM 之间的兼容性。
始终使用完全限定的密码字符串。

因此,您应该尝试的第一件事是将密码限制为使用 ECB 模式的密码。 Node.js 的加密模块会自动应用 PKCS#5/PKCS#7 填充,因此您不必在这方面做任何特别的事情。

接下来是关键。您的示例密钥长度为 32 个字符。如果我们查看 Java 代码,它应该是十六进制编码的,这意味着密钥实际上只有 16 个字节(八位字节)或 128 位长。您需要在使用之前从 Hex 解码密钥。

另一个问题是crypto.createDecipher 需要密码作为参数,但您似乎有一个密钥。在这种情况下,您需要使用crypto.createDecipheriv。请不要混淆密码和密钥。它们具有截然不同的属性,但好处是您通常可以从密码中获取密钥。更多信息请参见:How to securely hash passwords?

正如我之前所说,Java 使用填充。许多操作模式需要填充以加密任意长的明文。其中之一是欧洲央行模式。填充增加了 1 到 16 个字节(16 个字节是 AES 的块大小)。这意味着您的密文必须是 32 个字符的倍数(十六进制编码)。如果不是,则不是有效的密文。

未经测试的代码,因为示例密文无效:

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));

这段代码真的很不安全:使用ECB模式,不是随机的,没有认证!你根本不应该使用这个加密代码。

【讨论】:

    猜你喜欢
    • 2017-04-15
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-06
    • 2015-10-31
    • 2018-11-13
    • 1970-01-01
    相关资源
    最近更新 更多