使用 Web Crypto 导入 PEM 密钥
Import PEM Keys using Web Crypto
我将 CryptoKey 导出为 PEM 样式,现在我想将其导入回来。
我使用以下代码生成了我的密钥:
function generate() {
return window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {name: "SHA-256"},
},
true,
["encrypt", "decrypt"]
).then(function (key) {
return key;
})
.catch(function (err) {
console.error(err);
});
}
我正在尝试使用下一个代码导入字符串(pem 样式)的私钥:
function importPrivateKey(pemKey) {
return crypto.subtle.importKey("pkcs8", convertPemToBinary(pemKey), {name:"RSA-OAEP", hash:{name:"SHA-256"}}, true, ["encrypt", "decrypt"]);}
不幸的是,它 returns 这个错误:
SyntaxError: Cannot create a key using the specified key usages.
更新
convertPemToBinary 函数
function convertPemToBinary(pem) {
var lines = pem.split('\n');
var encoded = '';
for (var i = 0; i < lines.length; i++) {
if (lines[i].trim().length > 0 &&
lines[i].indexOf('-----BEGIN RSA PRIVATE KEY-----') < 0 &&
lines[i].indexOf('-----BEGIN RSA PUBLIC KEY-----') < 0 &&
lines[i].indexOf('-----BEGIN PUBLIC KEY-----') < 0 &&
lines[i].indexOf('-----END PUBLIC KEY-----') < 0 &&
lines[i].indexOf('-----BEGIN PRIVATE KEY-----') < 0 &&
lines[i].indexOf('-----END PRIVATE KEY-----') < 0 &&
lines[i].indexOf('-----END RSA PRIVATE KEY-----') < 0 &&
lines[i].indexOf('-----END RSA PUBLIC KEY-----') < 0) {
encoded += lines[i].trim();
}
}
return base64StringToArrayBuffer(encoded);
}
convertPemToBinary 函数中使用的子函数:
function base64StringToArrayBuffer(b64str) {
b64str = b64EncodeUnicode(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;
}
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
您不能使用 RSA-OAEP 私钥加密。问题可能是由于您在导入时在密钥用法中设置了 encrypt
标签。
参见 webcrypto 规范,第 22.4 节 https://w3c.github.io/webcrypto/Overview.html#rsa-oaep
If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
已更新
函数base64StringToArrayBuffer
不正确
b64str = b64EncodeUnicode(b64str);
var byteStr = atob(b64str);
PEM 是 base64 编码的,函数 b64EncodeUnicode
是对内容进行两次编码。
在此处查看我的回答 https://whosebug.com/a/38714970/6371459,其中包含生成 RSA-OAEP 密钥、导出、编码为 PEM、解码并再次导入的完整示例(注意:不使用 headers)
将这两行替换为
function b64DecodeUnicode(str) {
return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
我将 CryptoKey 导出为 PEM 样式,现在我想将其导入回来。 我使用以下代码生成了我的密钥:
function generate() {
return window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {name: "SHA-256"},
},
true,
["encrypt", "decrypt"]
).then(function (key) {
return key;
})
.catch(function (err) {
console.error(err);
});
}
我正在尝试使用下一个代码导入字符串(pem 样式)的私钥:
function importPrivateKey(pemKey) {
return crypto.subtle.importKey("pkcs8", convertPemToBinary(pemKey), {name:"RSA-OAEP", hash:{name:"SHA-256"}}, true, ["encrypt", "decrypt"]);}
不幸的是,它 returns 这个错误:
SyntaxError: Cannot create a key using the specified key usages.
更新
convertPemToBinary 函数
function convertPemToBinary(pem) {
var lines = pem.split('\n');
var encoded = '';
for (var i = 0; i < lines.length; i++) {
if (lines[i].trim().length > 0 &&
lines[i].indexOf('-----BEGIN RSA PRIVATE KEY-----') < 0 &&
lines[i].indexOf('-----BEGIN RSA PUBLIC KEY-----') < 0 &&
lines[i].indexOf('-----BEGIN PUBLIC KEY-----') < 0 &&
lines[i].indexOf('-----END PUBLIC KEY-----') < 0 &&
lines[i].indexOf('-----BEGIN PRIVATE KEY-----') < 0 &&
lines[i].indexOf('-----END PRIVATE KEY-----') < 0 &&
lines[i].indexOf('-----END RSA PRIVATE KEY-----') < 0 &&
lines[i].indexOf('-----END RSA PUBLIC KEY-----') < 0) {
encoded += lines[i].trim();
}
}
return base64StringToArrayBuffer(encoded);
}
convertPemToBinary 函数中使用的子函数:
function base64StringToArrayBuffer(b64str) {
b64str = b64EncodeUnicode(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;
}
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
您不能使用 RSA-OAEP 私钥加密。问题可能是由于您在导入时在密钥用法中设置了 encrypt
标签。
参见 webcrypto 规范,第 22.4 节 https://w3c.github.io/webcrypto/Overview.html#rsa-oaep
If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
已更新
函数base64StringToArrayBuffer
不正确
b64str = b64EncodeUnicode(b64str);
var byteStr = atob(b64str);
PEM 是 base64 编码的,函数 b64EncodeUnicode
是对内容进行两次编码。
在此处查看我的回答 https://whosebug.com/a/38714970/6371459,其中包含生成 RSA-OAEP 密钥、导出、编码为 PEM、解码并再次导入的完整示例(注意:不使用 headers)
将这两行替换为
function b64DecodeUnicode(str) {
return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}