解决CryptoJS Encryptor JAVA Decryp

2018-07-15  本文已影响0人  golden_coder

前段时间遇到一个需求,前端用CryptoJS加密,例如用AES和3DES,后台用JAVA解密.网上对于JAVA的AES和3DES算法DEMO有很多,自己去实现了一下,都能实现自己加密后自己解密.但是关键是前端用CryptoJS加密后,自己后端怎么都解密不出来,而且经常报错说key size不合法等等.

这里多插一句话,之前没太了解加密解密的内容,之后才发现原来相同的明文和密钥加密出来的密文是可以不同的,而且还能解出来.原谅我见识短浅!!!

之后我看了一下这些站长工具的js,都是这样的:


$("#encrypt_result").val(CryptoJS.AES.encrypt($("#msg_source").val(),$("#pwd").val()));

这里关键的一点是js没有指明用什么模式和用什么填充方式,另外iv也没有指定,所以刚开始让我很抓狂,你前端怎么做的不写清楚,我后端怎么去解啊!!!

最后是查到了stackflow一位大神的回答后才知道怎么去做的:

CryptoJS implements the same key derivation function as OpenSSL and the same format to put the IV into the encrypted data. So all Java code that deals with OpenSSL encoded data applies.

https://stackoverflow.com/questions/41432896/cryptojs-aes-encryption-and-java-aes-decryption

具体的英文意思很简单,这里不重复,反正就是用处理OpenSSL的代码处理一下就可以

public static void main(String[] args) throws Exception {
     String secret = "René Über";

     String cipherText = "U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=";

    byte[] cipherData = Base64.getDecoder().decode(cipherText);

    byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);

    MessageDigest md5 = MessageDigest.getInstance("MD5");

    final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes(StandardCharsets.UTF_8), md5);

    SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");

    IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);

    byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);

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

    aesCBC.init(Cipher.DECRYPT_MODE, key, iv);

    byte[] decryptedData = aesCBC.doFinal(encrypted);

    String decryptedText = new String(decryptedData, StandardCharsets.UTF_8);

    System.out.println(decryptedText);
}

public static byte[][] GenerateKeyAndIV(int keyLength, int ivLength, int iterations, byte[] salt, byte[] password, MessageDigest md) {

    int digestLength = md.getDigestLength();

    int requiredLength = (keyLength + ivLength + digestLength - 1) / digestLength * digestLength;

    byte[] generatedData = new byte[requiredLength];

    int generatedLength = 0;

    try {

        md.reset();

        // Repeat process until sufficient data has been generated

        while (generatedLength < keyLength + ivLength) {

            // Digest data (last digest if available, password data, salt if available)

            if (generatedLength > 0)

                md.update(generatedData, generatedLength - digestLength, digestLength);

            md.update(password);

            if (salt != null)

                md.update(salt, 0, 8);

            md.digest(generatedData, generatedLength, digestLength);

            // additional rounds

            for (int i = 1; i < iterations; i++) {

                md.update(generatedData, generatedLength, digestLength);

                md.digest(generatedData, generatedLength, digestLength);

            }

            generatedLength += digestLength;

        }

        // Copy key and IV into separate byte arrays

        byte[][] result = new byte[2][];

        result[0] = Arrays.copyOfRange(generatedData, 0, keyLength);

        if (ivLength > 0)

            result[1] = Arrays.copyOfRange(generatedData, keyLength, keyLength + ivLength);

        return result;

    } catch (DigestException e) {

        throw new RuntimeException(e);

    } finally {

        // Clean out temporary data

        Arrays.fill(generatedData, (byte)0);

    }

}

这个代码和其他一般代码不同的是GenerateKeyAndIV方法,这也是我唯一看不懂的地方.比较有意思的是,上面代码是拿来解密AES的,如果换成3DES的话,代码其实只要改下GenerateKeyAndIV中的参数,keyLength设为24,ivlength设为8,然后什么AES都改成DESede就可以了.(用AES的麻烦在于它的key有256位,jdk默认支持128位的key,因此要替换jdk的jar包)

最后科普一下关于CryptoJs AES的加密模式

The modes of operation currently available are:

CBC (the default)

CFB

CTR

OFB

ECB

And the padding schemes currently available are:

Pkcs7 (the default)

Iso97971

AnsiX923

Iso10126

ZeroPadding

NoPadding

上一篇下一篇

猜你喜欢

热点阅读