使用Web Crypto导入PEM密钥

时间:2017-01-08 03:19:10

标签: javascript webcryptoapi

我将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"]);}

不幸的是,它会返回此错误:

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);
    }));
}

1 个答案:

答案 0 :(得分:1)

您无法使用RSA-OAEP私钥进行加密。问题可能是由于您在导入时在密钥用法中设置了encrypt标记。

请参阅webcrypto规范,第22.4节https://w3c.github.io/webcrypto/Overview.html#rsa-oaep

  

如果key的[[type]]内部插槽不是“public”,则抛出InvalidAccessError。

<强>已更新

函数base64StringToArrayBuffer不正确

 b64str = b64EncodeUnicode(b64str);
 var byteStr = atob(b64str); 

PEM是base64编码的,函数b64EncodeUnicode正在对内容进行两次编码。

请参阅我的答案https://stackoverflow.com/a/38714970/6371459,其中包含生成RSA-OAEP密钥,导出,编码到PEM,再次解码和导入的完整示例(注意:不使用标题)

替换这两行
function b64DecodeUnicode(str) {
    return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
}