為什么要做加密解密?主要是避免第三方檢測系統(WAF)檢測出文件有問題,但是文件是用戶上傳的,我們控制不了這些文件,所以主要是通過對用戶上傳文件進行加密,后臺解密后存儲。
前端:
1: 安裝crypto-js
npm install crypto-js -save
2: 編寫工具:
import CryptoJS from 'crypto-js'
export function encryptFile(file) {// console.log("32---->: ",CryptoJS.lib.WordArray.random(32).toString(CryptoJS.enc.Hex).substring(0, 32))// console.log("16---->: ", CryptoJS.lib.WordArray.random(16).toString(CryptoJS.enc.Hex).substring(0, 16))const key = CryptoJS.enc.Utf8.parse("16ByteFixedKey12"); // 密鑰需與后端一致?:ml-citation{ref="8" data="citationList"}// console.log("key->: ",key)// const iv = CryptoJS.enc.Utf8.parse("f468c06be3fea831"); // IV需與后端一致?:ml-citation{ref="8" data="citationList"}const iv = CryptoJS.enc.Utf8.parse('Fixed16ByteIV456'); // IV需與后端一致?:ml-citation{ref="8" data="citationList"}// console.log("iv---->: ", iv)return new Promise((resolve, reject) => {const reader = new FileReader();reader.onload = (e) => {// const fileData = CryptoJS.lib.WordArray.create(e.target.result);const fileData = new Uint8Array(e.target.result);const wordArray = CryptoJS.lib.WordArray.create(fileData);const encrypted = CryptoJS.AES.encrypt(wordArray, key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});// 轉換為二進制Blob并上傳?:ml-citation{ref="4,5" data="citationList"}const encryptedBlob = new Blob([encrypted.toString()], { type: "application/octet-stream" });const encryptedFile = new File([encryptedBlob],file.name,{ type: "application/octet-stream" });encryptedFile.uid = file.uidresolve(encryptedFile); // 返回 Base64 格式密文};reader.readAsArrayBuffer(file.raw);});
}
3: 使用工具
// 收集所有加密的 Promiseconst promises = [];this.$refs.upload.$refs['upload-inner'].fileList.forEach(v => {if (v.status === 'ready') {const encryptPromise = encryptFile(v).then(res => {v.raw = resreturn v; // 返回 Promise 的結果});promises.push(encryptPromise); // 將 Promise 添加到數組}});// 等待所有加密操作完成后再提交Promise.all(promises).then(() => {// console.log("加密后")this.$refs.upload.submit(); // 所有加密完成后提交}).catch(error => {console.error('加密失敗:', error);this.loading = false;});
后臺(grails)
1: 增加包
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
2: 編寫解密方法:
def decryptFile(def file) {def encryptedFile = file.inputStreamprintln file.originalFilenamebyte[] encryptedData = IOUtils.toByteArray(encryptedFile)// 將 Base64 字符串解碼為原始密文字節數組String encryptedString = new String(encryptedData, "UTF-8")byte[] decodedData = java.util.Base64.getDecoder().decode(encryptedString)// 初始化解密器?:ml-citation{ref="8" data="citationList"}SecretKeySpec secretKey = new SecretKeySpec("16ByteFixedKey12".getBytes("UTF-8"), "AES")IvParameterSpec ivSpec = new IvParameterSpec("Fixed16ByteIV456".getBytes("UTF-8"))Security.addProvider(new BouncyCastleProvider())Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC")cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec)// 執行解密?:ml-citation{ref="8" data="citationList"}return cipher.doFinal(decodedData);
// byte[] decryptedBytes = cipher.doFinal(decodedData)
//
// // 保存解密文件?:ml-citation{ref="5" data="citationList"}
// new File("/Users/zhangjiayu/Desktop/project/files/test.pdf").withOutputStream { it.write(decryptedBytes) }}
注意:
?前后臺使用的key【16ByteFixedKey12】和IV【Fixed16ByteIV456】需要保持一致