yii2-netdisk/web/js/vault_core.js
Chenx221 f83c7ed325
实现文件保险箱的端到端加密
*未完全测试
*不保证数据安全性
2024-03-11 20:24:51 +08:00

121 lines
4.2 KiB
JavaScript

const vaultRawKey = sessionStorage.getItem('vaultRawKey');
async function generateEncryptionKeyFromPassword(password) {
const passwordBuffer = new TextEncoder().encode(password);
const key = await window.crypto.subtle.importKey(
'raw',
passwordBuffer,
{name: 'PBKDF2'},
false,
['deriveKey']
);
return await window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: new Uint8Array([]),
iterations: 100000,
hash: 'SHA-256'
},
key,
{name: 'AES-GCM', length: 256},
false,
['encrypt', 'decrypt']
);
}
// 加密文件
async function encryptFile(file, password) {
const iv = window.crypto.getRandomValues(new Uint8Array(12)); // 生成随机 IV
const passwordBuffer = new TextEncoder().encode(password);
const key = await window.crypto.subtle.importKey(
'raw',
passwordBuffer,
{name: 'PBKDF2'},
false,
['deriveKey']
);
const derivedKey = await window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: new Uint8Array([]),
iterations: 100000,
hash: 'SHA-256'
},
key,
{name: 'AES-GCM', length: 256},
false,
['encrypt', 'decrypt']
);
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function(event) {
const plaintextData = event.target.result;
window.crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: iv }, // 使用随机生成的 IV
derivedKey,
plaintextData
).then(encryptedData => {
const encryptedBlob = new Blob([iv, encryptedData], {type: file.type});
resolve(encryptedBlob);
}).catch(error => {
reject(error);
});
};
reader.readAsArrayBuffer(file);
});
}
// 解密文件
async function decryptFile(encryptedFile, password) {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = async function(event) {
try {
const encryptedData = new Uint8Array(event.target.result);
const iv = encryptedData.slice(0, 12); // 从密文中提取 IV
const ciphertext = encryptedData.slice(12);
const passwordBuffer = new TextEncoder().encode(password);
const key = await window.crypto.subtle.importKey(
'raw',
passwordBuffer,
{name: 'PBKDF2'},
false,
['deriveKey']
);
const derivedKey = await window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: new Uint8Array([]),
iterations: 100000,
hash: 'SHA-256'
},
key,
{name: 'AES-GCM', length: 256},
false,
['encrypt', 'decrypt']
);
const decryptedData = await window.crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: iv }, // 使用从密文中提取的 IV
derivedKey,
ciphertext
);
const decryptedFile = new Blob([decryptedData], { type: encryptedFile.type });
resolve(decryptedFile);
} catch (error) {
reject(error);
}
};
fileReader.readAsArrayBuffer(encryptedFile);
});
}
async function downloadAndDecryptFile(url, password, filename) {
const response = await fetch(url);
const encryptedFile = await response.blob();
const decryptedFile = await decryptFile(encryptedFile, password);
const blob = new Blob([decryptedFile], {type: decryptedFile.type});
const blobURL = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = blobURL;
link.download = filename;
link.click();
window.URL.revokeObjectURL(blobURL);
}