Java和Javascript之间的加密和解密将无法正常工作

Jas*_*son 16 javascript java encryption cryptography aes

编辑1

在decryptFile方法中,解密部分不会输出任何内容.

let decrypted = CryptoJS.AES.decrypt(e.target.result, CryptoJS.enc.Utf8.parse(key), {
    iv: CryptoJS.enc.Utf8.parse(iv),
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
});
Run Code Online (Sandbox Code Playgroud)


编辑2评论部分中给出 的链接部分解决了问题.它确实对跨平台进行加密和解密,但由于PBKDF2具有SHA256散列,它相当慢.我找不到只使用AES部分而不是PKBDF2部分的方法.


原文

我对Java和Javascript版本使用相同的密钥和IV.我无法解密用Java加密的Javascript中的文件,也无法解密用Javascript加密的Java文件.我需要这两个兼容彼此,但我无法弄清楚我是如何尝试解密以前用Java加密的Javascript中的文件.我已经成功地在两者之间实现了解密和加密文本,但是当我想要解密一个用Java加密的文件时,它就无法工作了.

用Java加密/解密文件:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Test {
    private SecretKey secretKey;
    private IvParameterSpec ivParameterSpec;

    private String key = "ThisIsMyGreatKey";
    private byte[] ivKey = "ABCDEFGHabcdefgh".getBytes();

    public static void main(String[] args) {
        try {
            new Test().run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void run() {
        ivParameterSpec = new IvParameterSpec(ivKey);
        secretKey = new SecretKeySpec(key.getBytes(), "AES");
        encryptOrDecryptFile(Cipher.ENCRYPT_MODE,
            new File("src/cactus.jpg"), new File("src/cactus-encrypted.jpg"));
    }

    private void encryptOrDecryptFile(int mode, File inputFile, File outputFile) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(mode, secretKey, ivParameterSpec);

            // Read input
            byte[] input = new byte[(int) inputFile.length()];
            FileInputStream inputStream = new FileInputStream(inputFile);
            inputStream.read(input);

            // Encrypt and write to output
            byte[] output = cipher.doFinal(input);
            FileOutputStream outputStream = new FileOutputStream(outputFile);
            outputStream.write(output);

            inputStream.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在Javascript中加密/解密

<input type="file" id="file-input" onchange="handleFile(this)">
<button onclick="useEncryptionForFile()" id="encrypt-file">Encrypt File</button>
<button onclick="useDecryptionForFile()" id="decrypt-file">Decrypt File</button>
<textarea id="output"></textarea>
<img id="example">

<script>
    let key = "ThisIsMyGreatKey";
    let iv = "ABCDEFGHabcdefgh";
    let useEncryption, useDecryption;

    let input = document.getElementById("file-input");
    let output = document.getElementById("output");
    let example = document.getElementById("example");

    function handleFile(element) {
        if (element.files && element.files[0]) {
            let file = element.files[0];
            if (useDecryption) {
                decryptFile(file);
            } else {
                encryptFile(file);
            }
        }
    }

    function encryptFile(file) {
        let reader = new FileReader();

        reader.onload = function (e) {
            let encrypted = CryptoJS.AES.encrypt(e.target.result, CryptoJS.enc.Utf8.parse(key), {
                iv: CryptoJS.enc.Utf8.parse(iv),
                mode: CryptoJS.mode.CBC,
                padding: CryptoJS.pad.Pkcs7
            });

            output.textContent = encrypted;

            let a = document.createElement("a");
            a.setAttribute('href', 'data:application/octet-stream,' + encrypted);
            a.setAttribute('download', file.name + '.encrypted');
            a.click();
        };

        reader.readAsDataURL(file);
    }

    function decryptFile(file) {
        let reader = new FileReader();
        reader.onload = function (e) {
            let decrypted = CryptoJS.AES.decrypt(e.target.result, CryptoJS.enc.Utf8.parse(key), {
                iv: CryptoJS.enc.Utf8.parse(iv),
                mode: CryptoJS.mode.CBC,
                padding: CryptoJS.pad.Pkcs7
            });

             // Decrypted is emtpy    
            output.textContent = decrypted;

            // Desperate try to get something working
            example.src = "data:image/png;base64," + btoa(decrypted);

            let a = document.createElement("a");
            a.setAttribute('href', decrypted);
            a.setAttribute('download', file.name.replace('encrypted', 'decrypted'));
            a.click();
        };

        reader.readAsText(file);
    }

    function useEncryptionForFile() {
        document.getElementById("encrypt-file").style.backgroundColor = "#757575";
        document.getElementById("decrypt-file").style.backgroundColor = "#FFFFFF";
        useEncryption = true;
      useDecryption = false;
    }

    function useDecryptionForFile() {
        document.getElementById("encrypt-file").style.backgroundColor = "#FFFFFF";
        document.getElementById("decrypt-file").style.backgroundColor = "#757575";
        useDecryption = true;
      useEncryption = false;
    }
</script>    
Run Code Online (Sandbox Code Playgroud)

如果你想要更多:) 我也做了一个小提琴,并且可以在这里下载 Java源代码.

在Java源代码中,我使用cactus.jpg作为文件,但是可以使用任何文件:).仙人掌可以在这里找到.

如何解密用Java加密的文件?我已经尝试将blob内容转换为String,将数据检索为ArrayBuffer并将其转换为String,将其作为文本接收并将其传递给解密方法,但似乎没有任何效果.

我在Javascript中使用的库是CryptoJS,在Java中是标准的Crypto库.

我发现其他类似的(1,2)的问题.但是,我认为它们差别太大,因为这些问题的答案并不涉及这个问题,而是一个小错误.

如果我忘记了任何数据,请告诉我.

Luk*_*ark 5

问题是您将解密结果解释为UTF8字符串.这不是它的工作原理.文件只是任意字节,它们不一定构成UTF8字符串.如果您不尝试将其解释为UTF8,则解密的结果是正确的.


Shu*_*lag 3

首先,尝试从 java 向 javascript 发送简单的加密文本,反之亦然,并测试代码是否正常工作。

如果代码适用于简单文本,即您能够从 Java 发送加密字符串并在 JavaScript 中成功解密,反之亦然,那么您可以做的是 Base64 编码加密字节/文件,然后传输文本并然后在另一端对其进行解码和解密。

如果代码不适用于简单文本,那么您可以尝试分别用 javascript 和 java 加密简单文本,并检查结果是否相同。如果不是,则说明 java 和 javascript 之间的加密/解密逻辑不匹配。

编辑:

正如您提到的代码适用于 String,我在下面展示了一个使用 java 中的 apache 通用编解码器库将文件转换为 Base64 String 的示例。

private static String encodeFileToBase64Binary(String fileName) throws IOException {
    File file = new File(fileName);
    byte[] encoded = Base64.encodeBase64(FileUtils.readFileToByteArray(file));
    return new String(encoded, StandardCharsets.US_ASCII);
}
Run Code Online (Sandbox Code Playgroud)

现在您加密该字符串并将其发送到 javascript。在javascript中,首先解密字符串,然后将其转换为文件对象。

例如。

 function base64toFile(encodedstring,filename,mimeType){
   return new File([encodedstring.arrayBuffer()],filename, {type:mimeType});

}   

//Usage example:
base64toFile('aGVsbG8gd29ybGQ=', 'hello.txt', 'text/plain');
Run Code Online (Sandbox Code Playgroud)