1

I am trying to re-create a code snippet from JS to Java, but the outputs are different. What am I doing wrong? This is the code snippet from JS:

var randomKey = 2116781760886580;

var key = CryptoJS.enc.Utf8.parse(randomKey);

var iv = CryptoJS.enc.Utf8.parse(randomKey);

var encrypt = CryptoJS.AES
    .encrypt(CryptoJS.enc.Utf8.parse("Text to encrypt"), key,
        {
            keySize: 128 / 8,
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });

var out = btoa(encrypt);   //SGpJSWhDUXNmMEMzSk0vbmovaGZyQT09

The following is the Java code snippet:

String randomKey = "2116781760886580";

String plainText = "Text to encrypt";

byte[] keyBytes = randomKey.getBytes(StandardCharsets.UTF_8);

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);

SecretKeySpec sKey = new SecretKeySpec(keyBytes,"AES");

cipher.init(Cipher.ENCRYPT_MODE, sKey, ivSpec);

byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

String out = Base64.getEncoder().encodeToString(encryptedBytes);    //HjIIhCQsf0C3JM/nj/hfrA==
10
  • Your key looks like a number in JS, while it is a string in Java (at least the type says so, as the code is not valid Java). Could that be the difference? Commented Feb 4, 2021 at 11:58
  • I think, you encrypt two times in your js code. CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse("Text to encrypt") .... But in java code, you encrypt one time. Commented Feb 4, 2021 at 11:59
  • 1
    The bug is in the CryptoJS code. CryptoJS.AES.encrypt() returns a CipherParams object that encapsulates various data, including the ciphertext. I don't know what btoa does with this object, but it doesn't return the Base64 encoded ciphertext. You can get it with encrypt.ciphertext.toString(CryptoJS.enc.Base64) or shorter with encrypt.toString() and it corresponds to the Base64 encoded ciphertext of the Java code. By the way, using the key as IV is generally insecure. Commented Feb 4, 2021 at 11:59
  • @marstran I double checked that in JS by printing the word array using string and number types, both results were the same. Commented Feb 4, 2021 at 12:52
  • @Topaco Ok, I am trying to re-create the same logic in Java, from an already existing implementation in CryptoJs. Commented Feb 4, 2021 at 12:54

1 Answer 1

1

CryptoJS.AES.encrypt() returns a CipherParams object that encapsulates several data, in particular the ciphertext. If the CipherParams object is passed to btoa(), it is first implicitly converted to a string using toString() which returns the Base64 encoded ciphertext of the CipherParams object by default, at least if no salt is involved as in this case. Together with the Base64 encoding of btoa(), the ciphertext is therefore Base64 encoded twice.

So that the Java code provides the same result as the JavaScript code, the ciphertext must therefore also be Base64 encoded twice, which is done e.g. with the following addition:

String out2 = Base64.getEncoder().encodeToString(out.getBytes(StandardCharsets.UTF_8));

Note that the redundant Base64 encoding is actually useless and only increases the amount of data (Base64 has 33% overhead). Also, using the key as IV is generally insecure, here.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.