mirror of
https://github.com/hashcat/hashcat.git
synced 2024-11-23 00:28:11 +00:00
194 lines
3.5 KiB
Perl
194 lines
3.5 KiB
Perl
|
#!/usr/bin/env perl
|
||
|
|
||
|
##
|
||
|
## Author......: See docs/credits.txt
|
||
|
## License.....: MIT
|
||
|
##
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
|
||
|
use Digest::SHA qw (sha1);
|
||
|
use Crypt::CBC;
|
||
|
|
||
|
sub module_constraints { [[0, 256], [-1, -1], [0, 55], [-1, -1], [-1, -1]] }
|
||
|
|
||
|
sub module_generate_hash
|
||
|
{
|
||
|
my $word = shift;
|
||
|
my $salt = shift; # unused since unsalted algo
|
||
|
my $iv = shift;
|
||
|
my $data = shift;
|
||
|
my $file = shift;
|
||
|
|
||
|
my $bit_len = 128;
|
||
|
my $key_len = $bit_len / 8;
|
||
|
|
||
|
my $is_decrypt = defined ($data);
|
||
|
|
||
|
my $padding = "none"; # for decryption we need this to "keep" the padding bytes
|
||
|
|
||
|
if ($is_decrypt == 0)
|
||
|
{
|
||
|
$padding = "standard";
|
||
|
|
||
|
# generate some additional random hash data:
|
||
|
|
||
|
my $iv_len = random_number (1, 16);
|
||
|
|
||
|
$iv = random_bytes ($iv_len);
|
||
|
|
||
|
$data = random_bytes (128);
|
||
|
|
||
|
$file = random_lowercase_string (random_number (1, 16));
|
||
|
|
||
|
$file .= ".txt";
|
||
|
}
|
||
|
|
||
|
my $iv_mod = $iv;
|
||
|
|
||
|
$iv_mod .= "\x00" x (16 - length ($iv_mod));
|
||
|
|
||
|
|
||
|
# start of main algo:
|
||
|
|
||
|
my $digest = sha1 ($word);
|
||
|
|
||
|
my $buf = "";
|
||
|
|
||
|
for (my $i = 0; $i < 20; $i++)
|
||
|
{
|
||
|
$buf .= chr (ord (substr ($digest, $i, 1)) ^ ord ("\x36")); # or just ^ 0x36
|
||
|
}
|
||
|
|
||
|
$buf .= "\x36" x 44;
|
||
|
|
||
|
my $key = sha1 ($buf);
|
||
|
|
||
|
|
||
|
$buf = "";
|
||
|
|
||
|
for (my $i = 0; $i < 20; $i++)
|
||
|
{
|
||
|
$buf .= chr (ord (substr ($digest, $i, 1)) ^ ord ("\x5c")); # or just ^ 0x36
|
||
|
}
|
||
|
|
||
|
$buf .= "\x5c" x 44;
|
||
|
|
||
|
# final key:
|
||
|
|
||
|
$key = $key . sha1 ($buf);
|
||
|
|
||
|
$key = substr ($key, 0, $key_len);
|
||
|
|
||
|
my $aes = Crypt::CBC->new ({
|
||
|
cipher => "Crypt::Rijndael",
|
||
|
key => $key,
|
||
|
iv => $iv_mod,
|
||
|
keysize => $key_len,
|
||
|
literal_key => 1,
|
||
|
header => "none",
|
||
|
padding => $padding,
|
||
|
});
|
||
|
|
||
|
if ($is_decrypt == 0)
|
||
|
{
|
||
|
$data = $aes->encrypt ($data);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
my $data_decrypted = $aes->decrypt ($data);
|
||
|
|
||
|
# the password is wrong if the decrypted data does not have the expected padding bytes:
|
||
|
|
||
|
if (substr ($data_decrypted, -16) ne "\x10" x 16)
|
||
|
{
|
||
|
$data = "fake"; # fake data
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $iv_padded = $iv;
|
||
|
|
||
|
if (length ($iv_padded) < 12)
|
||
|
{
|
||
|
$iv_padded .= "\x00" x (12 - length ($iv_padded));
|
||
|
}
|
||
|
|
||
|
my $hash = sprintf ("\$zip3\$*0*1*%i*0*%s*%s*0*0*0*%s", $bit_len, unpack ("H*", $iv_padded), unpack ("H*", $data), $file);
|
||
|
|
||
|
return $hash;
|
||
|
}
|
||
|
|
||
|
sub module_verify_hash
|
||
|
{
|
||
|
my $line = shift;
|
||
|
|
||
|
return unless (substr ($line, 0, 11) eq "\$zip3\$*0*1*");
|
||
|
|
||
|
my $idx1 = index ($line, ":");
|
||
|
|
||
|
return unless ($idx1 >= 11);
|
||
|
|
||
|
my $hash = substr ($line, 0, $idx1);
|
||
|
my $word = substr ($line, $idx1 + 1);
|
||
|
|
||
|
# bit_len:
|
||
|
|
||
|
$idx1 = index ($hash, "*", 11);
|
||
|
|
||
|
return unless ($idx1 > 0);
|
||
|
|
||
|
my $bit_len = substr ($hash, 11, $idx1 - 11);
|
||
|
|
||
|
$bit_len = int ($bit_len);
|
||
|
|
||
|
return unless ($bit_len == 128);
|
||
|
|
||
|
# unused:
|
||
|
|
||
|
return unless (substr ($hash, $idx1 + 1, 2) eq "0*");
|
||
|
|
||
|
# iv:
|
||
|
|
||
|
my $idx2 = index ($hash, "*", $idx1 + 3);
|
||
|
|
||
|
return unless ($idx2 > 0);
|
||
|
|
||
|
my $iv = substr ($hash, $idx1 + 3, $idx2 - $idx1 - 3);
|
||
|
|
||
|
return unless ($iv =~ m/^[0-9a-fA-F]+$/);
|
||
|
return unless ((length ($iv) % 2) == 0);
|
||
|
|
||
|
# data:
|
||
|
|
||
|
$idx1 = index ($hash, "*", $idx2 + 1);
|
||
|
|
||
|
return unless ($idx1 > 0);
|
||
|
|
||
|
my $data = substr ($hash, $idx2 + 1, $idx1 - $idx2 - 1);
|
||
|
|
||
|
return unless ($data =~ m/^[0-9a-fA-F]+$/);
|
||
|
return unless ((length ($data) % 2) == 0);
|
||
|
|
||
|
# unused:
|
||
|
|
||
|
return unless (substr ($hash, $idx1 + 1, 6) eq "0*0*0*");
|
||
|
|
||
|
# file:
|
||
|
|
||
|
my $file = substr ($hash, $idx1 + 7);
|
||
|
|
||
|
# convert to hex:
|
||
|
|
||
|
$iv = pack ("H*", $iv);
|
||
|
$data = pack ("H*", $data);
|
||
|
|
||
|
my $word_packed = pack_if_HEX_notation ($word);
|
||
|
|
||
|
my $new_hash = module_generate_hash ($word_packed, "", $iv, $data, $file);
|
||
|
|
||
|
return ($new_hash, $word);
|
||
|
}
|
||
|
|
||
|
1;
|