如何在浏览器中使用 Javascript encrypt/decrypt 任意二进制文件?

How can I encrypt/decrypt arbitrary binary files using Javascript in the browser?

我需要让用户从他们的系统加载文件,即时加密并上传到服务器并做相反的事情(从服务器下载文件,即时解密并让用户保存它们本地)。尽管首选 AES,但确切的加密方法不是很重要。

Encryption / decryption of binary data in the browser 这样的链接只是告诉你 "use CryptoJS" 但我找不到任何实际工作的示例。我发现的所有样本都专注于处理字符串,而在二进制数据中你可以轻松找到无效的 Unicode 序列。

有没有我可以测试的可以处理任何类型文件的工作示例?

注意:我不会解释如何解密数据,但使用加密代码和提供的文档链接应该很容易弄清楚。

首先,用户必须能够通过 input 元素 select 文件。

<input type="file" id="file-upload" onchange="processFile(event)">

然后您可以使用 HTML5 FileReader API

加载文件的内容
function processFile(evt) {
    var file = evt.target.files[0],
        reader = new FileReader();

    reader.onload = function(e) {
        var data = e.target.result;

        // to be continued...
    }

    reader.readAsArrayBuffer(file);   
}

使用WebCrypto API加密获取的数据。
如果您不想随机生成密钥,请使用 crypto.subtle.deriveKey 创建一个密钥,例如,根据用户输入的密码。

// [...]
var iv = crypto.getRandomValues(new Uint8Array(16)); // Generate a 16 byte long initialization vector

crypto.subtle.generateKey({ 'name': 'AES-CBC', 'length': 256 ]}, false, [ 'encrypt', 'decrypt' ])
    .then(key => crypto.subtle.encrypt({ 'name': 'AES-CBC', iv }, key, data))
    .then(encrypted => { /* ... */ });

现在您可以将加密数据发送到服务器(例如 AJAX)。 显然,您还必须以某种方式存储初始化向量,以便稍后成功解密所有内容。


这是一个提示加密数据长度的小例子。

注意: 如果显示 Only secure origins are allowed,请使用 https 重新加载页面并再次尝试示例(这是 WebCrypto API 的限制) :

function processFile(evt) {
    var file = evt.target.files[0],
        reader = new FileReader();

    reader.onload = function(e) {
        var data = e.target.result,
            iv = crypto.getRandomValues(new Uint8Array(16));
      
        crypto.subtle.generateKey({ 'name': 'AES-CBC', 'length': 256 }, false, ['encrypt', 'decrypt'])
            .then(key => crypto.subtle.encrypt({ 'name': 'AES-CBC', iv }, key, data) )
            .then(encrypted => {
                console.log(encrypted);
                alert('The encrypted data is ' + encrypted.byteLength + ' bytes long'); // encrypted is an ArrayBuffer
            })
            .catch(console.error);
    }

    reader.readAsArrayBuffer(file);   
}
<input type="file" id="file-upload" onchange="processFile(event)">

参见https://github.com/meixler/web-browser-based-file-encryption-decryption for an example showing encryption/decryption of arbitrary binary files using Javascript in the web browser, based on the Web Crypto API

您可以使用以下方法将文件转换为 blob:

new Blob([document.querySelector('input').files[0]])

这是加密和解密 blob 的代码

async function encryptblob(blob) {

    let iv = crypto.getRandomValues(new Uint8Array(12));
    let algorithm = {
        name: "AES-GCM",
        iv: iv
    }

    let key = await crypto.subtle.generateKey(
        {
            name: "AES-GCM",
            length: 256
        },
        true,
        ["encrypt", "decrypt"]
    );

    let data = await blob.arrayBuffer();

    const result = await crypto.subtle.encrypt(algorithm, key, data);

    let exportedkey =  await crypto.subtle.exportKey("jwk", key)
 
    return [new Blob([result]), iv.toString(), exportedkey]

}

async function decryptblob(encblob, ivdata, exportedkey) {


    let key = await crypto.subtle.importKey(
        "jwk",
        exportedkey,
        { name: "AES-GCM" },
        true,
        ["encrypt", "decrypt"]
    );

    let iv = new Uint8Array(ivdata.split(','))

    let algorithm = {
        name: "AES-GCM",
        iv: iv
    }

    let data = await encblob.arrayBuffer();

    let decryptedData = await crypto.subtle.decrypt(algorithm, key, data);

    return new Blob([decryptedData])


}