Web3 浏览器钱包:助记词、私钥存储与用户密码
最近开始接触 Web3,在做浏览器钱包插件开发时会频繁遇到助记词、私钥、Keystore、钱包密码这几个概念:助记词是怎么来的?私钥存在哪里、怎么加密?用户设的那个「密码」到底管什么用?本文结合主流标准(BIP-39、BIP-32、Web3 Secret Storage)做个简要梳理,并配一些插件里常用的代码示例,方便在开发浏览器钱包扩展时理解与实现。
开发中常用依赖示例(下文代码基于此类库):
// 助记词与 HD 派生:bip39 + ethers 或 @ethersproject/hdnode
import { ethers } from "ethers";
// 或
import * as bip39 from "bip39";
import { HDNodeWallet } from "ethers";
一、助记词是怎么生成的
助记词(Mnemonic),在不少钱包里也叫「Secret Recovery Phrase / 恢复短语」,是一串由 12 或 24 个英文单词组成的句子,用来备份和恢复整个钱包:有了助记词,可以在任意兼容的钱包里重新导出所有派生出的私钥和地址。其生成和还原遵循 BIP-39 标准。
1. 生成流程(助记词从哪来)
第一步:生成熵(Entropy)
先产生一段完全随机的二进制数据「熵」,长度必须是 32 的倍数,常见为 128 位或 256 位:- 128 位熵 → 对应 12 个助记词
- 256 位熵 → 对应 24 个助记词
熵必须来自密码学安全的随机源(CSPRNG),不能是可预测的。
第二步:加校验和
对熵做 SHA-256,取哈希的前若干位(位数 = 熵长度 / 32)作为校验和,拼在熵的后面。这样在用户日后输入助记词时,可以校验是否输错或漏词。第三步:按 11 位切块 → 映射到词库
把「熵 + 校验和」按每 11 位切成多段,每段对应 0~2047 的一个数,再映射到 BIP-39 规定的 2048 个英文单词 词库里的某一个词(11 位二进制刚好 2^11=2048 种取值)。第四步:得到助记词
把这些词用空格连起来,就是最终的助记词。12 词约对应 128 位熵,组合空间约 2^128 量级(约 3.4×10^38),暴力破解不现实;24 词则更大。
助记词本质上是「随机熵 + 校验」的人眼可读编码,不是密码学意义上的「密钥」,但谁拿到助记词谁就能在兼容钱包里恢复出同一套私钥,所以必须当作最高等级机密保管。
插件里生成与校验助记词(示例):
import * as bip39 from "bip39";
// 生成 12 词助记词(128 位熵)
const mnemonic12 = bip39.generateMnemonic(128);
// 生成 24 词助记词(256 位熵)
const mnemonic24 = bip39.generateMnemonic(256);
// 校验用户输入的助记词是否合法(含校验和)
const isValid = bip39.validateMnemonic(userInputMnemonic);
二、从助记词到私钥:种子与派生
助记词本身不直接当私钥用,而是先转成「种子」,再按 BIP-32(HD 钱包) 从种子派生出无数个私钥和地址。
助记词 → 种子(Seed)
用 PBKDF2(HMAC-SHA512,迭代 2048 次):以可选的用户 passphrase 为密钥,以字符串"mnemonic"+ 助记词为盐,生成 512 位(64 字节)的种子。这个过程是单向的:有助记词可以算种子,有种子推不回助记词。若创建钱包时额外设了「扩展 passphrase」(俗称第 13/25 个词),它也会参与生成种子,忘记则无法恢复。种子 → 主私钥与派生路径
种子通过 BIP-32 规定的层级推导,得到主私钥(master key),再按路径(如m/44'/60'/0'/0/0用于以太坊第一个账户)派生出每个账户的私钥和公钥。所以一个助记词对应一棵密钥树,所有「账户 1、账户 2、…」都是这棵树上不同路径的叶子,备份助记词就等于备份了整棵树。
助记词 → 种子 → 以太坊账户(ethers 示例):
import { ethers } from "ethers";
const mnemonic = "abandon abandon abandon ..."; // 12 或 24 词
// 从助记词创建 HD 钱包,默认路径 m/44'/60'/0'/0/0
const hdNode = ethers.HDNodeWallet.fromPhrase(mnemonic);
console.log(hdNode.privateKey); // 0x...
console.log(hdNode.address); // 0x...
// 派生第 N 个账户:m/44'/60'/0'/0/N
const account1 = ethers.HDNodeWallet.fromPhrase(
mnemonic,
undefined,
`m/44'/60'/0'/0/1`,
);
三、私钥的存储机制
钱包里真正用来签名交易的是私钥。私钥在设备上的存在形式大致有几类:
1. 由助记词在内存中派生
创建/导入钱包时,用户输入助记词(和可选 passphrase),钱包在内存中算出种子并派生私钥,用于签名。助记词和原始私钥最好不要在磁盘上明文存储,否则一旦被恶意扩展或恶意软件读到,资产就会丢。
2. Keystore(加密后的私钥文件)
很多钱包(尤其是桌面端、早期以太坊钱包)会以 Keystore 形式存私钥:把私钥用用户密码派生的密钥加密后,存成 JSON 文件(Web3 Secret Storage 定义)。典型流程是:
- 用 KDF(如 scrypt 或 PBKDF2)从用户密码推导出加密密钥;
- 用 AES-128-CTR 等对称加密算法加密私钥;
- 用 MAC(如对密文做 Keccak-256)保证完整性,防止篡改。
使用时必须输入正确的用户密码才能解密出私钥。Keystore 和用户密码 两者缺一不可,丢了密码又没有助记词或私钥备份,就没办法恢复。
3. 浏览器扩展钱包的存储
浏览器插件钱包会把加密后的数据(助记词或派生出的密钥材料)存在扩展的本地存储里(例如 Chrome 的 Local Extension Storage),有的实现里把这段加密存储称为 vault(即「保险库」,比喻只能靠密码打开的密文数据):内容用**用户设置的「钱包密码」**加密后写入,只有在本机输入密码后才能解密到内存里用。也就是说:
- 助记词 / 种子 在磁盘或扩展存储里是密文,解密密钥来自用户密码;
- 用户密码不参与 BIP-39 的「助记词 → 种子」推导(那一层用的是可选的 passphrase),只负责本地加密存储,防止别人打开你浏览器就能直接用钱包。
插件内:用用户密码加密后写入 storage(思路示例):
import { ethers } from "ethers";
// 加密:助记词 + 用户密码 → 密文(仅示例,生产环境建议用 scrypt + AES 等标准 KDF/加密)
async function encryptMnemonic(mnemonic, userPassword) {
const wallet = ethers.Wallet.fromPhrase(mnemonic);
const json = await wallet.encrypt(userPassword);
return json; // 可存入 chrome.storage.local
}
// 解密:用户输入密码后从 storage 取出密文,解密得到 Wallet,再 fromPhrase 或直接用私钥
async function decryptToWallet(encryptedJson, userPassword) {
return ethers.Wallet.fromEncryptedJson(encryptedJson, userPassword);
}
注意:上述 encrypt 是单私钥的 Keystore;若存的是助记词,需要自己用 crypto.subtle 或库(如 scrypt-js + AES-GCM)做「密码 → 密钥 → 加密助记词」,再存到 chrome.storage.local,解锁时再解密出助记词、用 ethers 派生账户。
四、用户密码的作用
「用户密码」(钱包密码、登录密码)在浏览器钱包里不是助记词,不是私钥,也不参与助记词到种子的数学推导(除非你额外用了 BIP-39 的 passphrase)。它主要做这几件事:
解锁本地加密存储
输入密码后,钱包用该密码解密存在本地的 vault/Keystore,把助记词或私钥加载到内存,才能签名、转账。不输入密码,恶意软件或他人拿到你的电脑,也拿不到明文助记词。授权敏感操作
很多钱包在「发送交易」「导出私钥」「显示助记词」等操作前会再次要求输入密码或做二次确认,避免在已解锁状态下被恶意页面或扩展滥用。不参与「恢复」
换设备或重装浏览器后,恢复钱包只需要助记词(以及可选的 BIP-39 passphrase),不需要旧设备的「钱包密码」。新设备上可以设一个全新的密码,只要助记词正确,就能导出同一批地址和资产。
简单说:用户密码是「本机保护层」,保护的是存在本地的密文;助记词是「跨设备恢复层」,谁掌握助记词谁就掌握资产。两者分工明确——密码丢了可以靠助记词在新环境恢复;助记词要是丢了或泄露,密码再复杂也没用。
五、小结
- 助记词:按 BIP-39 从随机熵生成,带校验和,映射到 2048 词表,12/24 词对应 128/256 位熵;用于备份与恢复,谁持有助记词谁就能在兼容钱包里恢复整棵密钥树。
- 私钥存储:可由助记词在内存中派生;或通过 Keystore(用户密码 + KDF + 对称加密)存成文件;浏览器钱包多用「用户密码加密的 vault(保险库)」存助记词或派生材料,避免明文落盘。
- 用户密码:只负责解锁本地加密存储和授权敏感操作,不参与助记词→种子的推导;换设备恢复只需助记词,不需旧密码。助记词与密码各司其职,助记词是资产恢复的根,密码是本地防护。