基于Electron+React的桌面应用文件加解密实现咨询(Node.js Crypto流)
基于Electron + React的多格式文件流加密/解密实现
看起来你已经选对了方向——用Node.js的crypto和fs流处理文件,比一次性把文件读进内存高效太多,尤其适合桌面应用里的txt、pdf、jpg、png这类不同格式的文件(流处理只认二进制数据,完全不挑文件类型)。不过你的现有代码还有几个小问题要修正,比如file_path没作为参数传入、createCipher已经被官方标记为弃用(安全性也不足),我来帮你完善整个加解密流程:
加密函数(安全优化版)
我把弃用的createCipher换成了更安全的createCipheriv(createCipher的密钥派生方式存在安全隐患),同时补全了参数传递、流的安全处理和错误捕获:
const crypto = require('crypto'); const fs = require('fs'); const { pipeline } = require('stream/promises'); // 用Promise版管道,适配async/await语法 export async function encryptFile(filePath, passphrase, outputPath) { // 从用户密码生成符合AES-192要求的密钥和随机IV(密钥24字节,IV16字节) const salt = crypto.randomBytes(16); const key = crypto.scryptSync(passphrase, salt, 24); const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-192-cbc', key, iv); try { // 用pipeline自动处理流的拼接、错误和关闭,避免内存泄漏 await pipeline( fs.createReadStream(filePath), cipher, fs.createWriteStream(outputPath, { flags: 'w' }) ); // 把salt和IV写入加密文件的开头,解密时必须用到这两个值 const outputFile = fs.openSync(outputPath, 'r+'); fs.writeSync(outputFile, salt, 0, salt.length, 0); fs.writeSync(outputFile, iv, 0, iv.length, salt.length); fs.closeSync(outputFile); return true; // 加密成功返回标记 } catch (err) { console.error('加密过程出错:', err); // 这里可以结合Electron的dialog组件给用户弹出错误提示 return false; } }
对应的解密函数
解密时需要读取加密文件开头的salt和IV,再用相同的密码生成密钥:
export async function decryptFile(encryptedFilePath, passphrase, outputPath) { // 先读取文件开头的salt和IV const fileBuffer = fs.readFileSync(encryptedFilePath, { encoding: null }); const salt = fileBuffer.slice(0, 16); const iv = fileBuffer.slice(16, 32); // 用相同的密码和salt生成密钥 const key = crypto.scryptSync(passphrase, salt, 24); const decipher = crypto.createDecipheriv('aes-192-cbc', key, iv); try { // 从第32字节开始读取加密数据(跳过前面的salt和IV) const inputStream = fs.createReadStream(encryptedFilePath, { start: 32 }); await pipeline( inputStream, decipher, fs.createWriteStream(outputPath, { flags: 'w' }) ); return true; // 解密成功返回标记 } catch (err) { console.error('解密过程出错:', err); return false; } }
在Electron + React中使用的关键细节
- 获取文件路径:
如果是通过前端File API拿到的文件,在Electron渲染进程开启nodeIntegration的情况下,可以直接通过file.path获取本地路径;也可以用Electron的弹窗让用户选择文件:// 渲染进程中(需开启remote模块或通过IPC调用主进程) const { dialog } = require('electron').remote; async function handleEncrypt() { const selectResult = await dialog.showOpenDialog({ filters: [{ name: '支持的文件', extensions: ['txt', 'pdf', 'jpg', 'png'] }] }); if (!selectResult.canceled && selectResult.filePaths.length > 0) { const inputPath = selectResult.filePaths[0]; const outputPath = `${inputPath}.encrypted`; // 给加密文件加后缀区分 const userPassphrase = '这里替换为用户输入的密码'; // 建议用React表单收集用户密码 const success = await encryptFile(inputPath, userPassphrase, outputPath); if (success) dialog.showMessageBox({ message: '加密完成!' }); } } - 权限与打包:打包Electron应用时,确保不要限制文件系统的读写权限,否则会无法操作文件。
- 密码安全:绝对不要硬编码密码,一定要让用户输入;如果需要记住密码,可以用Electron的
safeStorage模块加密存储。
内容的提问来源于stack exchange,提问作者Manish
相关产品推荐
相关产品推荐

