在 php 中检查 Bitcoin wallet.dat 密码哈希

问题描述

我想将密码与从特定比特币 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 中做到这一点(并且已经失败了好几天):

<?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);

?>

我浏览了比特币核心代码以了解它是如何完成的。

在 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] = 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';
     }
   }

?>