我试图使用WebCrypto API签署数据,但是不是创建一个私有/公共密钥并将其导出到pkcs#1或8,我真的想使用用户的PKCS#12签署数据.我已经阅读了W3C规范,但不能做太多的事情,也找不到任何有关如何做到这一点的好材料.现在我想把ActiveX和
Java Applet放在一边.有没有办法调整以下内容:
var buffer = encode(prompt("Please enter your password")); //TODO: //implement a prompt for a pfx or cert return crypto.subtle.importKey("raw",buffer,"PBKDF2",false,usages); //TODO: //instead of importing it,ask for the certificate's pass to sign data //with crypto.subtle.sign
任何指针?
UPDATE
这是我一直在工作的代码
<script src="forge.min.js"></script> <script> var errorsReportedByVerifier; errorsReportedByVerifier = checkStorage() && checkBrowserAPIs(); if (!errorsReportedByVerifier){ console.log("adding click event"); document.getElementById('btnPfx').addEventListener('click',handlePFXFile,false); storeVariables(); getVariables(); } function handlePFXFile(evnt) { console.log("handling pfx") //alert(document.getElementById('pfx').value); //error happens in 1st line //error object does not accept property replace //forge.min.js Line 1,Column: 17823 var p12Der = forge.util.decode64(document.getElementById('pfx').valueOf()); //var pkcs12Asn1 = forge.asn1.fromDer(p12Der); //var pkcs12 = forge.pkcs12.pkcs12FromAsn1(pkcs12Asn1,'pss'); console.log("pkcs12"); } </script>
解决方法
Web加密api不支持PKCS#12.您可以使用第三方库将p12解码为forge
https://github.com/digitalbazaar/forge#pkcs12,并在webcrypto中加载privateKey
阅读PKCS#12证书
PKCS#12存储在DER中,因此首先从文件读取它或使用预存的base64
//Reading certificate from a 'file' form field var reader = new FileReader(); reader.onload = function(e) { var contents = e.target.result; var pkcs12Der = arrayBufferToString(contents) var pkcs12B64 = forge.util.encode64(pkcs12Der); //do something else... } reader.readAsArrayBuffer(file); function arrayBufferToString( buffer ) { var binary = ''; var bytes = new Uint8Array( buffer ); var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode( bytes[ i ] ); } return binary; } //p12 certificate stored in Base64 format var pkcs12Der= forge.util.decode64(pkcs12B64);
解密PKCS#12,伪造并提取私钥
然后将DER格式解码为ASN1,并使伪造读取内容
var pkcs12Asn1 = forge.asn1.fromDer(pkcs12Der); var pkcs12 = forge.pkcs12.pkcs12FromAsn1(pkcs12Asn1,password);
然后从pkcs12获取所需证书的私钥(参见forge doc)并转换为PKCS#8以使用webcrypto导入
// load keypair and cert chain from safe content(s) for(var sci = 0; sci < pkcs12.safeContents.length; ++sci) { var safeContents = pkcs12.safeContents[sci]; for(var sbi = 0; sbi < safeContents.safeBags.length; ++sbi) { var safeBag = safeContents.safeBags[sbi]; // this bag has a private key if(safeBag.type === forge.pki.oids.keyBag) { //Found plain private key privateKey = safeBag.key; } else if(safeBag.type === forge.pki.oids.pkcs8ShroudedKeyBag) { // found encrypted private key privateKey = safeBag.key; } else if(safeBag.type === forge.pki.oids.certBag) { // this bag has a certificate... } } }
转换为PKCS#8
_privateKeyToPkcs8 function (privateKey) { var rsaPrivateKey = forge.pki.privateKeyToAsn1(privateKey); var privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey); var privateKeyInfoDer = forge.asn1.toDer(privateKeyInfo).getBytes(); var privateKeyInfoDerBuff = stringToArrayBuffer(privateKeyInfoDer); return privateKeyInfoDerBuff; } function stringToArrayBuffer(data){ var arrBuff = new ArrayBuffer(data.length); var writer = new Uint8Array(arrBuff); for (var i = 0,len = data.length; i < len; i++) { writer[i] = data.charCodeAt(i); } return arrBuff; }
导入密钥在Webcrypto
最后导入webcrypto的密钥
function _importCryptoKeyPkcs8(privateKey,extractable) { var privateKeyInfoDerBuff = _privateKeyToPkcs8(privateKey); //Importa la clave en la webcrypto return crypto.subtle.importKey( 'pkcs8',privateKeyInfoDerBuff,{ name: "RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}},extractable,["sign"]); } _importCryptoKeyPkcs8(entry.privateKey,extractable). then(function(cryptoKey) { //your cryptokey is here!!! }
电子签名
使用从上述方法返回的导入的cryptoKey,您可以使用webcrypto进行签名.
var digestToSign = forge.util.decode64(digestToSignB64); var digestToSignBuf = stringToArrayBuffer(digestToSign); crypto.subtle.sign( {name: "RSASSA-PKCS1-v1_5"},cryptoKey,digestToSignBuf) .then(function(signature){ signatureB64 = forge.util.encode64(arrayBufferToString(signature)) }
我包括来自base64的编码,因为数据转换不是微不足道的
在pkc12中,如果您需要构建像AdES这样的高级格式,您也可以拥有认证链