Added support of keyfiles within Keepass 1.x and Keepass 2.x
authorFist0urs <eddy.maaalou@gmail.com>
Wed, 6 Apr 2016 12:59:00 +0000 (14:59 +0200)
committerFist0urs <eddy.maaalou@gmail.com>
Wed, 6 Apr 2016 14:05:09 +0000 (16:05 +0200)
OpenCL/m13400.cl
OpenCL/types_ocl.c
include/shared.h
include/types.h
src/shared.c
tools/test.pl

index 178ea7c..90f9566 100644 (file)
@@ -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];
index 61c1be3..730eae0 100644 (file)
@@ -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];
index 7435896..b0f6677 100644 (file)
@@ -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
index dd2c677..ef31a3e 100644 (file)
@@ -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];
index 3ffb607..1c982bf 100644 (file)
@@ -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];
index 4ff6b3a..425362c 100755 (executable)
@@ -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;