進階
Wallet Encryption
深入了解 Bitcoin Core 錢包加密機制,如何保護私鑰安全。
10 分鐘
為什麼需要錢包加密?
Bitcoin Core 錢包存儲私鑰,這些私鑰控制你的比特幣。如果攻擊者獲得了 wallet.dat 文件的副本, 他們可以竊取所有資金。錢包加密使用密碼保護私鑰,即使文件被盜也無法直接使用。
加密保護的內容
✓ 加密保護
- • 私鑰(Private Keys)
- • HD 種子(Master Seed)
- • 導入的密鑰
⚠ 未加密
- • 公鑰和地址
- • 交易歷史
- • 標籤和元數據
加密方案
AES-256-CBC
Bitcoin Core 使用 AES-256-CBC 加密私鑰。加密密鑰通過 PBKDF2 從用戶密碼派生:
加密流程:
用戶密碼
↓
PBKDF2-HMAC-SHA512 (25000 迭代)
↓
主密鑰 (Master Key, 32 bytes)
↓
AES-256-CBC 加密
↓
加密的私鑰
存儲結構:
┌─────────────────────────────────┐
│ Salt (8 bytes) │
├─────────────────────────────────┤
│ Encrypted Master Key │
├─────────────────────────────────┤
│ IV (16 bytes per key) │
├─────────────────────────────────┤
│ Encrypted Private Key │
└─────────────────────────────────┘ 密鑰派生
import { pbkdf2Sync, createCipheriv, createDecipheriv, randomBytes } from 'crypto';
interface EncryptedWallet {
salt: Buffer;
encryptedMasterKey: Buffer;
masterKeyIV: Buffer;
encryptedKeys: Map;
}
interface EncryptedKey {
iv: Buffer;
ciphertext: Buffer;
}
// 從密碼派生加密密鑰
function deriveKey(password: string, salt: Buffer): Buffer {
return pbkdf2Sync(
password,
salt,
25000, // 迭代次數
32, // 密鑰長度 (256 bits)
'sha512'
);
}
// 加密私鑰
function encryptPrivateKey(
privateKey: Buffer,
masterKey: Buffer
): EncryptedKey {
const iv = randomBytes(16);
const cipher = createCipheriv('aes-256-cbc', masterKey, iv);
const ciphertext = Buffer.concat([
cipher.update(privateKey),
cipher.final()
]);
return { iv, ciphertext };
}
// 解密私鑰
function decryptPrivateKey(
encrypted: EncryptedKey,
masterKey: Buffer
): Buffer {
const decipher = createDecipheriv(
'aes-256-cbc',
masterKey,
encrypted.iv
);
return Buffer.concat([
decipher.update(encrypted.ciphertext),
decipher.final()
]);
}
// 完整的錢包加密流程
function encryptWallet(
privateKeys: Map,
password: string
): EncryptedWallet {
// 1. 生成隨機 salt
const salt = randomBytes(8);
// 2. 派生密鑰加密密鑰 (KEK)
const kek = deriveKey(password, salt);
// 3. 生成隨機主密鑰
const masterKey = randomBytes(32);
// 4. 用 KEK 加密主密鑰
const masterKeyIV = randomBytes(16);
const cipher = createCipheriv('aes-256-cbc', kek, masterKeyIV);
const encryptedMasterKey = Buffer.concat([
cipher.update(masterKey),
cipher.final()
]);
// 5. 用主密鑰加密所有私鑰
const encryptedKeys = new Map();
for (const [address, privateKey] of privateKeys) {
encryptedKeys.set(address, encryptPrivateKey(privateKey, masterKey));
}
return {
salt,
encryptedMasterKey,
masterKeyIV,
encryptedKeys
};
} 使用方式
加密錢包
# 加密現有錢包(只能執行一次)
bitcoin-cli encryptwallet "your-strong-passphrase"
# 注意:這會關閉 Bitcoin Core
# 重新啟動後錢包將被加密
# 加密後,錢包會自動鎖定
# 需要解鎖才能進行需要私鑰的操作 警告: 加密錢包後無法取消加密。如果忘記密碼,將永久失去對資金的訪問權。 在加密前,請確保備份 wallet.dat 和記住密碼。
解鎖錢包
# 解鎖錢包 60 秒
bitcoin-cli walletpassphrase "your-passphrase" 60
# 解鎖錢包用於 staking(不允許發送)
bitcoin-cli walletpassphrase "your-passphrase" 60 true
# 手動鎖定錢包
bitcoin-cli walletlock
# 查看錢包狀態
bitcoin-cli getwalletinfo | jq '.unlocked_until'
# 0 = 已鎖定
# > 0 = 解鎖到的 Unix 時間戳 更改密碼
# 更改錢包密碼
bitcoin-cli walletpassphrasechange "old-passphrase" "new-passphrase"
# 這會重新加密主密鑰
# 不需要重新加密所有私鑰 安全性考量
密碼強度
暴力破解估算
| 密碼類型 | 熵 | 破解時間* |
|---|---|---|
| 6 個小寫字母 | ~28 bits | 秒 |
| 8 個混合字符 | ~47 bits | 天 |
| 12 個混合字符 | ~71 bits | 數十年 |
| 4 個隨機單詞 | ~44 bits | 月 |
| 6 個隨機單詞 | ~66 bits | 數千年 |
* 假設攻擊者使用高端 GPU,考慮 PBKDF2 的 25000 次迭代
攻擊向量
潛在威脅
- 1. 內存攻擊: 解鎖時,私鑰會暫時存在於內存中。惡意軟體可能讀取內存。
- 2. 鍵盤記錄: 惡意軟體可能記錄密碼輸入。
- 3. 文件備份: 加密前的備份可能未加密。
- 4. 弱密碼: 簡單密碼可被暴力破解。
內存安全
安全內存處理
Bitcoin Core 採取措施保護內存中的敏感數據:
- • mlock(): 防止敏感數據被交換到磁碟(swap)
- • 清零內存: 使用完私鑰後,將內存清零
- • 自動鎖定: 超時後自動鎖定錢包
// Bitcoin Core 的安全內存分配 (簡化)
class secure_allocator {
public:
void* allocate(size_t n) {
void* ptr = std::malloc(n);
if (ptr) {
// 防止交換到磁碟
mlock(ptr, n);
}
return ptr;
}
void deallocate(void* ptr, size_t n) {
if (ptr) {
// 使用前清零
memory_cleanse(ptr, n);
munlock(ptr, n);
std::free(ptr);
}
}
};
// 安全清零(防止編譯器優化掉)
void memory_cleanse(void* ptr, size_t len) {
volatile unsigned char* p = (volatile unsigned char*)ptr;
while (len--) {
*p++ = 0;
}
} Descriptor 錢包
新錢包格式
Bitcoin Core 23.0+ 預設使用 Descriptor 錢包,它使用 SQLite 存儲並有不同的加密方式:
# 創建加密的 descriptor 錢包
bitcoin-cli createwallet "mywallet" false false "passphrase"
# 參數說明:
# - 錢包名稱
# - disable_private_keys (false = 包含私鑰)
# - blank (false = 創建預設密鑰)
# - passphrase (加密密碼)
# 查看錢包類型
bitcoin-cli getwalletinfo | jq '.format'
# "sqlite" = descriptor 錢包
# "bdb" = 傳統錢包 最佳實踐
✓ 推薦做法
- • 使用強密碼(12+ 字符或 6+ 隨機單詞)
- • 設定短的解鎖超時時間
- • 定期備份加密的錢包
- • 使用密碼管理器存儲密碼
- • 保持系統更新和安全
✗ 避免
- • 使用弱密碼或常見密碼
- • 長時間保持錢包解鎖
- • 在不安全的系統上解鎖
- • 忘記密碼(無法恢復!)
- • 將密碼與錢包備份放在一起
備份策略
# 備份加密的錢包
bitcoin-cli backupwallet "/path/to/backup/wallet.dat"
# 對於 descriptor 錢包
bitcoin-cli -rpcwallet=mywallet backupwallet "/path/to/backup/mywallet.sqlite"
# 導出私鑰(需要解鎖)
bitcoin-cli walletpassphrase "passphrase" 60
bitcoin-cli dumpprivkey "bc1q..."
# 導出所有描述符(descriptor 錢包)
bitcoin-cli listdescriptors true # true = 包含私鑰 備份建議: 備份應該包含加密的錢包文件和(分開存儲的)密碼。 考慮使用多個備份位置,包括離線存儲。
總結
- ✓ AES-256-CBC:使用強加密保護私鑰
- ✓ PBKDF2:25,000 次迭代減慢暴力破解
- ✓ 密碼強度:使用強密碼是安全的關鍵
- ⚠ 不可逆:忘記密碼意味著永久失去資金
已複製連結