彻底搞懂钱包加密:从主密钥到私钥的每一步

·

关键词:钱包加密、主密钥、PBKDF2、AES-256-CBC、私钥解密、比特币核心、wallet.dat、密钥派生

如果你曾因 比特币核心钱包 里那串乱码式的加密字段而犯愁,本文用半小时带你走完整条链路:从 主密钥(master key) 的生成,到 CKey 私钥 的解锁,全部用一段 80 行内、中文注释的 Python 脚本示范。读完你将理解 wallet.dat 里的 MKey/CKey 真正在干什么,也能自己动手做离线备份或恢复。


1. 为什么要加密钱包?

比特币资产本质上是“一串私钥”,任何人拿到私钥即可转账。为了降低被盗风险, 比特币核心钱包 在本地把私钥加密后再落盘,解密钥匙则由你设定的“口令”派生。
核心系统流程概览:

  1. 随机生成 32 字节 主密钥
  2. 用口令 → 盐 → PBKDF2-HMAC-SHA512钱包密钥(wallet key)IV
  3. 用 AES-256-CBC 加密主密钥 → 写入 wallet.dat 的 MKey 字段。
  4. 钱包运行时再次用同一套逻辑逆向解密,即可临时还原主密钥,解锁 CKey 集合,完成签名。

2. 组件词典


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 里的 MKeysaltiters 一并写入文件,以便后续找回。

👉 **【想一分钟测试?】直接复制到终端,替换自己的主密钥即可上手体验。](https://www.okx.com/join/8265080)


4. 解锁 CKey:从主密钥到单个私钥

有主密钥只是“拿到对私钥进行 AES 解密的另一把钥匙”,我们还需给 CKey 正确初始化向量再进行 AES。流程如下:

  1. 读 wallet.dat 里对应地址的 公共钥匙(public key)
  2. 对 public key 做 两次 SHA256 → 取前 16 字节 = IV (pk_iv)
  3. 用主密钥 + 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. 易被忽视的安全细节


6. 常见问题 FAQ

Q1:只用口令就能在另一台电脑恢复资产吗?
A:可以,但需要你同时记住 salt、iteration count、密文 mkey,以及 account 数量 等与 Ckey 相关的 schema 信息。换言之:牢记口令 + 备份 wallet.dat 才是唯一正解

Q2:我想自己写脚本验证“没装比特币核心”也能恢复密钥,行不行?
A:完全可以。把 wallet.dat 里 mkey 表块的 salt、iters、mkey_ctown 解析出来(可用 pywalletbitcoin-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 流程,不要等到真失钱包时才手忙脚乱。

至此,钱包加密的完整链路你已尽收眼底。祝各位资产安全、永远无需“爆肝”恢复。