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

时间:2021-11-10 18:22:47

I am trying to encode in nodejs and decryption for the same in nodejs works well. But when I try to do the decryption in Java using the same IV and secret, it doesn't behave as expected.

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

Here is the code snippet:

这是代码片段:

Encryption in nodeJs:

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

And the output is:

输出是:

<Buffer 94 fa a4 f4 a1 3c bf f6 d7 90 18 3f 3b db 3f b9>
94faa4f4a13cbff6d790183f3bdb3fb9:fae8b07a135e084eb91e

Code Snippet for decryption in JAVA:

用于在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));
    }
}

Output: �s˸8ƍ�

I am getting some junk value in the response. Tried a lot of options, but none of them seem to be working. Any lead/help is appreciated.

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

2 个解决方案

#1


2  

In your JS code, you're using the 32-character string d6F3231q7d19428743234@123nab@234 directly as the AES key, with each ASCII character directly mapped to a single key byte.

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

In the Java code, you're instead first hashing the same string with MD5, and then using the MD5 output as the AES key. It's no wonder that they won't match.

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

What you probably should be doing, in both cases, is either:

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

  1. randomly generating a string of 32 bytes (most of which won't be printable ASCII characters) and using it as the key; or
  2. 随机生成一个32字节的字符串(其中大部分不是可打印的ASCII字符)并将其用作密钥;要么

  3. using a key derivation function (KDF) to take an arbitrary input string and turn it into a pseudorandom AES key.
  4. 使用密钥派生函数(KDF)获取任意输入字符串并将其转换为伪随机AES密钥。

In the latter case, if the input string is likely to have less than 256 bits of entropy (e.g. if it's a user-chosen password, most of which only have a few dozen bits of entropy at best), then you should make sure to use a KDF that implements key stretching to slow down brute force guessing attacks.

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

#2


2  

In the Java code you are taking the MD5 hash of secret before using it as a key:

在Java代码中,在将其用作密钥之前,您将获取秘密的MD5哈希值:

MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(secretBytes);
SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");

Whereas, in your NodeJS code, you don't do this anywhere. So you're using two different keys when encrypting and decrypting.

然而,在您的NodeJS代码中,您不会在任何地方执行此操作。因此,在加密和解密时,您使用了两个不同的密钥。

Don't copy and paste code without understanding it. Especially crypto code.

不要在不理解代码的情况下复制和粘贴代码。特别是加密代码。

#1


2  

In your JS code, you're using the 32-character string d6F3231q7d19428743234@123nab@234 directly as the AES key, with each ASCII character directly mapped to a single key byte.

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

In the Java code, you're instead first hashing the same string with MD5, and then using the MD5 output as the AES key. It's no wonder that they won't match.

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

What you probably should be doing, in both cases, is either:

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

  1. randomly generating a string of 32 bytes (most of which won't be printable ASCII characters) and using it as the key; or
  2. 随机生成一个32字节的字符串(其中大部分不是可打印的ASCII字符)并将其用作密钥;要么

  3. using a key derivation function (KDF) to take an arbitrary input string and turn it into a pseudorandom AES key.
  4. 使用密钥派生函数(KDF)获取任意输入字符串并将其转换为伪随机AES密钥。

In the latter case, if the input string is likely to have less than 256 bits of entropy (e.g. if it's a user-chosen password, most of which only have a few dozen bits of entropy at best), then you should make sure to use a KDF that implements key stretching to slow down brute force guessing attacks.

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

#2


2  

In the Java code you are taking the MD5 hash of secret before using it as a key:

在Java代码中,在将其用作密钥之前,您将获取秘密的MD5哈希值:

MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(secretBytes);
SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");

Whereas, in your NodeJS code, you don't do this anywhere. So you're using two different keys when encrypting and decrypting.

然而,在您的NodeJS代码中,您不会在任何地方执行此操作。因此,在加密和解密时,您使用了两个不同的密钥。

Don't copy and paste code without understanding it. Especially crypto code.

不要在不理解代码的情况下复制和粘贴代码。特别是加密代码。