Extend ethereum wallet, PBKDF2-HMAC-SHA256 to allow arbitrary cipher length
#1
Hi All,

I am trying to develop my own module that is very similar to module 15600.  It is a crypto wallet that has a keystore very similar to Ethereum Wallet. It uses PBKDF2-HMAC-SHA256, the correct password can be confirmed by comparing a mac to a generated mac which is the keccak hash of the last 16 bytes of the derived key and cipher text.  I have tested the logic and it does work. 

Module 15600 expects the cipher to be 64 characters long, but the wallet I am trying to crack can be much longer. The current cipher text I have is 156 characters long. 

I have been going at it for several days and struggling. I have also looked at module 16300 for guidance. I am hoping to get some direction on the changes that I need to make. Within the module c file I am replacing this part

  ethereum_pbkdf2->ciphertext[0] = hex_to_u32 (&ciphertext_pos[ 0]);
  ethereum_pbkdf2->ciphertext[1] = hex_to_u32 (&ciphertext_pos[ 8]);
  ethereum_pbkdf2->ciphertext[2] = hex_to_u32 (&ciphertext_pos[16]);
  ethereum_pbkdf2->ciphertext[3] = hex_to_u32 (&ciphertext_pos[24]);
  ethereum_pbkdf2->ciphertext[4] = hex_to_u32 (&ciphertext_pos[32]);
  ethereum_pbkdf2->ciphertext[5] = hex_to_u32 (&ciphertext_pos[40]);
  ethereum_pbkdf2->ciphertext[6] = hex_to_u32 (&ciphertext_pos[48]);
  ethereum_pbkdf2->ciphertext[7] = hex_to_u32 (&ciphertext_pos[56]);

with this part

  crypto_pbkdf2->ciphertext[0] = hex_to_u32 (&ciphertext_pos[ 0]);
  crypto_pbkdf2->ciphertext[1] = hex_to_u32 (&ciphertext_pos[ 8]);
  crypto_pbkdf2->ciphertext[2] = hex_to_u32 (&ciphertext_pos[16]);
  crypto_pbkdf2->ciphertext[3] = hex_to_u32 (&ciphertext_pos[24]);
  crypto_pbkdf2->ciphertext[4] = hex_to_u32 (&ciphertext_pos[32]);
  crypto_pbkdf2->ciphertext[5] = hex_to_u32 (&ciphertext_pos[40]);
  crypto_pbkdf2->ciphertext[6] = hex_to_u32 (&ciphertext_pos[48]);
  crypto_pbkdf2->ciphertext[7] = hex_to_u32 (&ciphertext_pos[56]);
  crypto_pbkdf2->ciphertext[8] = hex_to_u32 (&ciphertext_pos[64]);
  crypto_pbkdf2->ciphertext[9] = hex_to_u32 (&ciphertext_pos[72]);
  crypto_pbkdf2->ciphertext[10] = hex_to_u32 (&ciphertext_pos[80]);
  crypto_pbkdf2->ciphertext[11] = hex_to_u32 (&ciphertext_pos[88]);
  crypto_pbkdf2->ciphertext[12] = hex_to_u32 (&ciphertext_pos[96]);
  crypto_pbkdf2->ciphertext[13] = hex_to_u32 (&ciphertext_pos[104]);
  crypto_pbkdf2->ciphertext[14] = hex_to_u32 (&ciphertext_pos[112]);
  crypto_pbkdf2->ciphertext[15] = hex_to_u32 (&ciphertext_pos[120]);
  crypto_pbkdf2->ciphertext[16] = hex_to_u32 (&ciphertext_pos[128]);
  crypto_pbkdf2->ciphertext[17] = hex_to_u32 (&ciphertext_pos[136]);
  crypto_pbkdf2->ciphertext[18] = hex_to_u32 (&ciphertext_pos[144]);
  crypto_pbkdf2->ciphertext[19] = hex_to_u32 (&ciphertext_pos[152]);



With the encoder I have replaced 

const int line_len = snprintf (line_buf, line_size, "%s*%u*%s*%08x%08x%08x%08x%08x%08x%08x%08x*%08x%08x%08x%08x%08x%08x%08x%08x",
    SIGNATURE_ETHEREUM_PBKDF2,
    salt->salt_iter + 1,
    tmp_salt,
    byte_swap_32 (ethereum_pbkdf2->ciphertext[0]),
    byte_swap_32 (ethereum_pbkdf2->ciphertext[1]),
    byte_swap_32 (ethereum_pbkdf2->ciphertext[2]),
    byte_swap_32 (ethereum_pbkdf2->ciphertext[3]),
    byte_swap_32 (ethereum_pbkdf2->ciphertext[4]),
    byte_swap_32 (ethereum_pbkdf2->ciphertext[5]),
    byte_swap_32 (ethereum_pbkdf2->ciphertext[6]),
    byte_swap_32 (ethereum_pbkdf2->ciphertext[7]),
    byte_swap_32 (digest[0]),
    byte_swap_32 (digest[1]),
    byte_swap_32 (digest[2]),
    byte_swap_32 (digest[3]),
    byte_swap_32 (digest[4]),
    byte_swap_32 (digest[5]),
    byte_swap_32 (digest[6]),
    byte_swap_32 (digest[7])
  );


with this part

