温馨提示:本文翻译自stackoverflow.com,查看原文请点击:javascript - AES encryption and decryption of files using crypto-js
aes cryptojs javascript

javascript - 使用crypto-js进行文件的AES加密和解密

发布于 2020-05-22 14:25:37

我目前有这样的要求,但是我无法解密加密的文件,生成的文件总是损坏并且无法打开,并且我不知道问题出在哪里。下面发布的代码是我在VUE中使用的代码。

Encode() {
           let CryptoJS = require("crypto-js");
            this.file_mime = this.file.type;
            this.file_name = this.file.name;
            let reader = new FileReader();
            reader.onload = () => {
                let key = "1234567887654321";
                // let wordArray = CryptoJS.lib.WordArray.create(reader.result);
                // let plaintext = CryptoJS.enc.Hex.stringify(wordArray);
                let encrypted = CryptoJS.AES.encrypt(reader.result, key).toString();

                this.file2 = new Blob([encrypted], {
                    type: this.file_mime
                });
                const a = document.createElement("a");
                const url = window.URL.createObjectURL(this.file2);
                const filename = this.file_name;
                a.href = url;
                a.download = filename;
                a.click();
                window.URL.revokeObjectURL(url);
            };
            reader.readAsBinaryString(this.file);
        }

Decode() {
            let CryptoJS = require("crypto-js");
            let reader = new FileReader();
            reader.onload = () => {
                let key = "1234567887654321";
                let decrypted = CryptoJS.AES.decrypt(reader.result, key).toString(CryptoJS.enc.Utf8)
                this.file2 = new Blob([decrypted], {type: this.file_mime});
                const a = document.createElement("a");
                const url = window.URL.createObjectURL(this.file2);
                const filename = this.file_name;
                a.href = url;
                a.download = filename;
                a.click();
                window.URL.revokeObjectURL(url);
            };
            reader.readAsBinaryString(this.file);
        }

查看更多

提问者
Young Xu
被浏览
12
Topaco 2020-03-06 00:37

在JavaScript中有几种类型的数组:ArrayArrayBuffer类型数组CryptoJS也使用WordArray您必须在这些类型之间正确转换。

为了进行加密,FileReader.readAsBinaryString应将其替换为FileReader.readAsArrayBuffer,它将以形式从文件返回二进制数据ArrayBuffer在加密方法中,ArrayBuffer可以将转换为WordArray,可以直接由处理CryptoJS.AES.encryptCryptoJS.AES.encrypt将密文作为CipherParams对象(在此处返回,并将其转换toString()为OpenSSL格式的Base64编码的字符串。此字符串可用于直接创建Blob。

注意:由于密钥是CryptoJS.AES.encrypt作为字符串传递的,因此将其解释为密码短语,并使用与OpenSSL使用的算法相同的算法生成8个字节的随机盐,该算法将与密码短语一起生成密钥和IV。密文之前是一个16字节的块,该块由的ASCII编码组成Salted__,后跟8字节的salt盐,并且整个内容都是Base64编码的。在这个OpenSSL的格式Base64编码的数据。因此开头U2FsdGVkX1在这里这里

加密方法的变化:

function encrypt(input) {
    var file = input.files[0];
    var reader = new FileReader();
    reader.onload = () => {
        var key = "1234567887654321";
        var wordArray = CryptoJS.lib.WordArray.create(reader.result);           // Convert: ArrayBuffer -> WordArray
        var encrypted = CryptoJS.AES.encrypt(wordArray, key).toString();        // Encryption: I: WordArray -> O: -> Base64 encoded string (OpenSSL-format)

        var fileEnc = new Blob([encrypted]);                                    // Create blob from string

        var a = document.createElement("a");
        var url = window.URL.createObjectURL(fileEnc);
        var filename = file.name + ".enc";
        a.href = url;
        a.download = filename;
        a.click();
        window.URL.revokeObjectURL(url);
    };
    reader.readAsArrayBuffer(file);
}

注意:由于加密数据是通过Base64编码的,而Base64编码的开销为33%,因此与未加密的数据相比,加密的数据相应更大。

对于解密,FileReader.readAsBinaryString应替换为FileReader.readAsText,因为加密的数据以Base64编码的字符串(以OpenSSL格式)存储,可以直接传递给CryptoJS.AES.decrypt该字符串被隐式转换为CipherParams对象(在此CipherParams也可以显式地传递对象)。CryptoJS.AES.decrypt将解密后的数据返回为WordArray,以便转换为类型数组或ArrayBuffer创建blob是必需的。为此,可以使用以下功能:

function convertWordArrayToUint8Array(wordArray) {
    var arrayOfWords = wordArray.hasOwnProperty("words") ? wordArray.words : [];
    var length = wordArray.hasOwnProperty("sigBytes") ? wordArray.sigBytes : arrayOfWords.length * 4;
    var uInt8Array = new Uint8Array(length), index=0, word, i;
    for (i=0; i<length; i++) {
        word = arrayOfWords[i];
        uInt8Array[index++] = word >> 24;
        uInt8Array[index++] = (word >> 16) & 0xff;
        uInt8Array[index++] = (word >> 8) & 0xff;
        uInt8Array[index++] = word & 0xff;
    }
    return uInt8Array;
}

注意:WordArray无法将转换为Utf8字符串(如在发布的代码中一样),并且通常会破坏数据,因为二进制数据(例如pdf)包含任意字节序列,这些字节序列通常不对应于Utf8编码(因为二进制数据不包含可打印字符),请参见此处

解密方法的变化:

function decrypt(input) {
    var file = input.files[0];
    var reader = new FileReader();
    reader.onload = () => {
        var key = "1234567887654321";  

        var decrypted = CryptoJS.AES.decrypt(reader.result, key);               // Decryption: I: Base64 encoded string (OpenSSL-format) -> O: WordArray
        var typedArray = convertWordArrayToUint8Array(decrypted);               // Convert: WordArray -> typed array

        var fileDec = new Blob([typedArray]);                                   // Create blob from typed array

        var a = document.createElement("a");
        var url = window.URL.createObjectURL(fileDec);
        var filename = file.name.substr(0, file.name.length - 4) + ".dec";
        a.href = url;
        a.download = filename;
        a.click();
        window.URL.revokeObjectURL(url);
    };
    reader.readAsText(file);
}