如何使用CryptoJS通过AES算法实现文件加密?
将RC4加密迁移到AES的解决方案
AES是块加密算法,和流加密的RC4调用逻辑完全不同,直接替换方法名肯定无法运行。核心差异在于:
- AES需要初始化向量(IV),解密时必须和加密时使用的IV完全一致
- AES要求密钥长度符合算法标准(128/192/256位),且需指定加密模式(默认CBC)
- CryptoJS的AES加密需要明确处理IV的存储与读取,不能像RC4那样直接传入明文和密钥
以下是修改后的完整代码,替换原RC4相关逻辑:
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js" integrity="sha512-E8QSvWZ0eCLGk4km3hxSsNmGWbLtSCSUcewDQPQWZF6pEU8GlT8a5fF32wOl1i8ftdMhssTrF/OhyGWwonTcXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <div> <h1>encrypt/decrypt file</h1> <ol> <li>Set password</li> <li>Pick a file</li> <li>Download decrypted/encrypted file</li> </ol> <div> <input type="text" id="pass" placeholder="pass"> <button id="encrypt">encrypt file</button> <button id="decrypt">decrypt file</button> <button id="test">test</button> </div> </div> <script> // 保留原辅助函数不变 const download = (data, filename, type) => { const file = new Blob([data], { type: type }); const a = document.createElement('a'); const url = URL.createObjectURL(file); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); setTimeout(function() { document.body.removeChild(a); window.URL.revokeObjectURL(url); }, 0); }; const pickAFile = (getText = true) => { return new Promise((resolve, reject) => { const input = document.createElement('input'); input.type = 'file'; input.onchange = (e) => { const file = e.target.files[0]; const reader = new FileReader(); if (!getText) { resolve(file); } else { reader.onload = (e) => resolve(e.target.result); reader.onerror = (e) => reject(e); reader.readAsText(file); } }; input.click(); }); }; const convertWordArrayToUint8Array = (wordArray) => { const arrayOfWords = wordArray.hasOwnProperty('words') ? wordArray.words : []; const length = wordArray.hasOwnProperty('sigBytes') ? wordArray.sigBytes : arrayOfWords.length * 4; const uInt8Array = new Uint8Array(length); let index = 0; let word; let i; for (i = 0; i < length; i++) { word = arrayOfWords[i]; uInt8Array[index++] = word >> 24; uInt8Array[index++] = (word >> 16) & 0xff; uInt8Array[index++] = (word >> 8) & 0xff; uInt8Array[index++] = word & 0xff; } return uInt8Array; }; // /辅助函数结束 function app() { const passNode = document.querySelector('input#pass'); const encryptNode = document.querySelector('#encrypt'); const decryptNode = document.querySelector('#decrypt'); encryptNode.addEventListener('click', () => { if (!passNode.value) return alert('Password input is empty! Aborting.'); // 用SHA3生成256位密钥,适配AES-256标准 const key = CryptoJS.SHA3(passNode.value); // 生成16字节随机IV(AES块大小固定为16字节) const iv = CryptoJS.lib.WordArray.random(16); pickAFile(false).then((file) => { const reader = new FileReader(); reader.onload = (e) => { const wordArray = CryptoJS.lib.WordArray.create(e.target.result); // AES加密:指定密钥、IV,使用默认CBC模式 const encrypted = CryptoJS.AES.encrypt(wordArray, key, { iv: iv }); // 将IV与密文拼接为"IV:密文"格式(均为Base64编码),方便解密时拆分 const encryptedData = `${iv.toString(CryptoJS.enc.Base64)}:${encrypted.ciphertext.toString(CryptoJS.enc.Base64)}`; download(encryptedData, `encrypted-${file.name}`, 'text/plain'); }; reader.readAsArrayBuffer(file); }); }); decryptNode.addEventListener('click', () => { if (!passNode.value) return alert('Password input is empty! Aborting.'); const key = CryptoJS.SHA3(passNode.value); pickAFile(true).then((encryptedText) => { try { // 拆分IV与密文 const [ivBase64, ciphertextBase64] = encryptedText.split(':'); const iv = CryptoJS.enc.Base64.parse(ivBase64); const ciphertext = CryptoJS.enc.Base64.parse(ciphertextBase64); // AES解密:传入密文对象、密钥和IV const decrypted = CryptoJS.AES.decrypt( { ciphertext: ciphertext }, key, { iv: iv } ); const typedArray = convertWordArrayToUint8Array(decrypted); download(typedArray, `decrypted-${file.name}`, file.type); } catch (error) { console.log('wrong password or invalid encrypted data!'); } }); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', app); } else { app(); } </script>
关键改动说明
- IV处理:每次加密生成随机IV,并与密文一起存储,解密时必须使用相同IV才能正确还原数据
- 密钥适配:原代码用SHA3生成的32字节(256位)密钥刚好符合AES-256的要求,无需修改密钥生成逻辑
- 加密结果存储:将IV和密文用冒号分隔保存为Base64字符串,确保解密时能准确拆分出所需参数
- 解密逻辑调整:从加密文件中拆分IV和密文后,再传入AES解密方法完成解密
内容的提问来源于stack exchange,提问作者Oleksandr
相关产品推荐
相关产品推荐

