关键词:钱包加密、主密钥、PBKDF2、AES-256-CBC、私钥解密、比特币核心、wallet.dat、密钥派生
如果你曾因 比特币核心钱包 里那串乱码式的加密字段而犯愁,本文用半小时带你走完整条链路:从 主密钥(master key) 的生成,到 CKey 私钥 的解锁,全部用一段 80 行内、中文注释的 Python 脚本示范。读完你将理解 wallet.dat 里的 MKey/CKey 真正在干什么,也能自己动手做离线备份或恢复。
1. 为什么要加密钱包?
比特币资产本质上是“一串私钥”,任何人拿到私钥即可转账。为了降低被盗风险, 比特币核心钱包 在本地把私钥加密后再落盘,解密钥匙则由你设定的“口令”派生。
核心系统流程概览:
- 随机生成 32 字节 主密钥。
- 用口令 → 盐 → PBKDF2-HMAC-SHA512 → 钱包密钥(wallet key) 与 IV 。
- 用 AES-256-CBC 加密主密钥 → 写入 wallet.dat 的 MKey 字段。
- 钱包运行时再次用同一套逻辑逆向解密,即可临时还原主密钥,解锁 CKey 集合,完成签名。
2. 组件词典
- 主密钥 (mkey)
32 字节,真正用来加密/解密的对称密钥,本文简称为“主密钥”便于记忆。 - 口令 (password)
人脑记忆的东西,长度+随机度直接决定暴力破解难度;长度≥12 建议,勿用维基词库中的单词。 - 盐 (salt)
8 字节随机,让相同口令也永不派生出相同 wallet key,防彩虹表。 - 迭代次数 (iteration count)
默认在 25000~500000 之间浮动,比特币核心自动选择。同样的 salt+count 写死 wallet.dat 里。 - CKey
wallet.dat 中一个 48 字节字段,存放被主密钥 AES 加密的 具体地址对应的私钥(raw key)。
3. 动手 Run:10 行脚本跑通主密钥加解密
下面代码引入 3 个库:标准库 hashlib, binascii, 第三方 pyaes(可 pip install pyaes)。代码全部带中文注释,复制即跑。
import hashlib, binascii, pyaes, os, random
# 1. 随机 32 字节主密钥(示例用常量,你与真实钱包使用时请替换)
mkey = binascii.unhexlify("5c5692da0f165d3d32e5c05a56dde9b2d0ebc05f100f8d0616941e9abe7e0fb0")
# 2. 设定口令、盐与迭代次数
password = b'password123'
salt = os.urandom(8) # 可写死
iters = random.randint(25000, 100000) # 可写死
# 3. PBKDF2 生成 wallet_key 与 iv
hash512 = hashlib.pbkdf2_hmac('sha512', password, salt, iters)
wallet_key = hash512[0:32]
iv = hash512[32:48]
# 4. AES-256-CBC 加密
aes = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(wallet_key, iv))
ciphertext = aes.feed(mkey) + aes.feed()
# 5. 解密(流程完全相同)
aes = pyaes.Decrypter(pyaes.AESModeOfOperationCBC(wallet_key, iv))
plaintext = aes.feed(ciphertext) + aes.feed()
assert plaintext == mkey # 断言成功表示一切正常跑完后,ciphertext 就是 wallet.dat 里的 MKey,salt 与 iters 一并写入文件,以便后续找回。
👉 **【想一分钟测试?】直接复制到终端,替换自己的主密钥即可上手体验。](https://www.okx.com/join/8265080)
4. 解锁 CKey:从主密钥到单个私钥
有主密钥只是“拿到对私钥进行 AES 解密的另一把钥匙”,我们还需给 CKey 正确初始化向量再进行 AES。流程如下:
- 读 wallet.dat 里对应地址的 公共钥匙(public key)。
- 对 public key 做 两次 SHA256 → 取前 16 字节 = IV (pk_iv)。
- 用主密钥 + pk_iv AES-256-CBC 解密 CKey → 得到 32 字节私钥。
示意代码:
import hashlib, pyaes, binascii
master_key = binascii.unhexlify("5c5692da0f165d3d32e5c05a56dde9b2d0ebc05f100f8d0616941e9abe7e0fb0")
ckey_enc = binascii.unhexlify("316787cf...")
pub = binascii.unhexlify("027a098dbada15a...")
pk_iv = hashlib.sha256(hashlib.sha256(pub).digest()).digest()[:16]
aes = pyaes.Decrypter(pyaes.AESModeOfOperationCBC(master_key, pk_iv))
raw_key = aes.feed(ckey_enc)[:32]
print("私钥:", raw_key.hex())成功后,你就能离线把 raw_key 导入任意轻钱包或硬件钱包,完成“冷备份恢复”。
5. 易被忽视的安全细节
- 口令复杂度决定安全门槛:大于 60 位完全随机字符,或 ≥15 英文+符号混合+数字,可显著拖慢 GPU 暴力破解。
- Salt & Iteration 透明可见:wallet.dat 中的 mkey 区块明文包含,只具备防止彩虹表的价值,不算秘密。要保护真正的价值,还是要口令够强。
- Ckey 才是最终私钥:一旦主密钥泄露,谁会第一时间怀疑 CKey?务必对 wallet.dat 整体 做全盘加密+云备份加密再上传。
6. 常见问题 FAQ
Q1:只用口令就能在另一台电脑恢复资产吗?
A:可以,但需要你同时记住 salt、iteration count、密文 mkey,以及 account 数量 等与 Ckey 相关的 schema 信息。换言之:牢记口令 + 备份 wallet.dat 才是唯一正解。
Q2:我想自己写脚本验证“没装比特币核心”也能恢复密钥,行不行?
A:完全可以。把 wallet.dat 里 mkey 表块的 salt、iters、mkey_ctown 解析出来(可用 pywallet 或 bitcoin-cli dumpwallet),再用本文算法即可。
Q3:PBKDF2 的迭代次数会越来越大吗?
A:目前~500 000 次已很富裕,再高就失去用户体验;重点是并行计算 GPU 的效率已被暴力破解硬件提升,与其无限加价,不如用 BIP39 助记词 + 长口令。
Q4:有没有图形工具直接帮我解密?
A:Objective-C 的 WalletKit 与 python 的 bitcoin-explorer 都提供 CLI/GUI,界面大同小异。核心仍是本文算法。👉 **如果你偏爱在线工具,可以先到这里体验一键导入。](https://www.okx.com/join/8265080)
Q5:脚本跑完只得到一串十六进制,如何变 WIF 私钥?
A:Python 里用 bitcoin 库:
from bitcoin import *
wif = encode_privkey(raw_key.hex(), 'wif_compressed')Q6:我能对同一密码换 salt 并重加密吗?
A:可以。但这将使所有现有 CKey 重新加密,等同 重新生成整个 wallet.dat。别忘了同时重新导出/同步地址列表,否则旧断点充值会查不到 UTXO。
7. 实战小结
| 让你秒用的 3 句话 |
|---|
| 1. 备份 wallet.dat 更重要。加密口令复杂到无需记忆,再把它在安全笔记里记牢。 |
| 2. 任何“离线恢复”场景都需 主密钥+CKey+IV 三件套,缺一不可。 |
| 3. 把本文脚本改写成自己日常工具,定期测试 restore 流程,不要等到真失钱包时才手忙脚乱。 |
至此,钱包加密的完整链路你已尽收眼底。祝各位资产安全、永远无需“爆肝”恢复。