简体   繁体   中英

Java AES Encrypt in Javascript using CryptoJS

I'm trying to replicate the encryption used in a Java application using Javascript and CryptoJS. I'm not quite sure how I should be replicating the SecretKeySpec, as it seems CryptoJS expects a string for the key.

Here is the Java encryption code that I need to replicate in JS:

public byte[] encrypt(byte[] origin)
    {
        String key = "testkey";
        SecretKeySpec sks = new SecretKeySpec(convertAESKey(key), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[16];
        cipher.init(Cipher.ENCRYPT_MODE, sks, new IvParameterSpec(iv));
        return cipher.doFinal(origin);
    }

private byte[] convertAESKey(String key)
   {
        byte[] keyBytes;
        keyBytes = key.getBytes("UTF-8");
        byte[] keyBytes16 = new byte[16];
        System.arraycopy(keyBytes, 0, keyBytes16, 0,
                Math.min(keyBytes.length, 16));
        return keyBytes16;
    }
}

My JS code so far:

var iv = new Uint8Array(16);
var key = "testkey";

var encrypted = CryptoJS.AES.encrypt(
    someByteArray,
    key,
    {
        iv: iv,
        mode: CryptoJS.mode.CBC
    }
);

Also, the final output of cipher is a encrypted byte array. The final output of CryptoJS appears to be an object with cipherText. Is there a way to get the output as a byte array ?

The only thing I could think of now is to convert the encrypted response into a string, then converting that into a byte array, but this doesn't seem to match the output of the Java encryption.

CryptoJS doesn't handle Uint8Array by default, so I'm not going to use it and instead will use the default WordArray for representing binary data.

var iv = CryptoJS.lib.WordArray.create([0, 0, 0, 0]);
var key = "testkey";

key = CryptoJS.enc.Utf8.parse(key);
for (var i = key.words.length; i < 4; i++) {
    key.words[i] = 0;
}
key.sigBytes = 16;
key.clamp();

var encrypted = CryptoJS.AES.encrypt(
    someByteArray,
    key,
    {
        iv: iv,
        mode: CryptoJS.mode.CBC
    }
);
console.log(encrypted.ciphertext.toString(CryptoJS.enc.Hex));

This will give a hex string which can be easily compared to the ciphertext produced by Java.


This code is not very secure:

  • The IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.

  • The key must be random (read: look like random noise). Text doesn't look random and you would severely reduce your security by (mis-)using a password as a key. If you have a password, then you need to derive a key from that using something like PBKDF2, bcrypt, scrypt or Argon2 with a high iteration count / cost factor.

  • You should authenticate your ciphertexts in order to detect (malicious) manipulation. If you don't do this, then this might be vulnerable against a padding oracle attack. Authentication can be accomplished with an authenticated mode of operation like GCM or EAX, or using an encrypt-then-MAC scheme with a strong MAC such as HMAC-SHA256.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM