【问题标题】:CryptoJS AES encryption and JAVA AES decryption value mismatchCryptoJS AES 加密和 JAVA AES 解密值不匹配
【发布时间】:2013-07-20 18:49:11
【问题描述】:

我在客户端使用 CryptoJS AES 算法加密文本,我在 Java 的服务器端解密它,我得到了异常。

JS代码:

var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");
console.info("encrypted " + encrypted);
var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");
var plainText = decrypted.toString(CryptoJS.enc.Utf8)
console.info("decrypted " + plainText);

js 输出:

encrypted U2FsdGVkX1/uYgVsNZmpbgKQJ8KD+8R8yyYn5+irhoI=
decrypted Message

Java 代码:

import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.regex.Pattern;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class AESJavaScript {
    private SecretKeySpec key;
    private Cipher cipher;
    private int size = 128;
    private static final Charset CHARSET = Charset.forName("UTF-8"); 

    public AESJavaScript() throws NoSuchAlgorithmException,
            NoSuchPaddingException, NoSuchProviderException {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(size); // 192 and 256 bits may not be available
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        key = new SecretKeySpec(raw, "AES/CTR/NoPadding");
        cipher = Cipher.getInstance("AES/CTR/NoPadding");
    }

    public void setKey(String keyText) {
        byte[] bText = new byte[size];
        bText = keyText.getBytes(CHARSET);
        key = new SecretKeySpec(bText, "AES/CTR/NoPadding");
    }

    public String encrypt(String message) throws InvalidKeyException,
            IllegalBlockSizeException, BadPaddingException {
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encrypted = cipher.doFinal(message.getBytes());
        return byteArrayToHexString(encrypted);
    }

    public String decrypt(String hexCiphertext)
            throws IllegalBlockSizeException, BadPaddingException,
            InvalidKeyException {
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decrypted = cipher.doFinal(hexStringToByteArray(hexCiphertext));
        return byteArrayToHexString(decrypted);
    }

    private static String byteArrayToHexString(byte[] raw) {
        String hex = "0x";
        String s = new String(raw);
        for (int x = 0; x < s.length(); x++) {
            char[] t = s.substring(x, x + 1).toCharArray();
            hex += Integer.toHexString((int) t[0]).toUpperCase();
        }
        return hex;
    }

    private static byte[] hexStringToByteArray(String hex) {
        Pattern replace = Pattern.compile("^0x");
        String s = replace.matcher(hex).replaceAll("");

        byte[] b = new byte[s.length() / 2];
        for (int i = 0; i < b.length; i++) {
            int index = i * 2;
            int v = Integer.parseInt(s.substring(index, index + 2), 16);
            b[i] = (byte) v;
        }
        return b;
    }

    public static void main(String[] args) {
        try {
            AESJavaScript ajs = new AESJavaScript();
            ajs.setKey("Secret Passphrase");
            String hexCiphertext = "U2FsdGVkX1/uYgVsNZmpbgKQJ8KD+8R8yyYn5+irhoI=";
            String decrypted = ajs.decrypt(hexCiphertext);
            System.out.println("decrypted > " + decrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

例外是:

java.security.InvalidKeyException: Invalid AES key length: 17 bytes
    at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:372)
    at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1052)
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1010)
    at javax.crypto.Cipher.implInit(Cipher.java:786)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:849)
    at javax.crypto.Cipher.init(Cipher.java:1213)
    at javax.crypto.Cipher.init(Cipher.java:1153)
    at com.test.jenkins.jenkinsRestart.AESJavaScript.decrypt(AESJavaScript.java:49)
    at com.test.jenkins.jenkinsRestart.AESJavaScript.main(AESJavaScript.java:82)

我在这里做错了什么还是有其他简单的方法来进行这种加密和解密?

【问题讨论】:

标签: java javascript encryption aes cryptojs


【解决方案1】:

您的 Java 代码充满了错误。以下是其中一些:

  • 您的初始异常是由于您的 "Secret Passphrase" 字符串包含 17 个字节而引起的。您需要将其截断为 16 个字节(或填充它以匹配 24 或 32 个字节)。您需要匹配 CryptoJS 库的行为。

  • 您正在尝试对看似经过 base64 编码的数据进行十六进制解码。尝试使用DatatypeConverter.parseBase64Binary(hex);

  • 您正在使用算法"AES/CTR/NoPadding" 创建密钥。这无效,请使用"AES"

  • 您必须将 IV/nonce 值传递给您的解密:

    cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(...));
    

    您使用的值将取决于 CryptoJS 正在做什么。也许它使用全零?也许它会生成一个随机的,您需要将其与密文一起存储?

这应该足以让您入门。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    • 2019-08-13
    • 1970-01-01
    • 2014-08-17
    • 2015-11-01
    • 1970-01-01
    相关资源
    最近更新 更多