早年在web端做对称/非对称的加解密还是个很复杂的操作,由于没有js层面的基础库。很多基础设施只能从头开始。
QQ登录注册之前使用的RSA加密算法就是参考http://www-cs-students.stanford.edu/~tjw/jsbn/的实现。
还有各种aes/md5/sha等常用算法的js库也是层出不穷。但是由于大多都是个人项目,很多库并没有很好的维护,对于不同的算法支持也不是很完整。比如基于https://github.com/travist/jsencrypt就缺少RSA/OEAP的支持,https://github.com/ricmoo/aes-js也缺少AES/GCM的支持。
当然近些年来Web标准突飞猛进。对于常用密码学套件来说,最大的新增特性就是Web Crypto API了。
Web Crypto API提供了常用算法的加密/解密/签名/验证/摘要/key生成/协商等操作,功能上和nodejs中的crypto模块基本等同,也就是Web端的OpenSSL了。
但是由于接口和nodejs中的crypto不同,Web Crypto API统一采用的Promise来处理异步逻辑,而不是nodejs中的回调。这样可以很方便的使用await/async简化代码。
针对摘要算法提供的是disgest接口,这个接口可以提供SHA-1/SHA-256/SHA-384/SHA-512的摘要算法。
对于MD5等老旧的算法是不支持的。SHA-1这里也很特殊标准之前是规定支持这个算法,但是由于SHA-1本身存在缺陷,已经建议不使用,从浏览器来看就是移除SHA-1的支持。
window.crypto.subtle.digest(
{
name: "SHA-256",
},
new Uint8Array([1,2,3,4])
)
.then(function(hash){
console.log(new Uint8Array(hash));
})
.catch(function(err){
console.error(err);
});
这里比较特殊的就是接口的输入和输出都是ArrayBuffer相关的类
除了摘要算法之外,加解密签名都需要密钥来操作。涉及到的主要就是密钥生成/导入/导出。、
下面是生成密钥的示例代码
window.crypto.subtle.generateKey(
{
name: "RSASSA-PKCS1-v1_5",//算法名称
hash: {name: "SHA-256"}, //签名时的hash算法
//RSA参数
modulusLength: 2048, //私钥长度
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
//EC参数
namedCurve: "P-256",//曲线名字
//AES参数
length: 256, //密钥长度
},
false, //是否可以被导出
["sign", "verify"] //该key支持的操作
)
.then(function(key){
//这里获取的key可以用于后续加解密签名等操作
console.log(key);
})
.catch(function(err){
console.error(err);
});
当然除了本地生成密钥还有导入外部密钥
window.crypto.subtle.importKey(
"jwk", //密钥格式
{ //密钥内容
kty: "oct",
k: "Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE",
alg: "A256CTR",
ext: true,
},
{ //密钥算法
name: "AES-CTR",
},
false, //是否能被导出
["encrypt", "decrypt"] //支持的操作模式
)
这里比较让人疑惑的就是密钥格式和密钥内容两个参数了
通常我们使用的密钥格式为PEM/DER。而上述例子中的jwk指的是JSON Web Key
。具体可以参见rfc7517。
对于常见的PEM格式我们需要使用其中有效内容部分。即BEGIN/END之间的部分所以我们可以将其中内容提取出来之后base64解码。
function convertPemToBinary(pem) {
var lines = pem.split('\n')
var encoded = ''
for (var i = 0; i < lines.length; i++) {
if (lines[i].trim().length > 0 &&
!/-----BEGIN .*-----/.test(lines[i]) &&
!/-----END .*-----/.test(lines[i])) {
encoded += lines[i].trim()
}
}
return base64StringToArrayBuffer(encoded)
}
function base64StringToArrayBuffer(b64str) {
var byteStr = atob(b64str)
var bytes = new Uint8Array(byteStr.length)
for (var i = 0; i < byteStr.length; i++) {
bytes[i] = byteStr.charCodeAt(i)
}
return bytes.buffer
}
DER格式则就是PEM中具体的内容。
对于EC/RSA公钥使用pkcs8的PEM/DER格式的实际数据配合密钥格式spki
就可以导入了。
而私钥则是pkcs8格式的实际数据配合密钥格式pkcs8
。
对称密钥则可以通过raw
加上实际密钥内容导入。
导出操作则相对简单
window.crypto.subtle.exportKey(
"jwk", //密钥格式
key //密钥
)
.then(function(keydata){
console.log(keydata);
})
.catch(function(err){
console.error(err);
});
window.crypto.subtle.encrypt(
{
name: "RSA-OAEP",
},
publicKey,
data
)
.then(function(encrypted){
console.log(new Uint8Array(encrypted));
})
.catch(function(err){
console.error(err);
});
window.crypto.subtle.decrypt(
{
name: "RSA-OAEP",
},
privateKey,
data
)
.then(function(decrypted){
console.log(new Uint8Array(decrypted));
})
.catch(function(err){
console.error(err);
});
加解密的接口都类似,输入算法/密钥/数据,输出结果。这里输入输出的数据也都是ArrayBuffer的格式
window.crypto.subtle.sign(
{
name: "RSASSA-PKCS1-v1_5",
},
privateKey,
data
)
.then(function(signature){
console.log(new Uint8Array(signature));
})
.catch(function(err){
console.error(err);
});
window.crypto.subtle.verify(
{
name: "RSASSA-PKCS1-v1_5",
},
publicKey,
signature,
data
)
.then(function(isvalid){
console.log(isvalid);
})
.catch(function(err){
console.error(err);
});
签名和验证签名的接口也是类似。
Web Crypto API的入口是window.crypto.subtle
。
所有的接口都是window.crypto.subtle
的方法。所有接口的返回都是Promise
对象。
涉及密钥操作的算法需要先生成或导入密钥。导入密钥的格式有raw
,spki
,pkcs8
,jwk
。raw用于对称密钥直接导入的情况,spki则是DER格式的公钥,pkcs8时DER格式的pkcs8私钥,jwk则支持所有的场景,但是需要转换。
所有算法输入输出均为ArrayBuffer
具体浏览器支持可以参见https://caniuse.com/#feat=cryptography
针对旧浏览器的polyfill/shim可以看https://github.com/vibornoff/webcrypto-shim和https://github.com/PeculiarVentures/webcrypto-liner
常见的样例代码可以参见https://github.com/diafygi/webcrypto-examples
最后Web Crypto API
由于属于安全接口,在非https的页面上可能不可用(chrome中)。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有