mirror of
https://github.com/hashcat/hashcat.git
synced 2024-11-23 16:38:29 +00:00
76 lines
2.1 KiB
Perl
76 lines
2.1 KiB
Perl
|
#!/usr/bin/env 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));
|