我正在使用 openpgp 库来加密和解密 React 组件内的文件。加密按预期工作,内存使用量较少,但解密占用过多内存。 我使用的库版本是:5.7.0
下面是带有加解密功能的代码示例。加密类型与密码对称。
import React, { useState } from "react";
import * as openpgp from "openpgp";
const FileEncrypter = () => {
const [file, setFile] = useState(null);
const [password, setPassword] = useState("");
const [encryptedFile, setEncryptedFile] = useState(null);
const [decryptedFile, setDecryptedFile] = useState(null);
const handleFileChange = (e) => {
const selectedFile = e.target.files[0];
setFile(selectedFile);
};
const handlePasswordChange = (e) => {
setPassword(e.target.value);
};
const fileToStream = (file) => {
const blob = new Blob([file], { type: file.type });
const stream = blob.stream();
return stream;
}
const streamEncryptFile = async (fileToEncrypt) => {
const fileName = `${file.name}.pgp`;
const readableStream = fileToStream(fileToEncrypt);
const message = await openpgp.createMessage({ binary: readableStream });
const encrypted = await openpgp.encrypt({
message, // input as Message object
passwords: [password], // multiple passwords possible
format: 'binary', // don't ASCII armor (for Uint8Array output)
config: { preferredCompressionAlgorithm: openpgp.enums.compression.zlib } // compress the data with zlib
});
const blob = await webStreamToBlob(encrypted);
console.log("Encrypt Output Size: ", formatBytes(blob.size));
return new File([blob], fileName, { type: 'application/octet-stream' });
}
const streamDecryptFile = async (fileToDecrypt) => {
const fileName = `${file.name}`;
const readableStream = fileToStream(fileToDecrypt);
const message = await openpgp.readMessage({ binaryMessage: readableStream });
const decrypted = await openpgp.decrypt({
message, // input as Message object
passwords: [password], // multiple passwords possible
format: 'binary', // don't ASCII armor (for Uint8Array output)
config: { preferredCompressionAlgorithm: openpgp.enums.compression.zlib } // compress the data with zlib
});
const blob = await webStreamToBlob(decrypted.data);
console.log("Decrypt Output Size: ", formatBytes(blob.size));
return new File([blob], fileName, { type: 'application/octet-stream' });
}
const webStreamToBlob = async (webStream) => {
try {
const reader = webStream.getReader();
//const reader = webStream.getReader({ chunkSize: 1 * 1024 * 1024 });
const chunks = [];
let done, value;
while (!done) {
({ done, value } = await reader.read());
if (value) {
console.log("Chunk Count: ", chunks.length + 1);
chunks.push(value);
}
}
const blob = new Blob(chunks, { type: 'application/octet-stream' });
return blob;
} catch (error) {
console.error('Error in coverting to blob:', error);
//throw new Error('Failed to convert WebStream to Blob.');
}
}
const formatBytes = (bytes, decimals = 2) => {
if (!+bytes) return '0 Bytes'
const k = 1024
const dm = decimals < 0 ? 0 : decimals
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`
}
const handleEncryptClick = async () => {
const encryptedFile = await streamEncryptFile(file);
setEncryptedFile(encryptedFile);
};
const handleDecryptClick = async () => {
const decryptedFile = await streamDecryptFile(encryptedFile);
setDecryptedFile(decryptedFile);
};
return (
<div>
<input type="file" onChange={handleFileChange} />
<input type="text" placeholder="Password" onChange={handlePasswordChange} />
<button onClick={handleEncryptClick}>Encrypt</button>
{encryptedFile && <button onClick={handleDecryptClick}>Decrypt</button>}
<br />
{encryptedFile && (
<a href={URL.createObjectURL(encryptedFile)} download={`${file.name}.pgp`}>
Download encrypted file
</a>
)}
<br />
{decryptedFile && (
<a href={URL.createObjectURL(decryptedFile)} download={`${file.name}`}>
Download decrypted file
</a>
)}
</div>
);
};
export default FileEncrypter;