mirror of
https://github.com/hashcat/hashcat.git
synced 2024-11-01 13:09:11 +00:00
6365672c34
Some algorithms have ambiguous hashes (e.g. case-insensetive usernames in Net-NTLMv2 hashes). This optional function allows test modules to unify the hashlist before the verification process starts. Also update readme and minor code formatting.
113 lines
2.6 KiB
Perl
113 lines
2.6 KiB
Perl
#!/usr/bin/env perl
|
|
|
|
##
|
|
## Author......: See docs/credits.txt
|
|
## License.....: MIT
|
|
##
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Crypt::Mode::CBC;
|
|
use Crypt::PBKDF2;
|
|
use Digest::SHA qw (sha256 sha256_hex);
|
|
|
|
sub module_generate_hash
|
|
{
|
|
my $word = shift;
|
|
my $salt = shift // random_hex_string (2*16);
|
|
my $iter = shift // 100000;
|
|
my $iv = shift // random_hex_string (2*16);
|
|
my $plain = shift // random_hex_string (2*1024);
|
|
|
|
my $b_iv = pack ('H*', $iv);
|
|
my $b_salt = pack ('H*', $salt);
|
|
my $b_plain = pack ('H*', $plain);
|
|
|
|
my $kdf = Crypt::PBKDF2->new
|
|
(
|
|
hash_class => 'HMACSHA1',
|
|
iterations => $iter,
|
|
output_len => 32
|
|
);
|
|
|
|
my $pass_hash = sha256 ($word);
|
|
my $key = $kdf->PBKDF2 ($b_salt, $pass_hash);
|
|
my $cbc = Crypt::Mode::CBC->new ('AES', 0);
|
|
my $b_cipher = $cbc->encrypt ($b_plain, $key, $b_iv);
|
|
my $cipher = unpack ('H*', $b_cipher);
|
|
my $checksum = sha256_hex ($b_plain);
|
|
|
|
my $hash = '$odf$'."*1*1*$iter*32*$checksum*16*$iv*16*$salt*0*$cipher";
|
|
|
|
return $hash;
|
|
}
|
|
|
|
sub module_verify_hash
|
|
{
|
|
my $line = shift;
|
|
|
|
my ($hash, $word) = split (':', $line);
|
|
|
|
return unless defined $hash;
|
|
return unless defined $word;
|
|
|
|
$word = pack_if_HEX_notation ($word);
|
|
|
|
# tokenize
|
|
my @data = split ('\*', $hash);
|
|
|
|
next unless scalar @data == 12;
|
|
|
|
my $signature = shift @data;
|
|
my $cipher_type = shift @data;
|
|
my $cs_type = shift @data;
|
|
my $iter = shift @data;
|
|
my $cs_len = shift @data;
|
|
my $cs = shift @data;
|
|
my $iv_len = shift @data;
|
|
my $iv = shift @data;
|
|
my $salt_len = shift @data;
|
|
my $salt = shift @data;
|
|
my $unused = shift @data;
|
|
my $cipher = shift @data;
|
|
|
|
# validate
|
|
return unless $signature eq '$odf$';
|
|
return unless $cipher_type eq '1';
|
|
return unless $cs_type eq '1';
|
|
return unless $cs_len eq '32';
|
|
return unless $iv_len eq '16';
|
|
return unless $salt_len eq '16';
|
|
return unless $unused eq '0';
|
|
return unless defined $cipher;
|
|
|
|
# decrypt
|
|
my $b_iv = pack ('H*', $iv);
|
|
my $b_salt = pack ('H*', $salt);
|
|
my $b_cipher = pack ('H*', $cipher);
|
|
|
|
my $kdf = Crypt::PBKDF2->new
|
|
(
|
|
hash_class => 'HMACSHA1',
|
|
iterations => $iter,
|
|
output_len => 32
|
|
);
|
|
|
|
my $pass_hash = sha256 ($word);
|
|
my $key = $kdf->PBKDF2 ($b_salt, $pass_hash);
|
|
my $cbc = Crypt::Mode::CBC->new ('AES', 0);
|
|
my $b_plain = $cbc->decrypt ($b_cipher, $key, $b_iv);
|
|
my $plain = unpack ('H*', $b_plain);
|
|
|
|
my $new_hash = module_generate_hash ($word, $salt, $iter, $iv, $plain);
|
|
|
|
return unless defined $new_hash;
|
|
|
|
return unless $new_hash eq $hash;
|
|
|
|
return $new_hash;
|
|
}
|
|
|
|
1;
|