Node.js的crypto模块能否处理视频文件的加密解密?
问题原因
- 你当前使用的
crypto.createCipher()与crypto.createDecipher()属于Node.js官方已经废弃的API,其内部基于密码自动派生密钥和IV(初始化向量)的逻辑依赖OpenSSL底层实现,不同Node版本可能存在兼容差异,且默认派生策略安全性极低。 - 视频文件体积通常远大于音频文件,你大概率是在写入流还未完全触发
finish事件、所有数据未完全落盘的情况下就尝试打开输出文件,此时文件不完整自然无法播放;音频文件因为体积小,流处理完成速度快,所以你测试时刚好是写完的状态,就可以正常播放。 - AES-256-CBC算法要求必须使用16字节的IV、32字节的密钥,旧API自动派生的参数在处理大体积二进制文件时,偶尔会出现填充逻辑异常,导致末尾块数据损坏。
修正后的实现代码
请使用官方推荐的createCipheriv/createDecipheriv接口,且等待流处理完成后再操作输出文件:
const crypto = require('crypto'); const fs = require('fs'); // aes-256-cbc要求密钥32字节,IV16字节,生产环境请把密钥存在环境变量中,不要硬编码 const algorithm = 'aes-256-cbc'; // 基于密码派生32字节密钥,第二个参数为盐值,可自行修改 const key = crypto.scryptSync('d6F3Efeq', 'custom_salt_2024', 32); // 加密方法 function encryptFile(inputPath, outputPath) { // 每次加密随机生成16位IV const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv(algorithm, key, iv); const input = fs.createReadStream(inputPath); const output = fs.createWriteStream(outputPath); // 将IV写入加密文件开头,解密时需要读取 output.write(iv); input.pipe(cipher).pipe(output); return new Promise((resolve, reject) => { output.on('finish', resolve); output.on('error', reject); }); } // 解密方法 function decryptFile(inputPath, outputPath) { // 先读取加密文件前16位的IV const ivBuffer = Buffer.alloc(16); const fd = fs.openSync(inputPath, 'r'); fs.readSync(fd, ivBuffer, 0, 16, 0); fs.closeSync(fd); // 读取加密内容时跳过前16位IV const input = fs.createReadStream(inputPath, { start: 16 }); const decipher = crypto.createDecipheriv(algorithm, key, ivBuffer); const output = fs.createWriteStream(outputPath); input.pipe(decipher).pipe(output); return new Promise((resolve, reject) => { output.on('finish', resolve); output.on('error', reject); }); } // 测试流程 (async () => { await encryptFile('video.mp4', 'video.enc'); await decryptFile('video.enc', 'video.out4.mp4'); console.log('加解密全部完成,现在可正常打开输出视频文件'); })();
内容的提问来源于stack exchange,提问作者Kseniia Kotenko
相关产品推荐
相关产品推荐

