节点JS中的AES-256-CTR加密和Java中的解密

Ash*_*dey 8 java security encryption cryptography node.js

我试图在nodejs中编码,并且在nodejs中解密相同效果很好.但是当我尝试使用相同的IV和秘密在Java中进行解密时,它的行为并不像预期的那样.

这是代码片段:

nodeJs中的加密:

var crypto = require('crypto'),
algorithm = 'aes-256-ctr',
_ = require('lodash');

var secret = 'd6F3231q7d19428743234@123nab@234';

function encrypt(text, secret) {
    var iv = crypto.randomBytes(16);
    console.log(iv);
    var cipher = crypto.createCipheriv(algorithm, new Buffer(secret), iv);
    var encrypted = cipher.update(text);

    encrypted = Buffer.concat([encrypted, cipher.final()]);

    return iv.toString('hex') + ':' + encrypted.toString('hex');
}
var encrypted = encrypt("8123497494", secret);
console.log(encrypted);
Run Code Online (Sandbox Code Playgroud)

输出是:

<Buffer 94 fa a4 f4 a1 3c bf f6 d7 90 18 3f 3b db 3f b9>
94faa4f4a13cbff6d790183f3bdb3fb9:fae8b07a135e084eb91e
Run Code Online (Sandbox Code Playgroud)

用于在JAVA中解密的代码片段:

public class Test {

    public static void main(String[] args) throws Exception {
        String s = "94faa4f4a13cbff6d790183f3bdb3fb9:fae8b07a135e084eb91e";
        String seed = "d6F3231q7d19428743234@123nab@234";

        decrypt(s, seed);
    }

    private static void decrypt(String s, String seed)
            throws NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        String parts[] = s.split(":");
        String ivString = parts[0];
        String encodedString = parts[1];
        Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

        byte[] secretBytes = seed.getBytes("UTF-8");

        IvParameterSpec ivSpec = new IvParameterSpec(hexStringToByteArray(ivString));

        /*Removed after the accepted answer
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] thedigest = md.digest(secretBytes);*/ 

        SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");

        cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);
        byte[] output = cipher.doFinal(hexStringToByteArray(encodedString));

        System.out.println(new String(output));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出: s˸8ƍ

我在回复中得到了一些垃圾值.尝试了很多选择,但它们似乎都没有起作用.任何领导/帮助表示赞赏.

Ilm*_*nen 4

在您的 JS 代码中,您使用的是 32 个字符的字符串d6F3231q7d19428743234@123nab@234直接使用 32 个字符的字符串作为 AES 密钥,每个 ASCII 字符直接映射到单个密钥字节。

在 Java 代码中,您首先使用 MD5 对同一字符串进行哈希处理,然后使用 MD5 输出作为 AES 密钥。难怪他们不匹配。

在这两种情况下,您可能应该做的是:

  1. 随机生成一个 32 字节的字符串(其中大部分不会是可打印的 ASCII 字符)并将其用作密钥;或者
  2. 使用密钥派生函数 (KDF)获取任意输入字符串并将其转换为伪随机 AES 密钥。

在后一种情况下,如果输入字符串的熵可能少于 256 位(例如,如果它是用户选择的密码,其中大多数最多只有几十位熵),那么您应该确保使用实现密钥拉伸的KDF来减缓暴力猜测攻击。


诗。为了解决下面的问题,MD5 输出一个 16 字节的摘要,当用作 AES SecretKeySpec 时,它将生成 AES-128 密钥。要在 Java 中使用 AES-256,您需要提供 32 字节密钥。如果尝试在 Java 中使用 32 字节 AES 密钥会引发 InvalidKeyException,则您可能使用的是旧版本的 Java,其加密策略有限,不允许加密密钥长于 128 位。正如链接问题的答案所述,您需要升级到 Java 8 更新 161 或更高版本,或者获取并安装适用于您的 Java 版本的无限制加密策略文件。