如何导入 PEM 格式的 RSA 私钥以用于 WebCrypto?

How can I import an RSA private key in PEM format for use with WebCrypto?

我正在尝试使用 WebCrypto 通过 RSA-PSS 对令牌进行签名,但我一直收到错误消息:

DataError: Data provided to an operation does not meet requirements

crypto.subtle.importKey

这是我的 JavaScript 代码:

function signToken(token, key) {
    crypto.subtle.importKey(
        'pkcs8',
        PEM2Binary(key),
        {
            name: 'RSA-PSS',
            hash: { name: 'SHA-256' },
        },
        false,
        ['sign']
    ).then(function(privKey){
        crypto.subtle.sign(
            'RSA-PSS',
            privKey,
            new TextEncoder().encode(token)
        ).then(function(signedToken){
            msg = JSON.stringify({ intent: 'authenticate-token', signedToken: signedToken });
            socket.send(msg);
        })
    }).catch(function(error){
        console.error(error);
    })
}

function PEM2Binary(pem) {
    var encoded = '';
    var lines = pem.split('\n');
    for (var i = 0; i < lines.length; i++) {
        if (lines[i].indexOf('-----') < 0) {
            encoded += lines[i];
        }
    }
    var byteStr = atob(encoded);
    var bytes = new Uint8Array(byteStr.length);
    for (var i = 0; i < byteStr.length; i++) {
        bytes[i] = byteStr.charCodeAt(i);
    }
    return bytes.buffer;
}

我使用的示例私钥:

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA3d+Y/kWq4nNrJd0dgktQ7lfDUtEIxcs10I8+xPEUhpvacotB
o787dDP4ZFYhRQf0WMjQYJwEna/NsrPuY2fgFWIBlUdpkj1SR00FBxHvnRlzP1Sg
cYnJlqh7/A26tM51nVkMtf/4NtYr+jFvRmB5759U1GRBFwZYsoWQRQlQKh5MAk89
KRc/TvrXNzam39GcLvSYz9uN0p2p2Mrofjgv42m53AqC9LOrQbwDX7Dxl0n4z3EI
Z2Ycx33QZVYiLPH1GHTJ8+JuKjqY0ovu6lghGN0y2xR+sqWNvgyW7xlDWZ6Vwyxs
K5SCIc48VwiiAyGZGhcCZloMlO5S/dutycgHhQIDAQABAoIBAQDXfef2bmu+bSNQ
LyYN+mCsXQkUUnoWwXuPCNGKLiwlYRIV1jL2ezGfdyp1KUI+7a7g3Immi2HgVXOP
cTrDyYvWuM2Y0zcyFeTn42JSr5TuHF3W0LbUD2N/tDxXXm5MVYnePTMfQXEusW0d
Hw5YaDOGDFYzwvuFBWD4YsjwhE8b12np/BZxniTzIl/blW+moocxAampj2SOc9dV
Z06Nw1gQYScclKqdASxnIsOOALhu7h0qOLAhhVgYWH6c+AC1q/72QQy9QYOW87e/
U5mkmxfjFtifYgnBGCRN5Uv5S6lnJD10z8+yR4SomVlxDTw0UkJMOT96KEhI5ICf
s1kKU2AxAoGBAPeWvNX63C+XbgDscttSNBrx6TOEwfeZiaGSxE+P+vKa3/YuVASf
rkL0xLnUTj+OhoaLzTetQ99RlUQsYkP8IQbIhiqXMHjpDTJStlHEbdJeT1fRUVF5
55S61bpYL8xLGYNvCFEmV66YuyZBAWq/DgkBG6gX2f71lHo2UJL/B/WjAoGBAOVp
Nw5/42wuwtSoynl5f0Tlbb5nruLbNMuaSAZ7ZjDVL6DXmwTyBQgg478LWB29xP2I
Or0TTPped3DeLTJrAG9Gxz6SEHfyh0lN7wc2RfS15NNfHKJwQJjuEaTR498yHWKq
UQkryU5xe3Qfr51RkFvmWzw91aUU0YwvqWDYodC3AoGBAPEBCBv6ry6cZvX7M+qN
4C6CYJBHoFAWYsSmivUvoAVcALowapR9ozGF9aE2Klzvrb92gnK59CGD1pqf4Z9v
4+4ob4Ex3nsz0Ca2IMcDQCvQpcdD97YpxeUe4UEc6pogWFt6T0w+2IcaIMKh8HEq
PM1DCNrdLNRj1P4JtPEB04ulAoGAXXIBGifftCZL+CGU7+wceizWCfPj2cYeeDys
z+8dzhBYaTTJkTcf85KqEhyF1P+CqR7/hhrBhU5Laq8lS98n+yuiZwtKKAGjN6nG
DnL+BdK9lZeta0E8Hs8CYteX8UdRjun/PjQWuJwjBEcP2o3ptnVbfmtVhfu361lS
rf8v0nsCgYAoshpslw7/qxUw7ac4xy0puMwuBBFAiQLFm5siOjZohOWYgQ3gZpl0
TJD9jBnEiH/Jpc883YzSh2bnEGZZ9wBffnhv1rjfNh6PbrcSdSKOznPEMpvw/pOB
wBnu6RWZ9mtWWIdDmYEJDqzrV7qp2w2x2foLc4oyCUKbUbQ/DvTYFQ==
-----END RSA PRIVATE KEY-----

在此先感谢您的帮助。

PEM文件中的header -----BEGIN RSA PRIVATE KEY-----是为PKCS#1 keys保留的,但是WebCryptoApi不支持pkcs1,所以你需要使用类似的工具将key从PKCS#1转换为PKCS#8 openssl.

# openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs1.key -out pkcs8.key