Pet*_*lak 4 javascript base64 pem arraybuffer webcrypto-api
我想知道如何解决这个问题。我使用 WebCrypto API 生成 RSA-OAEP 密钥对,然后从导出为 ArrayBuffer 的密钥对中导出 pkcs8 中的私钥,并且我想将此 ArrayBuffer 编码为 base64,以便可以将其存储为 PEM。
\n\n在此测试示例中,我将密钥导出为 pkcs8 并将此 pkcs8 导入回 CryptoKey。问题是有时有效有时无效。
\n\n这些是代码的结果:\n注意:仅发生这些状态之一,而不是同时发生。\n注意2:此示例不包含 -----BEGIN PRIVATE KEY----- 前缀和后缀 我仅对钥匙。
\n\nCase1:未捕获(在承诺中)URIError:URI格式错误(\ xe2 \ x80 \ xa6)b64DecodeUnicode @ try.php:20b64toab @ try.php:70wayBack @ try.php:66(匿名函数)@ try.php:56
\n\nCase2:未定义:1未捕获(承诺中)DOMException
\n\nCase3:好的 - 一直可以正常工作。
\n\n我不知道是什么原因导致了错误,但我认为这与 base64 编码有关。正如我所说,有时私钥生成正常,有时则不行。
\n\n非常感谢您提前提供的每一个帮助。
\n\nfunction b64EncodeUnicode(str) {\n return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {\n return String.fromCharCode(\'0x\' + p1);\n }));\n}\n\nfunction b64DecodeUnicode(str) {\n return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {\n return \'%\' + (\'00\' + c.charCodeAt(0).toString(16)).slice(-2);\n }).join(\'\'));\n}\n\nfunction addNewLines(str) {\n var finalString = \'\';\n for(var i=0; i < str.length; i++) {\n finalString += str.substring(0, 64) + \'\\n\';\n str = str.substring(64);\n }\n\n return finalString;\n}\n\nwindow.crypto.subtle.generateKey(\n {\n name: "RSA-OAEP",\n modulusLength: 2048,\n publicExponent: new Uint8Array([0x01, 0x00, 0x01]),\n hash: {name: "SHA-256"}\n },\n true,\n ["encrypt", "decrypt"]\n).then(function(keyPair) {\n window.crypto.subtle.exportKey(\n "pkcs8",\n keyPair.privateKey\n ).then(function(exportedPrivateKey) {\n var byteArray = new Uint8Array(exportedPrivateKey);\n console.log(byteArray);\n var byteString = \'\';\n for(var i=0; i < byteArray.byteLength; i++) {\n byteString += String.fromCodePoint(byteArray[i]);\n }\n\n wayBack(addNewLines(b64EncodeUnicode(byteString)));\n });\n});\n\nfunction wayBack(pem) {\n var lines = pem.split(\'\\n\');\n var encodedString = \'\';\n for(var i=0; i < lines.length; i++) {\n encodedString += lines[i].trim();\n }\n b64toab(encodedString);\n}\n\nfunction b64toab(b64) {\n var byteString = b64DecodeUnicode(b64);\n console.log(byteString);\n var byteArray = new Uint8Array(byteString.length);\n for(var i=0; i < byteString.length; i++) {\n byteArray[i] = byteString.codePointAt(i);\n }\n console.log(byteArray);\n\n window.crypto.subtle.importKey(\n "pkcs8",\n byteArray,\n {\n name: "RSA-OAEP",\n hash: {name: "SHA-256"}\n },\n true,\n ["decrypt"]\n ).then(function(importedPrivateKey) {\n console.log(importedPrivateKey);\n });\n}\nRun Code Online (Sandbox Code Playgroud)\n
当您将字符串拆分为 64 个字符的块时,您忘记了包含 PEM 的最后部分。只需添加finalString += str;到addNewLines
function addNewLines(str) {
var finalString = '';
for(var i=0; i < str.length; i++) {
finalString += str.substring(0, 64) + '\n';
str = str.substring(64);
}
finalString += str;
return finalString;
}
Run Code Online (Sandbox Code Playgroud)
我重构了你的例子来看看发生了什么。如果您认为有用,请使用以下代码
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
function b64DecodeUnicode(str) {
return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
function addNewLines(str) {
var finalString = '';
for(var i=0; i < str.length; i++) {
finalString += str.substring(0, 64) + '\n';
str = str.substring(64);
}
finalString += str;
return finalString;
}
function removeLines(pem) {
var lines = pem.split('\n');
var encodedString = '';
for(var i=0; i < lines.length; i++) {
encodedString += lines[i].trim();
}
return encodedString;
}
function stringToArrayBuffer(byteString){
var byteArray = new Uint8Array(byteString.length);
for(var i=0; i < byteString.length; i++) {
byteArray[i] = byteString.codePointAt(i);
}
return byteArray;
}
function arrayBufferToString(exportedPrivateKey){
var byteArray = new Uint8Array(exportedPrivateKey);
var byteString = '';
for(var i=0; i < byteArray.byteLength; i++) {
byteString += String.fromCodePoint(byteArray[i]);
}
return byteString;
}
window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {name: "SHA-256"}
},
true,
["encrypt", "decrypt"]
).then(function(keyPair) {
window.crypto.subtle.exportKey(
"pkcs8",
keyPair.privateKey
).then(function(exportedPrivateKey) {
var privateKeyDer = arrayBufferToString(exportedPrivateKey); //pkcs#8 to DER
var privateKeyB64 = b64EncodeUnicode(privateKeyDer); //btoa(privateKeyDer);
var privateKeyPEMwithLines = addNewLines(privateKeyB64); //split PEM into 64 character strings
var privateKeyPEMwithoutLines = removeLines(privateKeyPEMwithLines); //join PEM
var privateKeyDerDecoded = b64DecodeUnicode(privateKeyPEMwithoutLines); // atob(privateKeyB64);
var privateKeyArrayBuffer = stringToArrayBuffer(privateKeyDerDecoded); //DER to arrayBuffer
window.crypto.subtle.importKey( //importKEy
"pkcs8",
privateKeyArrayBuffer,
{
name: "RSA-OAEP",
hash: {name: "SHA-256"}
},
true,
["decrypt"]
).then(function(importedPrivateKey) {
console.log(importedPrivateKey);
});
});
});
Run Code Online (Sandbox Code Playgroud)