问题描述
我想将密码与从特定比特币 wallet.dat 文件中使用 bitcoin2john.py 生成的哈希匹配。
首先,我创建了一个带密码“bit”的 wallet.dat。
bitcoin2john.py 为此 wallet.dat 文件生成以下输出: 比特币$64$12c098515dc4f4140786e352f05d3065f17a2ca8f15c5f1c93923dc7146380c6$16$146b99a74fa7b536$1350172$
可以使用 hashcat 破解该哈希。 Haschcat 为其返回正确的密码:
$bitcoin$64$12c098515dc4f4140786e352f05d3065f17a2ca8f15c5f1c93923dc7146380c6$16$146b99a74fa7b536$1350172$0$1350172
现在我想在 PHP 中做到这一点(并且已经失败了好几天): 我浏览了比特币核心代码以了解它是如何完成的。 在 wallet.ccp (https://github.com/bitcoin/bitcoin/blob/2556a973ed5839c81ad23cc4d3f187f3a777483c/src/wallet/wallet.cpp) 的第 387 行中,函数 ChangeWalletPassphrase 显示了步骤。
在 crypter.ccp (https://github.com/bitcoin/bitcoin/blob/c7ad94428ab6f54661d7a5441e1fdd0ebf034903/src/wallet/crypter.cpp) 的第 13 和 39 行中,使用了 BytesToKeySHA512AES 和 SetKeyFromPassphrase 函数。 这是我的 PHP 示例代码在“最终密码短语加密”之前所做的。 据我通过互联网研究发现,由此生成的密钥和 iv 然后用于使用 AES-256-CBC 加密密码。
你也可以在比特币核心代码中找到它。但看起来好像不是密码短语,而是 MasterKey (_vMasterKey) 被加密。
但是我没有 MasterKey,所以 Hashcat(来自我的测试场景)没有它。
但是,如果我对密码进行加密,则无法生成正确的哈希值。<?PHP
$testPassphrase = 'bit';
/*
* Hash from wallet.dat with passphrase: "bit"
* (Could be cracked by hashcat)
*/
$passHash = '$bitcoin$64$12c098515dc4f4140786e352f05d3065f17a2ca8f15c5f1c93923dc7146380c6$16$146b99a74fa7b536$135174$2$00$2$00';
/*
* Remove hash identifier (not needed)
*/
$passHash = str_replace('$bitcoin$','',$passHash);
/*
* Split hash into pieces
* ([0] = ??,[1] = passphrase hash,[2] = salt len,[3] = salt,[4] = iteration count,[5] = salt position,[6] = ??,[7] == ??,[8] == ??)
*/
$passHashArray = explode('$',$passHash);
/*
* Combine passphrase and salt
*/
$passtoHash = $testPassphrase.$passHashArray[3];
/*
* Hash $passtoHash $passHasArray[4] times with SHA512
*/
for($i = 0; $i < $passHashArray[4]; $i++){
$passtoHash = hash('SHA512',$passtoHash,true);
}
/*
* Get Key and Iv from $passtoHash for final encryption
*/
$key = substr($passtoHash,32);
$iv = substr($passtoHash,32,16);
/*
* final passphrase encryption
*/
if(in_array('aes-256-cbc',openssl_get_cipher_methods())){
$testPassphrase = openssl_encrypt($testPassphrase,'aes-256-cbc',$key,OPENSSL_RAW_DATA,$iv);
}
/*
* show result (should be: $passHashArray[1] = "12c098515dc4f4140786e352f05d3065f17a2ca8f15c5f1c93923dc7146380c6")
*/
echo bin2hex($testPassphrase);
?>
解决方法
我们开始!
<?php
$testPassphrase = 'bit';
/*
* Hash from wallet.dat with passphrase: "bit"
* (Could be cracked by hashcat)
*/
$passHash = '$bitcoin$64$12c098515dc4f4140786e352f05d3065f17a2ca8f15c5f1c93923dc7146380c6$16$146b99a74fa7b536$135174$2$00$2$00';
/*
* Remove hash identifier (not needed)
*/
$passHash = str_replace('$bitcoin$','',$passHash);
/*
* Split hash into pieces
* ([0] = ??,[1] = master key,[2] = salt len,[3] = salt,[4] = iteration count,[5] = salt position,[6] = ??,[7] == ??,[8] == ??)
*/
$passHashArray = explode('$',$passHash);
/*
* Combine passphrase and salt
*/
$passToHash = $testPassphrase.hex2bin($passHashArray[3]);
/*
* Hash $passToHash $passHasArray[4] times with SHA512
*/
for($i = 0; $i < $passHashArray[4]; $i++){
$passToHash = hash('SHA512',$passToHash,true);
}
/*
* Get Key and Iv from $passToHash for final encryption
*/
$key = substr($passToHash,32);
$iv = substr($passToHash,32,16);
/*
* final passphrase encryption
*/
if(in_array('aes-256-cbc',openssl_get_cipher_methods())){
if(openssl_decrypt(hex2bin($passHashArray[1]),'aes-256-cbc',$key,OPENSSL_RAW_DATA,$iv)){
echo 'password correct';
}else{
echo 'decrypt failed';
}
}
?>