File: sqlcipher2hashcat.pl

package info (click to toggle)
hashcat 6.2.6%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 63,932 kB
  • sloc: lisp: 584,043; ansic: 372,246; perl: 24,890; cpp: 23,731; sh: 3,927; python: 868; makefile: 777
file content (75 lines) | stat: -rwxr-xr-x 2,130 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/perl

##
## Author......: See docs/credits.txt
## License.....: MIT
##

# In a first version I wrote a kernel that followed the original sqlcipher scheme which uses a MAC to verify the integrity (and therefore we knew we had guessed the correct password).
# But it turns out it's much easier to exploit the sqlite header format, which guarantees 20 zero bytes starting from offset 72.
# See: https://www.sqlite.org/fileformat.html
# The advantage is the user doesn't need to guess the MAC hash type and/or pagesize (in case it they customized).
# The user still needs to know the KDF hash type and iteration count, but they sqlcipher v3 and v4 come with a default for these.
# We'll check only 12 of 16 bytes from the encrypted block as an optimization so we only need to decrypt one block.
# Another optimization is that since the scheme uses CBC we do not need to find the correct position of the IV.
# This position is depending on the pagesize and the KDF hash type (which could be customized).
# As an alternative, or in case the sqlite header changes, we could also use entropy test.
# -atom

use strict;
use warnings;

if (scalar (@ARGV) < 2)
{
  print "usage: $0 encrypted.db preset [hash] [iteration]\n\n";
  print "preset 1 = SQLCIPHER v3\n";
  print "preset 2 = SQLCIPHER v4\n";
  print "preset 3 = CUSTOM, please specify hash type (1 = SHA1, 2 = SHA256, 3 = SHA512) and iteration count\n";

  exit -1;
}

my $db     = $ARGV[0];
my $preset = $ARGV[1];

my $type = 0;
my $iter = 0;

if ($preset == 1)
{
  $type = 1;
  $iter = 64000;
}
elsif ($preset == 2)
{
  $type = 3;
  $iter = 256000;
}
elsif ($preset == 3)
{
  $type = $ARGV[2];
  $iter = $ARGV[3];
}
else
{
  die "Invalid preset\n";
}

open (IN, $db) or die ("$db: $!\n");

binmode (IN);

my $data;

if (read (IN, $data, 96) != 96)
{
  die "ERROR: Couldn't read data from the file. Maybe incorrect file format?\n";
}

close (IN);

my $salt = substr ($data,  0, 16);
my $iv   = substr ($data, 64, 16);
my $enc  = substr ($data, 80, 16);

printf ("SQLCIPHER*%d*%d*%s*%s*%s\n", $type, $iter, unpack ("H*", $salt), unpack ("H*", $iv), unpack ("H*", $enc));