如何在浏览器中使用 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])
}
我需要让用户从他们的系统加载文件,即时加密并上传到服务器并做相反的事情(从服务器下载文件,即时解密并让用户保存它们本地)。尽管首选 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])
}