在做Web項目的過程中,由於要通過頁面上傳多個文件,而我們在后台計算過程中僅需要文件的哈希值,為了節省帶寬,我們選擇在前端頁面進行文件哈希值計算,然后把哈希值傳遞給后台,這樣避免了傳遞大量文件。
CryptoJS為JavaScript庫,提供了各種各樣的加密算法,包括MD5、SHA1、SHA256、AES、Rabbit等
(一)CryptoJS Github地址:
https://github.com/brix/crypto-js
(二)使用方法
1)引入核心js文件,需要使用的算法對應的js文件
2)cryptojs支持對字符串計算,或者對WordArray類型(CryptoJS自己封裝的數據類型)值的計算,如果需要對文件進行哈希值計算,則使用WordArray方式。
示例:
//String
var sha1Encrypt = CryptoJS.SHA1("Message");
var sha256Encrypt = CryptoJS.SHA256("Message");
//WordArray
var wordArray = CryptoJS.enc.Utf8.parse("cfca1234");
var base64 = CryptoJS.enc.Base64.stringify(wordArray);
3)對文件計算示例
//對文件計算哈希值:
function arrayBufferToWordArray(ab) {
var i8a = new Uint8Array(ab);
var a = [];
for (var i = 0; i < i8a.length; i += 4) {
a.push(i8a[i] << 24 | i8a[i + 1] << 16 | i8a[i + 2] << 8 | i8a[i + 3]);
}
return CryptoJS.lib.WordArray.create(a, i8a.length);
}
function uploadFile(){
var dat = $("#testfile")[0].files[0];
var reader = new FileReader();
reader.readAsArrayBuffer(dat);
reader.onload = function(evt){
console.log(evt.target.result);
var fileString = evt.target.result;
var wordArray = arrayBufferToWordArray(fileString);
var hash = CryptoJS.SHA256(wordArray).toString(CryptoJS.enc.Hex);
$("#file256").text(hash);
}
}
4)CryptoJS update
但是上面的方式會把文件一次性讀入內存,非常耗瀏覽器內存,當文件比較大時,容易導致瀏覽器崩潰,因此采用了CryptoJS update的方式,增量計算哈希值
function loadFile(fileId,hashId){
var contractFile = $("#"+fileId)[0].files[0];
var reader = new FileReader();
var blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice;
// 指定文件分塊大小(2M)
var chunkSize = 6 * 1024 * 1024;
// 計算文件分塊總數
var chunks = Math.ceil(contractFile.size / chunkSize);
// 指定當前塊指針
var currentChunk = 0;
var hasher = CryptoJS.algo.SHA256.create();
// FileReader分片式讀取文件
// 計算開始讀取的位置
var start = currentChunk * chunkSize;
// 計算結束讀取的位置
var end = start + chunkSize >= contractFile.size ? contractFile.size : start + chunkSize;
reader.readAsArrayBuffer(blobSlice.call(contractFile, start, end));
reader.onload = function(evt){
var fileStr = evt.target.result;
var tmpWordArray = arrayBufferToWordArray(fileStr);
hasher.update(tmpWordArray);
currentChunk += 1;
fileStr = null;
tmpWordArray = null;
// 判斷文件是否都已經讀取完
if (currentChunk < chunks) {
// 計算開始讀取的位置
var start = currentChunk * chunkSize;
// 計算結束讀取的位置
var end = start + chunkSize >= contractFile.size ? contractFile.size : start + chunkSize;
reader.readAsArrayBuffer(blobSlice.call(contractFile, start, end));
}
}
reader.onloadend = function(){
contractFile = null;
var fileobj = document.getElementById(fileId);
if(fileobj.outerHTML){
fileobj.outerHTML = fileobj.outerHTML;
}
CollectGarbage();
var hash = hasher.finalize();
$("#"+hashId).val(hash);
hasher = null;
blobSlice = null;
reader = null;
hash = null;
CollectGarbage();
}
}
(三)總結
parse和stringify
var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
var wordArray = CryptoJS.enc.Hex.parse(hexString);
var wordArray = CryptoJS.enc.Base64.parse(base64String);
var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
var hexString = CryptoJS.enc.Hex.stringify(wordArray);
var base64String = CryptoJS.enc.Base64.stringify(wordArray);
消息摘要算法
var hash = CryptoJS.MD5(message);
var hash = CryptoJS.MD5(wordArray);
......
update調用方式
var hasher = CryptoJS.algo.SHA256.create();
hasher.reset();
hasher.update('message');
hasher.update(wordArray);
var hash = hasher.finalize();
var hash = hasher.finalize('message');
var hash = hasher.finalize(wordArray);