今天下午和
一个妹子聊到在前端做AES加密,妹子说有一些开源的库,我想webcrypto提出来这么多年,应该
主流浏览器很多也应该有原生的支持了吧?写个加测试页面试试看:
<!DOCTYPE html>
<html>
<head>
<META NAME="Author" CONTENT="emu">
<META NAME="Keywords" CONTENT="webcrypto AES-CBC AES-GCM">
</head>
<body>
<div id="out"></div>
<script type="text/javascript">
function output(sign) {
document.getElementById("out").innerHTML += sign + "<br>";
}
function bufferToHex(b){
var dataview = new DataView(b);
result = "";
for (var i = 0; i < b.byteLength; i += 4) {
tmp = dataview.getUint32(i).toString(16);
result += (tmp.length == 8 ? "" : "0") + tmp;
}
return result;
}
function bufferToString(b){
//new TextDecoder().decode(b)
var hex=bufferToHex(b);
var result=unescape(hex.replace(/(..)/g,"%$1"));
return result;
}
function stringToBuffer(s){
//new TextEncoder().encode(s);
var a = s.split("");
for (var i = 0; i < a.length; i++) {
a[i] = a[i].charCodeAt(0)
};
var result = new Uint8Array(a);
return result;
}
var textToBeEncrypted = 'Hello World!';
var bufferToBeEncrypted=stringToBuffer(textToBeEncrypted);
var bufferToBeDecrypted;
var pwd="let me try this password"
var password = stringToBuffer(pwd);
var sAlg="AES-CBC";//AES-GCM部分浏览器不支持
var c = window.crypto || window.msCrypto;
var subtle = c.subtle || c.webkitSubtle;
var iv = c.getRandomValues(new Uint8Array(16));
var alg = { name: sAlg, iv: iv };
var op=c.subtle.digest('SHA-256', password)
var encryptKey,decryptKey,hash;
if(("then" in op)){
op.then(function(buffer){
hash=buffer;
c.subtle.importKey('raw', hash, alg, false, ['encrypt']).then(function(buffer){
encryptKey=buffer;
c.subtle.importKey('raw', hash, alg, false, ['decrypt']).then(function(buffer){
decryptKey=buffer;
doEncrypt(alg,encryptKey);
})
})
});
}else{
op.oncomplete=function(e){
var hash=e.target.result;
var op=c.subtle.importKey('raw', hash, alg, false, ['encrypt']);
op.oncomplete=function(e){
encryptKey=e.target.result;
op=c.subtle.importKey('raw', hash, alg, false, ['decrypt']);
op.oncomplete=function(e){
decryptKey=e.target.result;
encryptWithCryptoOperation(alg,encryptKey);
}
}
}
}
function doEncrypt(alg,encryptKey){
var op = c.subtle.encrypt(alg, encryptKey, bufferToBeEncrypted);
op.then(function(buffer){
bufferToBeDecrypted=buffer;
output("pwd: <b><i>"+pwd+"</i></b> alg:<b>"+sAlg+"</b> <br>encrypt("+textToBeEncrypted + ")="+ bufferToHex(buffer));
doDecrypt(alg,decryptKey);
})
}
function doDecrypt(alg,decryptKey){
var op = c.subtle.decrypt(alg, decryptKey, bufferToBeDecrypted);
op.then(function(buffer){
output("pwd:<b><i>"+pwd+"</i></b> alg:<b>"+sAlg+"</b> <br>decrypt("+bufferToHex(bufferToBeDecrypted) + ")="+ bufferToString(buffer));
})
}
function encryptWithCryptoOperation(alg,encryptKey){
var op = c.subtle.encrypt(alg, encryptKey);
op.onerror=function(e){output(sAlg+" unsupported")}
op.process(bufferToBeEncrypted);
op.oncomplete=function(e){
bufferToBeDecrypted=e.target.result
output("pwd: <b><i>"+pwd+"</i></b> alg:<b>"+sAlg+"</b> <br>encrypt("+textToBeEncrypted + ")="+ bufferToHex(bufferToBeDecrypted));
//decryptWithCryptoOperation(alg,decryptKey)
setTimeout(decryptWithCryptoOperation,0,alg,decryptKey)
}
op.finish();
}
function decryptWithCryptoOperation (alg,decryptKey){
var op = c.subtle.decrypt(alg, decryptKey);
op.onerror=function(e){(sAlg+" unsupported")}
op.process(bufferToBeDecrypted);
op.oncomplete=function(e){
if(!e.target.result){
output("IE is crazy!<br>");
encryptWithCryptoOperation(alg,encryptKey)
}else
output("pwd:<b><i>"+pwd+"</i></b> alg:<b>"+sAlg+"</b> <br>decrypt("+bufferToHex(bufferToBeDecrypted) + ")="+ bufferToString(e.target.result));
}
op.finish();
}
</script>
</body>
</html>
测试下来感觉各个浏览器支持程度还是参差不齐,IE11和Edge都是不同的实现方式,IE11甚至还会随机出现oncomplete的时候result数据都还没有ready的情况,甚至于有的时候完全相同的入参(包括随机数也相同)加密出来的结果居然会不同,也就是说有的时候加密算法自己会加密错,出来的结果根本就无法被正确解密,实在是个半成品:
(第一次加密错了,第二次加密对了解密错了,第三次终于加解密都对了)
(第一次加密错了,第二次对了)