关于 javascript:使用 WebCrypto API 生成 RSA 密钥对并使用密码保护它

Generate RSA key pair using WebCrypto API and protect it with passphrase

标题说明了一切。我想知道如何使用 WebCrypto API 生成 RSA 密钥对,以及如何使用密码保护它,以便将其存储在数据库中。


您可以使用 WebCrypto 生成 RSA 密钥对并将其导出为 jwk (Json Web Key)、pkcs#8 (private) 或 spki (public)。请参阅 SubtleCrypto.exportKey() 和下面的示例代码

要以受保护的方式将密钥导出到外部系统,您可以使用如下标准:

  • PKCS#8:在 IETF Public Key-Cryptographic Standard Encryption #8 中定义的 PKCS#8 私钥格式。允许使用密码进行加密,但 WebCryptography exportKey 不支持。它提供 PrivateKeyInfo

  • PKCS#12:PKCS#12 是一种密钥库交换格式。它可以包含私钥、带有公钥的证书和证书链。内容使用密码进行 3DES 加密。文件的扩展名通常为 .pfx 或 .p12

很遗憾,WebCrypto 不支持以具有加密的通用格式导出,例如 PKCS#8 - 加密或 PKCS#12。您可以使用第三方库(如 forge

)以其中一种格式导出密钥
示例代码

WebCrypto RSASSA-PKCS1-v1_5 - generateKey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
window.crypto.subtle.generateKey(
    {
        name:"RSASSA-PKCS1-v1_5",
        modulusLength: 2048, //can be 1024, 2048, or 4096
        publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
        hash: {name:"SHA-256"}, //can be"SHA-1","SHA-256","SHA-384", or"SHA-512"
    },
    true, //whether the key is extractable (i.e. can be used in exportKey)
    ["sign","verify"] //can be any combination of"sign" and"verify"
)
.then(function(key){
    //returns a keypair object
    console.log(key);
    console.log(key.publicKey);
    console.log(key.privateKey);
})
.catch(function(err){
    console.error(err);
});

WebCrypto RSASSA-PKCS1-v1_5 - 导出密钥

1
2
3
4
5
6
7
8
9
10
11
window.crypto.subtle.exportKey(
   "pkcs8", //can be"jwk" (public or private),"spki" (public only), or"pkcs8" (private only)
    privateKey //can be a publicKey or privateKey, as long as extractable was true
)
.then(function(keydata){
    //returns the exported key data
    console.log(keydata);
})
.catch(function(err){
    console.error(err);
});

锻造-PKCS#8

1
2
3
4
5
6
7
//needed: wrap webcrypto pkcs#8 to forge privateKey (see doc)

// encrypts a PrivateKeyInfo and outputs an EncryptedPrivateKeyInfo
var encryptedPrivateKeyInfo = pki.encryptPrivateKeyInfo(
  privateKeyInfo, 'password', {
    algorithm: 'aes256', // 'aes128', 'aes192', 'aes256', '3des'
  });

// 将 EncryptedPrivateKeyInfo 转换为 PEM
var pem = pki.encryptedPrivateKeyToPem(encryptedPrivateKeyInfo);

锻造 - PKCS#12

1
2
3
4
5
6
7
8
9
//needed: wrap webcrypto pkcs#8 to forge privateKey (see doc)

// generate a p12 that can be imported by Chrome/Firefox
// (requires the use of Triple DES instead of AES)
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(privateKey, certChain, password,  {algorithm: '3des'});

// base64-encode p12
var p12Der = forge.asn1.toDer(p12Asn1).getBytes();
var p12b64 = forge.util.encode64(p12Der);


下载这个名为 OpenCrypto 的小型加密库,它允许您使用密码将私钥加密为 PKCS #8 RFC 5208 EncryptedPrivateKeyInfo 格式。库仅使用纯 JavaScript、WebCrypto API 以及 Promises。

这里是图书馆的链接:https://github.com/PeterBielak/OpenCrypto
该库在 MIT 许可下可免费用于商业用途。享受! ;)

这是一个简单的例子:

1
2
3
4
5
6
7
8
9
var crypt = new OpenCrypto();

crypt.getKeyPair().then(function(keyPair) {
     crypt.encryptPrivateKey(keyPair.privateKey,'securepassword').then(function(encryptedPrivateKey) {
        // This PEM Encrypted Private Key is fully compatiable with OpenSSL
        console.log(encryptedPrivateKey);
    });

});