当前位置: 首页 > 知识库问答 >
问题:

如何实现CryptoJS。AES。Java中的加密函数?

华聪
2023-03-14

我试图在java中实现crypto js中的以下代码以进行加密

let toEncrypt= "my data";
cryptoJs.AES.encrypt(toEncrypt,"apasswordblabla").toString();

以下是我的实现(AES/CBC/PKCS7Padding):

public String encrypt(Map<String,Object> param){
try {
            String toEncrypt= objectMapper.writeValueAsString(param);
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] saltData = Arrays.copyOfRange(stringToEncrypt.getBytes(StandardCharsets.UTF_8), 8, 16);
            final byte[][] keyAndIV = generateKeyAndIV(32, 16, 1, saltData, "apasswordblabla".getBytes(StandardCharsets.UTF_8), md5);
            SecretKeySpec skeySpec = new SecretKeySpec(keyAndIV[0], "AES");
            IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);
            Cipher cipher;
            cipher = Cipher.getInstance("AES/CBC/PKCS7Padding",BouncyCastleProvider.PROVIDER_NAME);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec,iv);
            byte[] base64Encoded = Base64.getEncoder().encode(cipher.doFinal(toEncrypt.getBytes(StandardCharsets.UTF_8)));
            return new String(base64Encoded);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
                | BadPaddingException | InvalidKeyException
                | JsonProcessingException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
            

        }
}

GenerateIV(int, int, int, byte[], byte[], MessageDigest)的实现:

  • 这个方法相当于OpenSSL的EVP_BytesToKey函数,正如我在cryptojs源代码(cryptojs)中看到的那样-js@4.1.1在文件密码核心上。js第658行),AES的默认格式化程序是OpenSSLFormatter
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);
        }
    }

然后我试着在这里用

let toDecrypt="[MY ENCRYPTED DATA IN BASE64]"
let decrypted = cryptoJs.AES.decrypt(toDecrypt, "apasswordblabla").toString(cryptoJs.enc.Utf8).toString(); 
console.log(decrypted);

而且它总是无法解密,错误是“格式错误的utf-8数据”。因此,我的java实现是错误的

我做错了什么?或者,如果有任何现成的库可以解决此问题,请提出建议

共有1个答案

郝乐心
2023-03-14

OpenSSL和CryptoJS使用的格式是base64(“Salted\uuuuu”)

下面是产生这种格式结果的代码(重用上面的GenerateKeyAndIV方法,没有任何修改):

    public static void main(String args[]) {
        Security.addProvider(new BouncyCastleProvider());
        System.out.println(encrypt());
    }

    public static String encrypt() {
        try {
            String stringToEncrypt = "Hello world 12345";
            String password = "apasswordblabla";
            SecureRandom sr = new SecureRandom();
            byte[] salt = new byte[8];
            sr.nextBytes(salt);
            final byte[][] keyAndIV = generateKeyAndIV(32, 16, 1, salt, password.getBytes(StandardCharsets.UTF_8),
                    MessageDigest.getInstance("MD5"));
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyCastleProvider.PROVIDER_NAME);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyAndIV[0], "AES"), new IvParameterSpec(keyAndIV[1]));
            byte[] encryptedData = cipher.doFinal(stringToEncrypt.getBytes(StandardCharsets.UTF_8));
            byte[] prefixAndSaltAndEncryptedData = new byte[16 + encryptedData.length];
            // Copy prefix (0-th to 7-th bytes)
            System.arraycopy("Salted__".getBytes(StandardCharsets.UTF_8), 0, prefixAndSaltAndEncryptedData, 0, 8);
            // Copy salt (8-th to 15-th bytes)
            System.arraycopy(salt, 0, prefixAndSaltAndEncryptedData, 8, 8);
            // Copy encrypted data (16-th byte and onwards)
            System.arraycopy(encryptedData, 0, prefixAndSaltAndEncryptedData, 16, encryptedData.length);
            return Base64.getEncoder().encodeToString(prefixAndSaltAndEncryptedData);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

生成的示例结果是:U2FsdGVkX1/O8jV2bfcM/06DM106oLAzdf7z66/JakGNefts4MftzXquopkxPaDo

使用以下代码在JSFIDLE中解码:

console.log(CryptoJS.AES.decrypt("U2FsdGVkX1/O8jV2bfcM/06DM106oLAzdf7z66/JakGNefts4MftzXquopkxPaDo", "apasswordblabla").toString(CryptoJS.enc.Utf8));

在浏览器控制台中生成所需输出:Hello world 12345

 类似资料:
  • 我之所以问这个问题,是因为两天来我读了很多关于crypto AES加密的帖子,就在我以为我得到了它的时候,我意识到我根本没有得到它。 这个帖子是最接近我的问题,我有完全相同的问题,但它没有得到回答: CryptoJS AES加密与JAVA AES解密值不匹配 我得到的是已经加密的字符串(我得到的代码只是为了看看他们是怎么做的),所以修改加密方式不是一个选项。这就是为什么所有类似的问题对我来说都不是

  • 客户端: 服务器端:

  • 我正在尝试使用Javascript和CryptoJS复制Java应用程序中使用的加密。我不太确定应该如何复制SecretKeySpec,因为CryptoJS似乎需要一个字符串作为密钥。 下面是我需要在JS中复制的Java加密代码: 到目前为止,我的JS代码: 此外,密码的最终输出是一个加密的字节数组。CryptoJS的最终输出似乎是一个带有密文的对象。有没有办法以字节数组的形式获取输出? 我现在唯

  • 注意:这只是为个人使用和学习,我不是试图滚动我自己的加密为公众使用。 我需要AES256加密一个字符串,但是我当前的尝试在十六进制解码时最终得到了一个类似server side的字符串。当十六进制解码时,它应该是一个有效的utf8 base64字符串,然后可以将其解码为原始字符串。这与这里提供的解决方案类似,但是salt并不是实际问题(尽管答案被接受),并且我无法在使用之前通过十六进制解码iv来抑

  • 问题内容: 我在使用CryptoJS解密在Go lang中加密的文本时遇到问题。 这是Go代码:https : //play.golang.org/p/xCbl48T_iN 这是JS代码:http: //jsfiddle.net/Ltkxm64n/ 两者都可以很好地进行加密和解密,但是当我将base64密文从GO复制到JS(反之亦然)时,它不起作用。我还注意到js输出的第一部分与Go输出相同,但是

  • 问题内容: 我有以下基于cryptojs的javascript加密/解密函数,它们运行良好。 在使用cryptpjs加密消息时,我使用随机盐,随机iv值和特定密码。在解密加密的消息时,我重复使用了相同的salt,iv和密码来生成密钥。 这部分效果很好.. 但是,当我尝试在Java服务器端解密相同的加密文本时,问题就开始了。我希望通过我的java服务器代码解密加密后的消息。这是我编写的Java代码: