如何使用种子确定性地生成安全的 RSA 密钥?

How to generate safe RSA keys deterministically using a seed?

我们如何使用助记词列表作为种子(就像我们已经习惯使用加密货币钱包一样)能够恢复私钥以防万一丢失、意外删除或卡在损坏的设备上?

这对客户端之间的端到端加密很有用:密钥应该在客户端生成,只有 public 密钥会与服务器共享。

用户可以在需要时离线重新生成密钥,只要他们能够再次提供助记词,显然是安全和离线存储的。

助记种子应该足够长以提供安全的熵。

Some Q&A appear to be very outdated:我们如何在 Javascript/Typescript 中实现这一点,可能使用维护的库?

解决方案:bip39node-forge

引用指导我实现此解决方案的 this answer

in this scenario, the resulting public key is, by nature, public, and thus can serve for offline dictionary attacks. The attacker just has to try possible passwords until he finds the same public key. That's intrinsic to what you want to achieve.

我们可以假设 128 bits of entropy should be enough 在可预见的未来可以防止这种攻击,但是我们可以幸运地决定我们的助记符有多强。

1。生成助记词

首先我们可以使用bip-39 JS实现生成助记词。

import { generateMnemonic } from "bip39";

const mnemonic = generateMnemonic(256) // 256 to be on the _really safe_ side. Default is 128 bit.

console.log(mnemonic) // prints 24 words

2。创建确定性 PRNG 函数

现在我们可以使用node-forge来生成我们的密钥了。 pki.rsa.generateKeypair 函数接受 pseudo-random number generator 函数。目标是让这个函数不计算 pseudo-random 数字(这不再是 确定性 ),而是 return 计算的值 来自助记符.

import { mnemonicToSeed } from "bip39";
import { pki, random } from "node-forge";

const seed = (await mnemonicToSeed(mnemonic)).toString('hex')
const bits = 4096

const prng = random.createInstance();
prng.seedFileSync = () => seed

3。生成密钥对

我们现在可以使用 feed the generateKeyPair 函数和我们“操纵”的 prng:

const { privateKey, publicKey } = pki.rsa.generateKeyPair({ bits, prng, workers: 2 })

瞧瞧!

我们现在拥有安全且确定的 RSA 密钥,直接在客户端生成,并可使用与输入相同的助记符恢复。 请考虑使用确定性密钥所涉及的风险,并确保您的用户不会将助记词存储在网上或客户端的任何其他地方(通常,建议将其写在纸上并存储在某个地方安全)。