3

I am trying to replicate the Java code for AES Encryption and Decryption in Node JS.

Java Code

    SecretKeySpec skeySpec;
    String key = "a4e1112f45e84f785358bb86ba750f48";

    public void encryptString(String key) throws Exception {
        try {
            skeySpec = new SecretKeySpec(key.getBytes(), "AES");
            cipher = Cipher.getInstance("AES");
            cipher.init(1, skeySpec);
            byte encstr[] = cipher.doFinal(message.getBytes());
            String encData = new String(encstr, "UTF-8");
            System.out.println(encData);
        } catch (NoSuchAlgorithmException nsae) {
            throw new Exception("Invalid Java Version");
        } catch (NoSuchPaddingException nse) {
            throw new Exception("Invalid Key");
        }
    }

Node JS

    var encryptKey = function (text) {
        var cipher = crypto.createCipher('aes256', 'a4e1112f45e84f785358bb86ba750f48');
        var crypted = cipher.update(text,'utf8', 'hex')
        crypted += cipher.final('hex');
        console.log(crypted);
        return crypted;
    }

I am unable to get the exact cipher-text in Node JS, which i am getting in Java.

Prashant Kumar Sharma
  • 1,120
  • 1
  • 11
  • 21
  • 2
    Whey-hey, another example of encryption where **absolutely everything** goes wrong. ECB mode, key as a string (hex, but not decoded), terrible exception handling not even registering the cause and using bad messages and using Exception etc. etc., bad encoding of the plaintext and why not use ECB for transport mode security. At least one error per line, do not use above code. – Maarten Bodewes Feb 18 '20 at 16:36

2 Answers2

2

Your code actually uses different encryption parameters in the 2 cases. AES, being a block cipher, takes: the plain text to encrypt, the initialization vector, also called IV (which is used in conjunction with the plaintext), and the encryption key.

In Java, the IV is, apparently, generated automatically on init() - from the Java SE platform docs for Cipher.init:

The generated parameters can be retrieved using getParameters or getIV (if the parameter is an IV).

In Node.js, if using the deprecated createCipher function, the IV is generated automatically based on the provided key, probably in a different way than in Java, so you will get a different cipher text. However, you should be using the non-deprecated variant crypto.createCipheriv: https://nodejs.org/docs/latest-v12.x/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options

In order to exactly reproduce the cipher text, you should:

  • Use the same encryption algorithm on both sides - it's best to specify this exactly, for example aes-256-cbc, or an authenticated encryption scheme such as aes-256-gcm, which is harder to use but provides message authentication.
  • Use the same IV on both sides, by providing it in the initialization params in Java, and by using createCipheriv in Node; though beware, you should always randomize it in production! See https://stackoverflow.com/a/20888967/6098312

As a closing remark, when using block encryption, you'll usually be generating securely-random IVs, which means the ciphertexts will always differ from one another, even for the same plaintext. This is a good thing! It protects your payload from an attacker who observes the encrypted data and makes conclusions based on message repetitions.

Robert Kawecki
  • 2,218
  • 1
  • 9
  • 17
  • Great answer, however even though it says in the Nodejs documentation that it's safe to expose the IV, would it still be safe to expose the IV with the encrypted text say when storing the encrypted text in a DB? See this for an example: https://gist.github.com/vlucas/2bd40f62d20c1d49237a109d491974eb Additionally, do you really want a new IV generated each encryption? – Darren Jun 02 '21 at 04:52
  • Ah ha, I found my answer after some more searching. https://stackoverflow.com/a/65464631/908171 – Darren Jun 02 '21 at 04:55
1

Finally after reviewing Java Docs and Node JS Crypto Docs managed to get the result. We have to use crypto.createCipheriv() instead of crypto.createCipher with a iv. Here iv will be null.

Code :

    let crypto = require('crypto');

    var iv = new Buffer.from('');   //(null) iv 
    var algorithm = 'aes-256-ecb';
    var password = 'a4e1112f45e84f785358bb86ba750f48';      //key password for cryptography

    function encrypt(buffer){
        var cipher = crypto.createCipheriv(algorithm,new Buffer(password),iv)
        var crypted = Buffer.concat([cipher.update(buffer),cipher.final()]);
        return crypted;
    }

    console.log(encrypt(new Buffer('TextToEncrypt')).toString())
Prashant Kumar Sharma
  • 1,120
  • 1
  • 11
  • 21