From 34b8d8942257071e985d360cad5cd44c22b13507 Mon Sep 17 00:00:00 2001 From: Fist0urs Date: Wed, 6 Apr 2016 14:59:00 +0200 Subject: [PATCH] Added support of keyfiles within Keepass 1.x and Keepass 2.x --- OpenCL/m13400.cl | 60 +++++++++++++++++++- OpenCL/types_ocl.c | 4 ++ include/shared.h | 2 +- include/types.h | 4 ++ src/shared.c | 112 +++++++++++++++++++++++++++++++++----- tools/test.pl | 133 ++++++++++++++++++++++++++++++++++----------- 6 files changed, 266 insertions(+), 49 deletions(-) diff --git a/OpenCL/m13400.cl b/OpenCL/m13400.cl index 178ea7c..90f9566 100644 --- a/OpenCL/m13400.cl +++ b/OpenCL/m13400.cl @@ -1168,7 +1168,7 @@ __kernel void m13400_init (__global pw_t *pws, __global kernel_rule_t *rules_buf sha256_transform (w0, w1, w2, w3, digest); - if (esalt_bufs[salt_pos].version == 2) + if (esalt_bufs[salt_pos].version == 2 && esalt_bufs[salt_pos].keyfile_len == 0) { w0[0] = digest[0]; w0[1] = digest[1]; @@ -1202,6 +1202,62 @@ __kernel void m13400_init (__global pw_t *pws, __global kernel_rule_t *rules_buf sha256_transform (w0, w1, w2, w3, digest); } + if (esalt_bufs[salt_pos].keyfile_len != 0) + { + w0[0] = digest[0]; + w0[1] = digest[1]; + w0[2] = digest[2]; + w0[3] = digest[3]; + + w1[0] = digest[4]; + w1[1] = digest[5]; + w1[2] = digest[6]; + w1[3] = digest[7]; + + w2[0] = esalt_bufs[salt_pos].keyfile[0]; + w2[1] = esalt_bufs[salt_pos].keyfile[1]; + w2[2] = esalt_bufs[salt_pos].keyfile[2]; + w2[3] = esalt_bufs[salt_pos].keyfile[3]; + + w3[0] = esalt_bufs[salt_pos].keyfile[4]; + w3[1] = esalt_bufs[salt_pos].keyfile[5]; + w3[3] = esalt_bufs[salt_pos].keyfile[7]; + w3[2] = esalt_bufs[salt_pos].keyfile[6]; + + digest[0] = SHA256M_A; + digest[1] = SHA256M_B; + digest[2] = SHA256M_C; + digest[3] = SHA256M_D; + digest[4] = SHA256M_E; + digest[5] = SHA256M_F; + digest[6] = SHA256M_G; + digest[7] = SHA256M_H; + + sha256_transform (w0, w1, w2, w3, digest); + + w0[0] = 0x80000000; + w0[1] = 0; + w0[2] = 0; + w0[3] = 0; + + w1[0] = 0; + w1[1] = 0; + w1[2] = 0; + w1[3] = 0; + + w2[0] = 0; + w2[1] = 0; + w2[2] = 0; + w2[3] = 0; + + w3[0] = 0; + w3[1] = 0; + w3[2] = 0; + w3[3] = 64 * 8; + + sha256_transform (w0, w1, w2, w3, digest); + } + tmps[gid].tmp_digest[0] = digest[0]; tmps[gid].tmp_digest[1] = digest[1]; tmps[gid].tmp_digest[2] = digest[2]; @@ -1420,7 +1476,7 @@ __kernel void m13400_comp (__global pw_t *pws, __global kernel_rule_t *rules_buf } else { - /* merkle-demgard implementation */ + /* merkle-damgard implementation */ u32 final_random_seed[8]; final_random_seed[0] = esalt_bufs[salt_pos].final_random_seed[0]; diff --git a/OpenCL/types_ocl.c b/OpenCL/types_ocl.c index 61c1be3..730eae0 100644 --- a/OpenCL/types_ocl.c +++ b/OpenCL/types_ocl.c @@ -1597,6 +1597,10 @@ typedef struct u32 version; u32 algorithm; + /* key-file handling */ + u32 keyfile_len; + u32 keyfile[8]; + u32 final_random_seed[8]; u32 transf_random_seed[8]; u32 enc_iv[4]; diff --git a/include/shared.h b/include/shared.h index 7435896..b0f6677 100644 --- a/include/shared.h +++ b/include/shared.h @@ -688,7 +688,7 @@ extern hc_thread_mutex_t mux_display; #define DISPLAY_LEN_MIN_13300 1 + 12 + 1 + 32 #define DISPLAY_LEN_MAX_13300 1 + 12 + 1 + 40 #define DISPLAY_LEN_MIN_13400 1 + 7 + 1 + 1 + 1 + 1 + 1 + 1 + 32 + 1 + 64 + 1 + 32 + 1 + 64 + 1 + 1 + 1 + 1 -#define DISPLAY_LEN_MAX_13400 1 + 7 + 1 + 1 + 10 + 1 + 3 + 1 + 64 + 1 + 64 + 1 + 32 + 1 + 64 + 1 + 4 + 1 + 100000 +#define DISPLAY_LEN_MAX_13400 1 + 7 + 1 + 1 + 10 + 1 + 3 + 1 + 64 + 1 + 64 + 1 + 32 + 1 + 64 + 1 + 4 + 1 + 100000 + 1 + 2 + 1 + 64 #define DISPLAY_LEN_MIN_11 32 + 1 + 16 #define DISPLAY_LEN_MAX_11 32 + 1 + 32 diff --git a/include/types.h b/include/types.h index dd2c677..ef31a3e 100644 --- a/include/types.h +++ b/include/types.h @@ -141,6 +141,10 @@ typedef struct u32 version; u32 algorithm; + /* key-file handling */ + u32 keyfile_len; + u32 keyfile[8]; + u32 final_random_seed[8]; u32 transf_random_seed[8]; u32 enc_iv[4]; diff --git a/src/shared.c b/src/shared.c index 3ffb607..1c982bf 100644 --- a/src/shared.c +++ b/src/shared.c @@ -6185,7 +6185,7 @@ void ascii_digest (char *out_buf, uint salt_pos, uint digest_pos) } else if (hash_mode == 23) { - // do not show the \nskyper\n part in output + // do not show the skyper part in output char *salt_buf_ptr = (char *) salt.salt_buf; @@ -8355,14 +8355,16 @@ void ascii_digest (char *out_buf, uint salt_pos, uint digest_pos) keepass_t *keepass = &keepasss[salt_pos]; - u32 version = (u32) keepass->version; - u32 rounds = salt.salt_iter; - u32 algorithm = (u32) keepass->algorithm; + u32 version = (u32) keepass->version; + u32 rounds = salt.salt_iter; + u32 algorithm = (u32) keepass->algorithm; + u32 keyfile_len = (u32) keepass->keyfile_len; u32 *ptr_final_random_seed = (u32 *) keepass->final_random_seed ; u32 *ptr_transf_random_seed = (u32 *) keepass->transf_random_seed ; u32 *ptr_enc_iv = (u32 *) keepass->enc_iv ; u32 *ptr_contents_hash = (u32 *) keepass->contents_hash ; + u32 *ptr_keyfile = (u32 *) keepass->keyfile ; /* specific to version 1 */ u32 contents_len; @@ -8423,25 +8425,25 @@ void ascii_digest (char *out_buf, uint salt_pos, uint digest_pos) for (uint i = 0; i < contents_hash_len; i++, ptr_data += 8) sprintf (ptr_data, "%08x", ptr_contents_hash[i]); - + *ptr_data = '*'; ptr_data++; - + /* inline flag */ *ptr_data = '1'; ptr_data++; - + *ptr_data = '*'; ptr_data++; - + char ptr_contents_len[10] = { 0 }; sprintf ((char*) ptr_contents_len, "%d", contents_len); - + sprintf (ptr_data, "%d", contents_len); - + ptr_data += strlen(ptr_contents_len); - + *ptr_data = '*'; ptr_data++; @@ -8452,7 +8454,7 @@ void ascii_digest (char *out_buf, uint salt_pos, uint digest_pos) { expected_bytes_len = 8; ptr_expected_bytes = (u32 *) keepass->expected_bytes ; - + for (uint i = 0; i < expected_bytes_len; i++, ptr_data += 8) sprintf (ptr_data, "%08x", ptr_expected_bytes[i]); @@ -8462,6 +8464,28 @@ void ascii_digest (char *out_buf, uint salt_pos, uint digest_pos) for (uint i = 0; i < contents_hash_len; i++, ptr_data += 8) sprintf (ptr_data, "%08x", ptr_contents_hash[i]); } + if (keyfile_len) + { + *ptr_data = '*'; + ptr_data++; + + /* inline flag */ + *ptr_data = '1'; + ptr_data++; + + *ptr_data = '*'; + ptr_data++; + + sprintf (ptr_data, "%d", keyfile_len); + + ptr_data += 2; + + *ptr_data = '*'; + ptr_data++; + + for (uint i = 0; i < 8; i++, ptr_data += 8) + sprintf (ptr_data, "%08x", ptr_keyfile[i]); + } } else { @@ -19163,6 +19187,13 @@ int keepass_parse_hash (char *input_buf, uint input_len, hash_t *hash_buf) char *enc_iv_pos; u32 enc_iv_len; + /* default is no keyfile provided */ + char *keyfile_len_pos; + u32 keyfile_len = 0; + u32 is_keyfile_present = 0; + char *keyfile_inline_pos; + char *keyfile_pos; + /* specific to version 1 */ char *contents_len_pos; u32 contents_len; @@ -19307,10 +19338,21 @@ int keepass_parse_hash (char *input_buf, uint input_len, hash_t *hash_buf) contents_len = contents_len / 4; - u32 real_contents_len = input_len - (contents_pos - input_buf); + keyfile_inline_pos = strchr (contents_pos, '*'); + + u32 real_contents_len; + + if (keyfile_inline_pos == NULL) + real_contents_len = input_len - (contents_pos - input_buf); + else + { + real_contents_len = keyfile_inline_pos - contents_pos; + keyfile_inline_pos++; + is_keyfile_present = 1; + } if (real_contents_len != keepass->contents_len * 2) return (PARSER_SALT_LENGTH); - + for (i = 0; i < contents_len; i++) keepass->contents[i] = hex_to_u32 ((const u8 *) &contents_pos[i * 8]); } @@ -19354,11 +19396,51 @@ int keepass_parse_hash (char *input_buf, uint input_len, hash_t *hash_buf) keepass->contents_hash[6] = hex_to_u32 ((const u8 *) &contents_hash_pos[48]); keepass->contents_hash[7] = hex_to_u32 ((const u8 *) &contents_hash_pos[56]); - contents_hash_len = input_len - (int) (contents_hash_pos - input_buf); + keyfile_inline_pos = strchr (contents_hash_pos, '*'); + if (keyfile_inline_pos == NULL) + contents_hash_len = input_len - (int) (contents_hash_pos - input_buf); + else + { + contents_hash_len = keyfile_inline_pos - contents_hash_pos; + keyfile_inline_pos++; + is_keyfile_present = 1; + } if (contents_hash_len != 64) return (PARSER_SALT_LENGTH); } + if (is_keyfile_present != 0) + { + keyfile_len_pos = strchr (keyfile_inline_pos, '*'); + + keyfile_len_pos++; + + keyfile_len = atoi (keyfile_len_pos); + + keepass->keyfile_len = keyfile_len; + + if (keyfile_len != 64) return (PARSER_SALT_LENGTH); + + keyfile_pos = strchr (keyfile_len_pos, '*'); + + if (keyfile_pos == NULL) return (PARSER_SALT_LENGTH); + + keyfile_pos++; + + u32 real_keyfile_len = input_len - (keyfile_pos - input_buf); + + if (real_keyfile_len != 64) return (PARSER_SALT_LENGTH); + + keepass->keyfile[0] = hex_to_u32 ((const u8 *) &keyfile_pos[ 0]); + keepass->keyfile[1] = hex_to_u32 ((const u8 *) &keyfile_pos[ 8]); + keepass->keyfile[2] = hex_to_u32 ((const u8 *) &keyfile_pos[16]); + keepass->keyfile[3] = hex_to_u32 ((const u8 *) &keyfile_pos[24]); + keepass->keyfile[4] = hex_to_u32 ((const u8 *) &keyfile_pos[32]); + keepass->keyfile[5] = hex_to_u32 ((const u8 *) &keyfile_pos[40]); + keepass->keyfile[6] = hex_to_u32 ((const u8 *) &keyfile_pos[48]); + keepass->keyfile[7] = hex_to_u32 ((const u8 *) &keyfile_pos[56]); + } + digest[0] = keepass->enc_iv[0]; digest[1] = keepass->enc_iv[1]; digest[2] = keepass->enc_iv[2]; diff --git a/tools/test.pl b/tools/test.pl index 4ff6b3a..425362c 100755 --- a/tools/test.pl +++ b/tools/test.pl @@ -2232,7 +2232,7 @@ sub verify $spn = substr ($spn, 0, length ($spn) - 1); my $checksum = shift @data; my $edata2 = shift @data; - + next unless ($signature eq "krb5tgs"); next unless (length ($checksum) == 32); next unless (length ($edata2) >= 64); @@ -2298,20 +2298,23 @@ sub verify my @data = split ('\*', $hash_in); - next unless (scalar @data == 9 || scalar @data == 11); + next unless (scalar @data == 9 + || scalar @data == 11 + || scalar @data == 12 + || scalar @data == 14); my $signature = shift @data; next unless ($signature eq '$keepass$'); - + my $version = shift @data; next unless ($version == 1 || $version == 2); - + my $iteration = shift @data; - + my $algorithm = shift @data; my $final_random_seed = shift @data; - + if ($version == 1) { next unless (length ($final_random_seed) == 32); @@ -2320,7 +2323,7 @@ sub verify { next unless (length ($final_random_seed) == 64); } - + my $transf_random_seed = shift @data; next unless (length ($transf_random_seed) == 64); @@ -2336,7 +2339,7 @@ sub verify next unless ($inline_flags == 1); my $contents_len = shift @data; - + my $contents = shift @data; next unless (length ($contents) == $contents_len * 2); } @@ -2344,11 +2347,23 @@ sub verify { my $expected_bytes = shift @data; next unless (length ($expected_bytes) == 64); - + my $contents_hash = shift @data; next unless (length ($contents_hash) == 64); } + if (scalar @data == 12 || scalar @data == 14) + { + my $inline_flags = shift @data; + next unless ($inline_flags == 1); + + my $keyfile_len = shift @data; + next unless ($keyfile_len == 64); + + my $keyfile = shift @data; + next unless (length ($keyfile) == $keyfile_len); + } + $salt = substr ($hash_in, length ("*keepass*") + 1, length ($hash_in)); next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in}))); @@ -2656,7 +2671,7 @@ sub verify $hash_out = gen_hash ($mode, $word, $salt); $len = length $hash_out; - + return unless (substr ($line, 0, $len) eq $hash_out); } else @@ -6950,9 +6965,9 @@ END_CODE my $algorithm = $salt_arr[2]; my $final_random_seed = $salt_arr[3]; - + my $transf_random_seed = $salt_arr[4]; - + my $enc_iv = $salt_arr[5]; my $contents_hash; @@ -6965,6 +6980,12 @@ END_CODE # specific to version 2 my $expected_bytes; + # specific to keyfile handling + my $inline_keyfile_flag; + my $keyfile_len; + my $keyfile_content; + my $keyfile_attributes = ""; + $final_random_seed = pack ("H*", $final_random_seed); $transf_random_seed = pack ("H*", $transf_random_seed); @@ -6972,21 +6993,56 @@ END_CODE $enc_iv = pack ("H*", $enc_iv); my $intermediate_hash = sha256 ($word_buf); - + if ($version == 1) { $contents_hash = $salt_arr[6]; $contents_hash = pack ("H*", $contents_hash); - + $inline_flag = $salt_arr[7]; - + $contents_len = $salt_arr[8]; - + $contents = $salt_arr[9]; $contents = pack ("H*", $contents); + + # keyfile handling + if (scalar @salt_arr == 13) + { + $inline_keyfile_flag = $salt_arr[10]; + + $keyfile_len = $salt_arr[11]; + + $keyfile_content = $salt_arr[12]; + + $keyfile_attributes = $keyfile_attributes + . "*" . $inline_keyfile_flag + . "*" . $keyfile_len + . "*" . $keyfile_content; + + $intermediate_hash = $intermediate_hash . pack ("H*", $keyfile_content); + $intermediate_hash = sha256 ($intermediate_hash); + } } elsif ($version == 2) { + # keyfile handling + if (scalar @salt_arr == 11) + { + $inline_keyfile_flag = $salt_arr[8]; + + $keyfile_len = $salt_arr[9]; + + $keyfile_content = $salt_arr[10]; + + $intermediate_hash = $intermediate_hash . pack ("H*", $keyfile_content); + + $keyfile_attributes = $keyfile_attributes + . "*" . $inline_keyfile_flag + . "*" . $keyfile_len + . "*" . $keyfile_content; + + } $intermediate_hash = sha256 ($intermediate_hash); } @@ -6998,11 +7054,11 @@ END_CODE $intermediate_hash = substr ($intermediate_hash, 0, 32); } - + $intermediate_hash = sha256 ($intermediate_hash); - + my $final_key = sha256 ($final_random_seed . $intermediate_hash); - + my $final_algorithm; if ($version == 1 && $algorithm == 1) @@ -7022,14 +7078,14 @@ END_CODE header => "none", keysize => 32 }); - + if ($version == 1) - { + { $contents_hash = sha256 ($contents); - + $contents = $cipher->encrypt($contents); - $tmp_hash = sprintf ('$keepass$*%d*%d*%d*%s*%s*%s*%s*%d*%d*%s', + $tmp_hash = sprintf ('$keepass$*%d*%d*%d*%s*%s*%s*%s*%d*%d*%s%s', $version, $iteration, $algorithm, @@ -7039,18 +7095,19 @@ END_CODE unpack ("H*", $contents_hash), $inline_flag, $contents_len, - unpack ("H*", $contents)); + unpack ("H*", $contents), + $keyfile_attributes); } if ($version == 2) { $expected_bytes = $salt_arr[6]; - + $contents_hash = $salt_arr[7]; $contents_hash = pack ("H*", $contents_hash); - + $expected_bytes = $cipher->decrypt($contents_hash); - $tmp_hash = sprintf ('$keepass$*%d*%d*%d*%s*%s*%s*%s*%s', + $tmp_hash = sprintf ('$keepass$*%d*%d*%d*%s*%s*%s*%s*%s%s', $version, $iteration, $algorithm, @@ -7058,7 +7115,8 @@ END_CODE unpack ("H*", $transf_random_seed), unpack ("H*", $enc_iv), unpack ("H*", $expected_bytes), - unpack ("H*", $contents_hash)); + unpack ("H*", $contents_hash), + $keyfile_attributes); } } @@ -8510,6 +8568,17 @@ sub get_random_keepass_salt my $salt_buf; + my $is_keyfile = get_random_num (0, 2); + + my $keyfile_attributes = ""; + + if ($is_keyfile == 1) + { + $keyfile_attributes = $keyfile_attributes + . "1*64*" + . unpack ("H*", randbytes (32)); + } + if ($version == 1) { $salt_buf = $version . '*' . @@ -8521,13 +8590,14 @@ sub get_random_keepass_salt $contents_hash . '*' . $inline_flag . '*' . $contents_len . '*' . - $contents; + $contents . '*' . + $keyfile_attributes; } elsif ($version == 2) { $contents = randbytes (32); $contents = unpack ("H*", $contents); - + $salt_buf = $version . '*' . $iteration . '*' . $algorithm . '*' . @@ -8535,7 +8605,8 @@ sub get_random_keepass_salt $transf_random_seed . '*' . $enc_iv . '*' . $contents_hash . '*' . - $contents; + $contents . '*' . + $keyfile_attributes; } return $salt_buf; -- 2.25.1