const int line_len = snprintf (line_buf, line_size, "%s*%u*%s*%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x*%08x%08x%08x%08x%08x%08x%08x%08x",
    SIGNATURE_CRYPTO_PBKDF2,
    salt->salt_iter + 1,
    tmp_salt,
    byte_swap_32 (crypto_pbkdf2->ciphertext[0]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[1]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[2]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[3]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[4]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[5]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[6]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[7]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[8]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[9]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[10]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[11]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[12]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[13]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[14]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[15]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[16]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[17]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[18]),
    byte_swap_32 (crypto_pbkdf2->ciphertext[19]),
    byte_swap_32 (digest[0]),
    byte_swap_32 (digest[1]),
    byte_swap_32 (digest[2]),
    byte_swap_32 (digest[3]),
    byte_swap_32 (digest[4]),
    byte_swap_32 (digest[5]),
    byte_swap_32 (digest[6]),
    byte_swap_32 (digest[7])
  );



In the kernel I have replaced this

/**
   * keccak
   */
  u32 ciphertext[8];
  ciphertext[0] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[0];
  ciphertext[1] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[1];
  ciphertext[2] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[2];
  ciphertext[3] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[3];
  ciphertext[4] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[4];
  ciphertext[5] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[5];
  ciphertext[6] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[6];
  ciphertext[7] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[7];
  u32 key[4];
  key[0] = hc_swap32_S (tmps[gid].out[4]);
  key[1] = hc_swap32_S (tmps[gid].out[5]);
  key[2] = hc_swap32_S (tmps[gid].out[6]);
  key[3] = hc_swap32_S (tmps[gid].out[7]);
  u64 st[25];
  st[ 0] = hl32_to_64_S (key[1], key[0]);
  st[ 1] = hl32_to_64_S (key[3], key[2]);
  st[ 2] = hl32_to_64_S (ciphertext[1], ciphertext[0]);
  st[ 3] = hl32_to_64_S (ciphertext[3], ciphertext[2]);
  st[ 4] = hl32_to_64_S (ciphertext[5], ciphertext[4]);
  st[ 5] = hl32_to_64_S (ciphertext[7], ciphertext[6]);
  st[ 6] = 0x01;
  st[ 7] = 0;
  st[ 8] = 0;
  st[ 9] = 0;
  st[10] = 0;
  st[11] = 0;
  st[12] = 0;
  st[13] = 0;
  st[14] = 0;
  st[15] = 0;
  st[16] = 0;
  st[17] = 0;
  st[18] = 0;
  st[19] = 0;
  st[20] = 0;
  st[21] = 0;
  st[22] = 0;
  st[23] = 0;
  st[24] = 0;



with 

u32 ciphertext[20];
  ciphertext[0] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[0];
  ciphertext[1] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[1];
  ciphertext[2] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[2];
  ciphertext[3] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[3];
  ciphertext[4] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[4];
  ciphertext[5] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[5];
  ciphertext[6] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[6];
  ciphertext[7] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[7];
  ciphertext[8] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[8];
  ciphertext[9] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[9];
  ciphertext[10] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[10];
  ciphertext[11] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[11];
  ciphertext[12] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[12];
  ciphertext[13] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[13];
  ciphertext[14] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[14];
  ciphertext[15] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[15];
  ciphertext[16] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[16];
  ciphertext[17] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[17];
  ciphertext[18] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[18];
  ciphertext[19] = esalt_bufs[DIGESTS_OFFSET_HOST].ciphertext[19];
  u32 key[4];
  key[0] = hc_swap32_S (tmps[gid].out[4]);
  key[1] = hc_swap32_S (tmps[gid].out[5]);
  key[2] = hc_swap32_S (tmps[gid].out[6]);
  key[3] = hc_swap32_S (tmps[gid].out[7]);
  u64 st[25];
  st[ 0] = hl32_to_64_S (key[1], key[0]);
  st[ 1] = hl32_to_64_S (key[3], key[2]);
  st[ 2] = hl32_to_64_S (ciphertext[1], ciphertext[0]);
  st[ 3] = hl32_to_64_S (ciphertext[3], ciphertext[2]);
  st[ 4] = hl32_to_64_S (ciphertext[5], ciphertext[4]);
  st[ 5] = hl32_to_64_S (ciphertext[7], ciphertext[6]);
  st[ 6] = hl32_to_64_S (ciphertext[9], ciphertext[8]);
  st[ 7] = hl32_to_64_S (ciphertext[11], ciphertext[10]);
  st[ 8] = hl32_to_64_S (ciphertext[13], ciphertext[12]);
  st[ 9] = hl32_to_64_S (ciphertext[15], ciphertext[14]);
  st[10] = hl32_to_64_S (ciphertext[17], ciphertext[16]);
  st[11] = hl32_to_64_S (ciphertext[19], ciphertext[18]);
  st[12] = 0x01;
  st[13] = 0;
  st[14] = 0;
  st[15] = 0;
  st[16] = 0;
  st[17] = 0;
  st[18] = 0;
  st[19] = 0;
  st[20] = 0;
  st[21] = 0;
  st[22] = 0;
  st[23] = 0;
  st[24] = 0;


I am clearly missing something as the test fails and when I ignore the test, it doesn't return the true password that is in the list. The error when running the module is 

* Device #1: ATTENTION! OpenCL kernel self-test failed.


Your device driver installation is probably broken.
See also: https://hashcat.net/faq/wrongdriver

Aborting session due to kernel self-test failure.

You can use --self-test-disable to override, but do not report related errors.

Module 15600, along with many others work without an issue so I know it is a problem with my code. 


In an ideal world the module would take a range of cipher lengths, which would open it to many more wallets. Full disclosure, I have minimal understanding of the C language (mainly Python and Java). 

Any help will be appreciated.
Reply
#2
Ok so, if the cipher text is divisible by 8 it works. So the issue must be the padding in the keccak hash. I still get the self test error, but it finds the password.
Reply
#3
I have managed to get it to work following the update for module 15700 provided by philsmd here https://hashcat.net/forum/archive/index....-9614.html.

I still get the * Device #1: ATTENTION! OpenCL kernel self-test failed unless I use the ST_HASH from module 15600.
Reply