Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AES-256-CTR Encryption in node JS and decryption in Java

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.

Here is the code snippet:

Encryption in nodeJs:

   var crypto = require('crypto'),
   algorithm = 'aes-256-ctr',
   _ = require('lodash'),
   secret = 'd6F3231q7d1942874322a@123nab@392';

  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:

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

        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.

like image 902
Ashish Pandey Avatar asked Feb 16 '18 15:02

Ashish Pandey


People also ask

Is AES 256 CTR secure?

Originally adopted by the federal government, AES encryption has become the industry standard for data security. AES comes in 128-bit, 192-bit, and 256-bit implementations, with AES 256 being the most secure.

How do I encrypt and decrypt data in node JS?

NodeJS provides inbuilt library crypto to encrypt and decrypt data in NodeJS. We can use this library to encrypt data of any type. You can do the cryptographic operations on a string, buffer, and even a stream of data. The crypto also holds multiple crypto algorithms for encryption.

Which algorithm is best for encryption and decryption in Java?

The Advanced Encryption Standard (AES, Rijndael) is a block cipher encryption and decryption algorithm, the most used encryption algorithm in the worldwide. The AES processes block of 128 bits using a secret key of 128, 192, or 256 bits.

What is AES 256 encryption in Java?

Java programming provides security for data transfer as well as communication between several nodes by supporting different encryption and hashing algorithms. In this section, we will discuss the AES 256 encryption algorithm and implement the logic in a Java program. What is AES? AES is an Advanced Encryption Standard algorithm.

How many rounds of AES encryption are there in Node JS?

AES uses 10 rounds for 128-bit keys, 12 rounds for 192-bit keys and 14 rounds for 256-bit keys. Each of these rounds uses a different 128-bit round key, which is calculated from the original AES key. Not going deep in AES encryption . Lets discuss how we can encrypt data in node js using AES encryption.

How to encrypt and decrypt data in Node JS?

AES Encryption & Decryption Data in Node.js. Node.js provides built-in library called crypto for cryptographic operations. We can do encryption on Streams, Strings, Arrays and Buffers. To install crypto module use below command in your project : npm install crypto --save. Lets see example to encrypt data using crypto module in node js.

What is a simple AES key size?

AES is an Advanced Encryption Standard algorithm. It is a type of symmetric, block cipher encryption and decryption algorithm. It works with key size 128, 192, and 256 bits. It uses a valid and similar secret key for both encryption and decryption.


2 Answers

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.

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.

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. using a key derivation function (KDF) to take an arbitrary input string and turn it into a pseudorandom AES key.

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.


Ps. To address the comments below, MD5 outputs a 16-byte digest, which will yield an AES-128 key when used as an AES SecretKeySpec. To use AES-256 in Java, you will need to provide a 32-byte key. If trying to use a 32-byte AES key in Java throws an InvalidKeyException, you are probably using an old version of Java with a limited crypto policy that does not allow encryption keys longer than 128 bits. As described this answer to the linked question, you will either need to upgrade to Java 8 update 161 or later, or obtain and install an unlimited crypto policy file for your Java version.

like image 175
Ilmari Karonen Avatar answered Sep 21 '22 09:09

Ilmari Karonen


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

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.

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

like image 37
Luke Joshua Park Avatar answered Sep 25 '22 09:09

Luke Joshua Park