mirror of
https://github.com/hashcat/hashcat.git
synced 2024-11-01 13:09:11 +00:00
13307 lines
312 KiB
Prolog
Executable File
13307 lines
312 KiB
Prolog
Executable File
#!/usr/bin/env perl
|
|
|
|
##
|
|
## Author......: See docs/credits.txt
|
|
## License.....: MIT
|
|
##
|
|
|
|
##
|
|
## Installation script for all perl and python modules:
|
|
##
|
|
## tools/install_modules.sh
|
|
##
|
|
|
|
##
|
|
## If you want to add a new hash mode, follow the STEP comments.
|
|
##
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Authen::Passphrase::LANManager;
|
|
use Authen::Passphrase::MySQL323;
|
|
use Authen::Passphrase::NTHash;
|
|
use Authen::Passphrase::PHPass;
|
|
use Convert::EBCDIC qw (ascii2ebcdic);
|
|
use Crypt::CBC;
|
|
use Crypt::DES;
|
|
use Crypt::Digest::RIPEMD160 qw (ripemd160_hex);
|
|
use Crypt::Digest::Whirlpool qw (whirlpool_hex);
|
|
use Crypt::ECB qw (encrypt);
|
|
use Crypt::Eksblowfish::Bcrypt qw (bcrypt en_base64);
|
|
use Crypt::Mode::CBC;
|
|
use Crypt::Mode::ECB;
|
|
use Crypt::MySQL qw (password41);
|
|
use Crypt::OpenSSH::ChachaPoly;
|
|
use Crypt::PBKDF2;
|
|
use Crypt::RC4;
|
|
use Crypt::Rijndael;
|
|
use Crypt::ScryptKDF qw (scrypt_hash scrypt_raw scrypt_b64);
|
|
use Crypt::Skip32;
|
|
use Crypt::Twofish;
|
|
use Crypt::UnixCrypt_XS qw (crypt_rounds fold_password base64_to_int24 block_to_base64 int24_to_base64);
|
|
use Digest::MD4 qw (md4 md4_hex);
|
|
use Digest::MD5 qw (md5 md5_hex);
|
|
use Digest::SHA qw (sha1 sha256 sha384 sha512 sha1_hex sha224_hex sha256_hex sha384_hex sha512_hex hmac_sha1 hmac_sha256 hmac_sha512);
|
|
use Digest::SHA1;
|
|
use Digest::SHA3 qw (sha3_224_hex sha3_256_hex sha3_384_hex sha3_512_hex);
|
|
use Digest::Keccak qw (keccak_224_hex keccak_256_hex keccak_384_hex keccak_512_hex);
|
|
use Digest::HMAC qw (hmac hmac_hex);
|
|
use Digest::BLAKE2 qw (blake2b_hex);
|
|
use Digest::GOST qw (gost gost_hex);
|
|
use Digest::HMAC_MD5 qw (hmac_md5);
|
|
use Digest::CRC qw (crc32);
|
|
use Digest::CMAC;
|
|
use Digest::SipHash qw (siphash);
|
|
use Digest::Perl::MD5;
|
|
use Encode;
|
|
use JSON;
|
|
use MIME::Base32 qw (encode_base32 decode_base32);
|
|
use MIME::Base64 qw (encode_base64 decode_base64 encode_base64url decode_base64url);
|
|
use Net::DNS::RR::NSEC3;
|
|
use Net::DNS::SEC;
|
|
use POSIX qw (strftime ceil);
|
|
use Text::Iconv;
|
|
|
|
my $hashcat = "./hashcat";
|
|
|
|
my $MAX_LEN = 55;
|
|
|
|
## STEP 1: Add your hash mode to this array.
|
|
#
|
|
# This array contains all supported hash modes.
|
|
#
|
|
##
|
|
|
|
my $MODES =
|
|
[
|
|
0, 10, 11, 12, 20, 21, 22, 23, 30, 40, 50,
|
|
60, 100, 101, 110, 111, 112, 120, 121, 122, 125, 130,
|
|
131, 132, 133, 140, 141, 150, 160, 200, 300, 400, 500,
|
|
600, 900, 1000, 1100, 1300, 1400, 1410, 1411, 1420, 1430, 1440,
|
|
1441, 1450, 1460, 1500, 1600, 1700, 1710, 1711, 1720, 1730, 1740,
|
|
1722, 1731, 1750, 1760, 1800, 2100, 2400, 2410, 2500, 2600, 2611,
|
|
2612, 2711, 2811, 3000, 3100, 3200, 3710, 3711, 3300, 3500, 3610,
|
|
3720, 3800, 3910, 4010, 4110, 4210, 4300, 4400, 4500, 4520, 4521,
|
|
4522, 4600, 4700, 4800, 4900, 5100, 5300, 5400, 5500, 5600, 5700,
|
|
5800, 6000, 6100, 6300, 6400, 6500, 6600, 6700, 6800, 6900, 7000,
|
|
7100, 7200, 7300, 7400, 7500, 7700, 7701, 7800, 7801, 7900, 8000,
|
|
8100, 8200, 8300, 8400, 8500, 8600, 8700, 8900, 9100, 9200, 9300,
|
|
9400, 9500, 9600, 9700, 9800, 9900, 10000, 10100, 10200, 10300, 10400,
|
|
10500, 10600, 10700, 10800, 10900, 11000, 11100, 11200, 11300, 11400, 11500,
|
|
11600, 11700, 11750, 11760, 11800, 11850, 11860, 11900, 12000, 12001, 12100,
|
|
12200, 12300, 12400, 12600, 12700, 12800, 12900, 13000, 13100, 13200, 13300,
|
|
13400, 13500, 13600, 13800, 13900, 14000, 14100, 14400, 14700, 14800, 14900,
|
|
15000, 15100, 15200, 15300, 15400, 15500, 15600, 15700, 15900, 16000, 16100,
|
|
16200, 16300, 16400, 16500, 16600, 16700, 16800, 16900, 17300, 17400, 17500,
|
|
17600, 17700, 17800, 17900, 18000, 18100, 18200, 18300, 18400, 18500, 99999
|
|
];
|
|
|
|
## STEP 2a: If your hash mode does not need a salt, add it to this array.
|
|
#
|
|
# This array contains all unsalted hash-modes that are handled in the 'default'
|
|
# branches in all three single, passthrough and verify test functions. There
|
|
# still are some unsalted hash-modes which are handled differently and are not
|
|
# listed here; they are caught in separate if conditions accordingly.
|
|
#
|
|
##
|
|
|
|
my $COMMON_UNSALTED_MODES =
|
|
[
|
|
0, 100, 101, 133, 200, 300, 600, 900, 1000, 1300, 1400,
|
|
1700, 2600, 3500, 4300, 4400, 4500, 4600, 4700, 5100, 5700, 6000,
|
|
6100, 6900, 9900, 10800, 11500, 11700, 11800, 16400, 17300, 17400, 17500,
|
|
17600, 17700, 17800, 17900, 18000, 18500, 99999
|
|
];
|
|
|
|
## STEP 2b: If your hash-mode has a salt without any specific syntax,
|
|
## add it to this array. Else look for STEP 2c (several spots).
|
|
#
|
|
# Same as above, only for salted hashes without specific salt formats.
|
|
#
|
|
##
|
|
|
|
my $COMMON_DEFAULT_SALTED_MODES =
|
|
[
|
|
10, 20, 23, 30, 40, 50, 60, 110, 120, 130, 140,
|
|
150, 160, 1410, 1420, 1430, 1440, 1450, 1460, 1710, 1720, 1730,
|
|
1740, 1750, 1760, 3610, 3710, 3720, 3910, 4010, 4110, 4210, 11750,
|
|
11760, 11850, 11860, 18100
|
|
];
|
|
|
|
# Arrays for hash modes with maximum password length 15
|
|
|
|
my $LESS_FIFTEEN = [500, 1600, 1800, 3200, 6300, 7400, 10500, 10700];
|
|
|
|
# Arrays for hash modes with unusual salts
|
|
|
|
my $ALLOW_LONG_SALT =
|
|
[
|
|
2500, 4520, 4521, 5500, 5600, 7100, 7200, 7300, 9400, 9500, 9600,
|
|
9700, 9800, 10400, 10500, 10600, 10700, 1100, 11000, 11200, 11300, 11400,
|
|
11600, 12600, 13500, 13800, 15000, 16900
|
|
];
|
|
|
|
my $IS_UTF16LE =
|
|
[
|
|
30, 40, 130, 131, 132, 133, 140, 141, 1000, 1100, 1430,
|
|
1440, 1441, 1730, 1740, 1731, 5500, 5600, 8000, 9400, 9500, 9600,
|
|
9700, 9800, 11600, 13500, 13800
|
|
];
|
|
|
|
my $LOTUS_MAGIC_TABLE =
|
|
[
|
|
0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c,
|
|
0x1b, 0x33, 0xfd, 0xd0, 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b,
|
|
0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, 0x41, 0x9f, 0xe1, 0xd9,
|
|
0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
|
|
0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0,
|
|
0xa6, 0x3f, 0xd8, 0x0c, 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17,
|
|
0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, 0x48, 0xe6, 0x1e, 0x53,
|
|
0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
|
|
0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12,
|
|
0xba, 0x3c, 0x06, 0x4e, 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b,
|
|
0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, 0x3a, 0xde, 0x96, 0x0e,
|
|
0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
|
|
0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02,
|
|
0x75, 0xd5, 0x61, 0xe3, 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e,
|
|
0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, 0xb4, 0xc5, 0xcc, 0x70,
|
|
0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
|
|
0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b,
|
|
0x82, 0xf9, 0x40, 0xb5, 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97,
|
|
0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, 0x64, 0x6d, 0x7a, 0xd4,
|
|
0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
|
|
0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9,
|
|
0x4c, 0xff, 0x43, 0xab
|
|
];
|
|
|
|
my $PDF_PADDING =
|
|
[
|
|
0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56,
|
|
0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
|
|
0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
|
|
];
|
|
|
|
my $CISCO_BASE64_MAPPING =
|
|
{
|
|
'A', '.', 'B', '/', 'C', '0', 'D', '1', 'E', '2', 'F', '3', 'G', '4', 'H',
|
|
'5', 'I', '6', 'J', '7', 'K', '8', 'L', '9', 'M', 'A', 'N', 'B', 'O', 'C',
|
|
'P', 'D', 'Q', 'E', 'R', 'F', 'S', 'G', 'T', 'H', 'U', 'I', 'V', 'J', 'W',
|
|
'K', 'X', 'L', 'Y', 'M', 'Z', 'N', 'a', 'O', 'b', 'P', 'c', 'Q', 'd', 'R',
|
|
'e', 'S', 'f', 'T', 'g', 'U', 'h', 'V', 'i', 'W', 'j', 'X', 'k', 'Y', 'l',
|
|
'Z', 'm', 'a', 'n', 'b', 'o', 'c', 'p', 'd', 'q', 'e', 'r', 'f', 's', 'g',
|
|
't', 'h', 'u', 'i', 'v', 'j', 'w', 'k', 'x', 'l', 'y', 'm', 'z', 'n', '0',
|
|
'o', '1', 'p', '2', 'q', '3', 'r', '4', 's', '5', 't', '6', 'u', '7', 'v',
|
|
'8', 'w', '9', 'x', '+', 'y', '/', 'z'
|
|
};
|
|
|
|
if (scalar @ARGV < 1)
|
|
{
|
|
usage_die ();
|
|
}
|
|
|
|
my $type;
|
|
my $mode;
|
|
my $len;
|
|
|
|
$type = shift @ARGV;
|
|
|
|
if ($type ne "verify")
|
|
{
|
|
if (scalar @ARGV > 1)
|
|
{
|
|
$mode = shift @ARGV;
|
|
$len = shift @ARGV;
|
|
}
|
|
elsif (scalar @ARGV == 1)
|
|
{
|
|
$mode = shift @ARGV;
|
|
$len = 0;
|
|
}
|
|
else
|
|
{
|
|
$len = 0;
|
|
}
|
|
|
|
if ($type eq "single")
|
|
{
|
|
single ($mode);
|
|
}
|
|
elsif ($type eq "passthrough")
|
|
{
|
|
passthrough ($mode);
|
|
}
|
|
else
|
|
{
|
|
usage_die ();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (scalar @ARGV != 4)
|
|
{
|
|
usage_die ();
|
|
}
|
|
|
|
my $mode = shift @ARGV;
|
|
my $hash_file = shift @ARGV;
|
|
my $in_file = shift @ARGV;
|
|
my $out_file = shift @ARGV;
|
|
|
|
my $db;
|
|
|
|
open (IN, "<", $hash_file) or die ("$hash_file: $!\n");
|
|
|
|
# clever ? the resulting database could be huge
|
|
# but we need some way to map lines in hashfile w/ cracks
|
|
# maybe rli2 way would be more clever (needs sorted input)
|
|
|
|
while (my $line = <IN>)
|
|
{
|
|
$line =~ s/[\n\r]*$//;
|
|
|
|
$db->{$line} = undef;
|
|
}
|
|
|
|
close (IN);
|
|
|
|
verify ($mode, $db, $in_file, $out_file);
|
|
}
|
|
|
|
# Array lookup
|
|
sub is_in_array
|
|
{
|
|
my $value = shift;
|
|
my $array = shift;
|
|
|
|
return grep { $_ eq $value } @{$array};
|
|
}
|
|
|
|
sub verify
|
|
{
|
|
my $mode = shift;
|
|
my $db = shift;
|
|
my $in_file = shift;
|
|
my $out_file = shift;
|
|
|
|
my $hash_in;
|
|
my $hash_out;
|
|
my $iter;
|
|
my $salt;
|
|
my $word;
|
|
my $param;
|
|
my $param2;
|
|
my $param3;
|
|
my $param4;
|
|
my $param5;
|
|
my $param6;
|
|
my $param7;
|
|
my $param8;
|
|
my $param9;
|
|
my $param10;
|
|
my $param11;
|
|
|
|
open (IN, "<", $in_file) or die ("$in_file: $!\n");
|
|
open (OUT, ">", $out_file) or die ("$out_file: $!\n");
|
|
|
|
my $len;
|
|
|
|
my $base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
my $itoa64_1 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
my $itoa64_2 = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
|
|
while (my $line = <IN>)
|
|
{
|
|
chomp ($line);
|
|
|
|
$line =~ s/\n$//;
|
|
$line =~ s/\r$//;
|
|
|
|
# remember always do "exists ($db->{$hash_in})" checks as soon as possible and don't forget it
|
|
|
|
# unsalted
|
|
if (is_in_array ($mode, $COMMON_UNSALTED_MODES)
|
|
|| $mode == 2400 || $mode == 3000
|
|
|| $mode == 8600 || $mode == 16000)
|
|
{
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$word = substr ($line, $index + 1);
|
|
}
|
|
# hash:salt
|
|
elsif (is_in_array ($mode, $COMMON_DEFAULT_SALTED_MODES)
|
|
|| $mode == 11 || $mode == 12 || $mode == 21 || $mode == 22
|
|
|| $mode == 112 || $mode == 121 || $mode == 1100 || $mode == 2410
|
|
|| $mode == 2611 || $mode == 2711 || $mode == 2811 || $mode == 3100
|
|
|| $mode == 3800 || $mode == 4520 || $mode == 4521 || $mode == 4522
|
|
|| $mode == 4900 || $mode == 5800 || $mode == 8400 || $mode == 11000
|
|
|| $mode == 12600 || $mode == 13500 || $mode == 13800 || $mode == 13900
|
|
|| $mode == 14000 || $mode == 14100 || $mode == 14400 || $mode == 14900
|
|
|| $mode == 15000)
|
|
{
|
|
# get hash
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
# identify lenghts of both salt and plain
|
|
|
|
my $salt_plain = substr ($line, $index1 + 1);
|
|
|
|
my $num_cols = () = $salt_plain =~ /:/g;
|
|
|
|
my $index2;
|
|
my $matched = 0;
|
|
my $start = 0;
|
|
|
|
$word = undef;
|
|
|
|
# fuzzy
|
|
foreach (my $i = 0; $i < $num_cols; $i++)
|
|
{
|
|
$index2 = index ($salt_plain, ":", $start);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$start = $index2 + 1;
|
|
|
|
$salt = substr ($salt_plain, 0, $index2);
|
|
$word = substr ($salt_plain, $index2 + 1);
|
|
|
|
# can't be true w/ wrong $hash:$salt, otherwise the
|
|
# algo must have many collisions
|
|
|
|
if (exists ($db->{$hash_in . ":" . $salt}))
|
|
{
|
|
$hash_in = $hash_in . ":" . $salt;
|
|
$matched = 1;
|
|
last;
|
|
}
|
|
}
|
|
|
|
next unless ($matched); # therefore: true == exists ($db->{$hash_in}
|
|
next unless (! defined ($db->{$hash_in}));
|
|
}
|
|
# dcc2
|
|
elsif ($mode == 2100)
|
|
{
|
|
# get hash
|
|
my $index1 = index ($line, "\$DCC2\$");
|
|
|
|
next if $index1 != 0;
|
|
|
|
# iterations
|
|
my $index2 = index ($line, "#", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$iter = substr ($line, $index1 + 6, $index2 - $index1 - 6);
|
|
|
|
# get hash
|
|
$index1 = index ($line, "#");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1 + 1);
|
|
|
|
# identify lenghts of both salt and plain
|
|
|
|
my $salt_plain = substr ($line, $index2 + 1);
|
|
|
|
my $num_cols = () = $salt_plain =~ /:/g;
|
|
|
|
my $matched = 0;
|
|
my $start = 0;
|
|
my $index3 = 0;
|
|
my $raw_hash;
|
|
|
|
$word = undef;
|
|
|
|
# fuzzy
|
|
foreach (my $i = 0; $i < $num_cols; $i++)
|
|
{
|
|
$index2 = index ($salt_plain, ":", $start);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$start = $index2 + 1;
|
|
|
|
$index3 = rindex ($salt_plain, "#", $index2);
|
|
|
|
$raw_hash = substr ($salt_plain, $index3 + 1, $index2 - $index3 - 1);
|
|
$salt = substr ($salt_plain, 0, $index3);
|
|
$word = substr ($salt_plain, $index2 + 1);
|
|
|
|
if (exists ($db->{$hash_in . $salt . "#" .$raw_hash}))
|
|
{
|
|
$hash_in = $hash_in . $salt . "#" . $raw_hash;
|
|
$matched = 1;
|
|
last;
|
|
}
|
|
}
|
|
|
|
next unless ($matched); # therefore: true == exists ($db->{$hash_in}
|
|
next unless (! defined ($db->{$hash_in}));
|
|
}
|
|
# salt:hash guaranteed only : because of hex salt
|
|
elsif ($mode == 7300)
|
|
{
|
|
# split hash and plain
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$salt = substr ($line, 0, $index1);
|
|
|
|
$salt = pack ("H*", $salt);
|
|
|
|
my $rest = substr ($line, $index1 + 1);
|
|
|
|
my $index2 = index ($rest, ":");
|
|
|
|
next if $index2 < 1;
|
|
|
|
$hash_in = substr ($rest, 0, $index2);
|
|
|
|
$word = substr ($rest, $index2 + 1);
|
|
|
|
next unless (exists ($db->{$salt . ":" . $hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# 1salthash fixed
|
|
elsif ($mode == 8100)
|
|
{
|
|
# split hash and plain
|
|
$salt = substr ($line, 1, 8);
|
|
|
|
my $rest = substr ($line, 1 + 8);
|
|
|
|
my $index2 = index ($rest, ":");
|
|
|
|
next if $index2 < 1;
|
|
|
|
$hash_in = substr ($rest, 0, $index2);
|
|
|
|
$word = substr ($rest, $index2 + 1);
|
|
|
|
next unless (exists ($db->{"1" . $salt . $hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# base64 and salt embedded SSHA1, salt length = total lenght - 20
|
|
elsif ($mode == 111)
|
|
{
|
|
# split hash and plain
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
# remove signature
|
|
my $plain_base64 = substr ($hash_in, 6);
|
|
|
|
# base64 decode to extract salt
|
|
my $decoded = decode_base64 ($plain_base64);
|
|
|
|
$salt = substr ($decoded, 20);
|
|
}
|
|
# base64 and salt embedded SSHA512, salt length = total length - 64
|
|
elsif ($mode == 1711)
|
|
{
|
|
# split hash and plain
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
# remove signature
|
|
my $plain_base64 = substr ($hash_in, 9);
|
|
|
|
# base64 decode to extract salt
|
|
my $decoded = decode_base64 ($plain_base64);
|
|
|
|
$salt = substr ($decoded, 64);
|
|
}
|
|
# macOS (first 8 hex chars is salt)
|
|
# ArubaOS (the signature gets added in gen_hash)
|
|
elsif ($mode == 122 || $mode == 1722 || $mode == 125)
|
|
{
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$salt = substr ($hash_in, 0, 8);
|
|
}
|
|
# MSSQL (2000, 2005 AND 2012), salt after version number
|
|
elsif ($mode == 131 || $mode == 132 || $mode == 1731)
|
|
{
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$salt = substr ($hash_in, 6, 8);
|
|
}
|
|
# Sybase ASE
|
|
elsif ($mode == 8000)
|
|
{
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$salt = substr ($hash_in, 6, 16);
|
|
}
|
|
# episerver salts
|
|
elsif ($mode == 141 || $mode == 1441)
|
|
{
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $index2 = index ($line, "*", 14);
|
|
|
|
#extract salt from base64
|
|
my $plain_base64 = substr ($hash_in, 14, $index2 - 14);
|
|
|
|
$salt = decode_base64 ($plain_base64);
|
|
}
|
|
# phpass (first 8 after $P$/$H$ -- or $S$ with drupal7)
|
|
elsif ($mode == 400 || $mode == 7900)
|
|
{
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$salt = substr ($hash_in, 4, 8);
|
|
|
|
# iterations = 2 ^ cost (where cost == $iter)
|
|
$iter = index ($itoa64_1, substr ($hash_in, 3, 1));
|
|
}
|
|
# $something$[rounds=iter$]salt$ (get last $, then check iter)
|
|
elsif ($mode == 500 || $mode == 1600 || $mode == 1800 || $mode == 3300 || $mode == 7400)
|
|
{
|
|
my $index1 = index ($line, ":", 30);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$index1 = index ($hash_in, ",", 1);
|
|
my $index2 = index ($hash_in, "\$", 1);
|
|
|
|
if ($index1 != -1)
|
|
{
|
|
if ($index1 < $index2)
|
|
{
|
|
$index2 = $index1;
|
|
}
|
|
}
|
|
|
|
$param = substr ($hash_in, $index2, 1);
|
|
|
|
$index2++;
|
|
|
|
# rounds= if available
|
|
$iter = 0;
|
|
|
|
if (substr ($hash_in, $index2, 7) eq "rounds=")
|
|
{
|
|
my $old_index = $index2;
|
|
|
|
$index2 = index ($hash_in, "\$", $index2 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$iter = substr ($hash_in, $old_index + 7, $index2 - $old_index - 7);
|
|
|
|
$index2++;
|
|
}
|
|
|
|
# get salt
|
|
my $index3 = rindex ($hash_in, "\$");
|
|
|
|
next if $index3 < 1;
|
|
|
|
$salt = substr ($hash_in, $index2, $index3 - $index2);
|
|
}
|
|
# descrypt (salt in first 2 char)
|
|
elsif ($mode == 1500)
|
|
{
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$salt = substr ($hash_in, 0, 2);
|
|
}
|
|
# bcrypt $something$something$salt.hash
|
|
elsif ($mode == 3200)
|
|
{
|
|
my $index1 = index ($line, ":", 33);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $index2 = index ($hash_in, "\$", 4);
|
|
|
|
$iter = substr ($hash_in, 4, $index2 - 4);
|
|
|
|
my $plain_base64 = substr ($hash_in, $index2 + 1, 22);
|
|
|
|
# base64 mapping
|
|
my $encoded = "";
|
|
|
|
for (my $i = 0; $i < length ($plain_base64); $i++)
|
|
{
|
|
my $char = substr ($plain_base64, $i, 1);
|
|
$encoded .= substr ($base64, index ($itoa64_2, $char), 1);
|
|
}
|
|
|
|
$salt = decode_base64 ($encoded);
|
|
}
|
|
# md5 (chap)
|
|
elsif ($mode == 4800)
|
|
{
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
my $index3 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index3 < 1;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index3 - $index1 - 1);
|
|
|
|
$word = substr ($line, $index3 + 1);
|
|
|
|
$hash_in = substr ($line, 0, $index3);
|
|
}
|
|
# IKE (md5 and sha1)
|
|
elsif ($mode == 5300 || $mode == 5400)
|
|
{
|
|
my $num_cols = () = $line =~ /:/g;
|
|
|
|
next unless ($num_cols >= 9);
|
|
|
|
my $index1 = -1;
|
|
my $failed = 0;
|
|
|
|
for (my $j = 0; $j < 9; $j++)
|
|
{
|
|
$index1 = index ($line, ":", $index1 + 1);
|
|
|
|
if ($index1 < 1)
|
|
{
|
|
$failed = 1;
|
|
last;
|
|
}
|
|
}
|
|
|
|
next if ($failed);
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $index2 = rindex ($line, ":", $index1 - 1);
|
|
|
|
$salt = substr ($line, 0, $index2);
|
|
}
|
|
# NetNTLMv1
|
|
elsif ($mode == 5500)
|
|
{
|
|
my $index1 = index ($line, "::");
|
|
|
|
next if $index1 < 1;
|
|
|
|
my $index2 = index ($line, ":", $index1 + 2);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$index2 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, 0, $index2);
|
|
|
|
$index2 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt .= substr ($line, $index2 + 1, 16);
|
|
|
|
$index2 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index2);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$word = substr ($line, $index2 + 1);
|
|
}
|
|
# NetNTLMv2
|
|
elsif ($mode == 5600)
|
|
{
|
|
my $index1 = index ($line, "::");
|
|
|
|
next if $index1 < 1;
|
|
|
|
my $index2 = index ($line, ":", $index1 + 2);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$index2 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, 0, $index2);
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt .= substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$hash_in = substr ($line, 0, $index2);
|
|
|
|
# do it later on for this hash mode:
|
|
# next unless ((exists ($db->{$hash_in}) and (! defined ($db->{$hash_in}))) or (exists ($db->{$mod}) and (! defined ($db->{$mod}))));
|
|
|
|
$word = substr ($line, $index2 + 1);
|
|
}
|
|
# AIX smd5 something BRACE salt$
|
|
elsif ($mode == 6300)
|
|
{
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $index2 = index ($hash_in, "}");
|
|
my $index3 = rindex ($hash_in, "\$");
|
|
|
|
$salt = substr ($hash_in, $index2 + 1, $index3 - $index2 - 1);
|
|
}
|
|
# AIX: something$salt$ (no $ at position 1)
|
|
elsif ($mode == 6400 || $mode == 6500 || $mode == 6700)
|
|
{
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $index2 = index ($hash_in, "}");
|
|
my $index3 = index ($hash_in, "\$");
|
|
my $index4 = rindex ($hash_in, "\$");
|
|
|
|
$salt = substr ($hash_in, $index3 + 1, $index4 - $index3 - 1);
|
|
|
|
$iter = substr ($hash_in, $index2 + 1, $index3 - $index2 - 1);
|
|
}
|
|
# 1Password, agilekeychain
|
|
elsif ($mode == 6600)
|
|
{
|
|
my $num_cols = () = $line =~ /:/g;
|
|
|
|
next unless ($num_cols > 2);
|
|
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$iter = substr ($line, 0, $index1);
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$salt .= substr ($line, $index2 + 1, $index1 - $index2 - 33);
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
}
|
|
# 1Password, cloudkeychain
|
|
elsif ($mode == 8200)
|
|
{
|
|
my @datas = split (":", $line);
|
|
|
|
next if scalar @datas < 4;
|
|
|
|
my $hash = shift @datas;
|
|
$salt = shift @datas;
|
|
$iter = shift @datas;
|
|
my $data = shift @datas;
|
|
|
|
$hash_in = $hash . ":" . $salt . ":" . $iter . ":" . $data;
|
|
|
|
$salt .= $data;
|
|
|
|
$word = join (":", @datas);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# lastpass (hash:iter:salt)
|
|
elsif ($mode == 6800)
|
|
{
|
|
my $index1 = index ($line, ":", 34);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
# identify lenghts of both salt and plain
|
|
|
|
my $salt_plain = substr ($line, $index1 + 1);
|
|
|
|
my $num_cols = () = $salt_plain =~ /:/g;
|
|
|
|
my $index2;
|
|
my $matched = 0;
|
|
my $start = 0;
|
|
|
|
$word = undef;
|
|
|
|
# fuzzy
|
|
foreach (my $i = 0; $i < $num_cols; $i++)
|
|
{
|
|
$index2 = index ($salt_plain, ":", $start);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$start = $index2 + 1;
|
|
|
|
$salt = substr ($salt_plain, 0, $index2);
|
|
$word = substr ($salt_plain, $index2 + 1);
|
|
|
|
# can't be true w/ wrong $hash:$salt, otherwise the
|
|
# algo must have many collisions
|
|
|
|
if (exists ($db->{$hash_in . ":" . $salt}))
|
|
{
|
|
$hash_in = $hash_in . ":" . $salt;
|
|
$matched = 1;
|
|
last;
|
|
}
|
|
}
|
|
|
|
next unless ($matched); # therefore: true == exists ($db->{$hash_in}
|
|
next unless (! defined ($db->{$hash_in}));
|
|
|
|
$index1 = index ($hash_in, ":");
|
|
$index2 = index ($hash_in, ":", $index1 + 1);
|
|
|
|
$iter = substr ($hash_in, $index1 + 1, $index2 - $index1 - 1);
|
|
$salt = substr ($hash_in, $index2 + 1);
|
|
}
|
|
# Fortigate
|
|
elsif ($mode == 7000)
|
|
{
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 != 47;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next unless (substr ($hash_in, 0, 3) eq "AK1");
|
|
|
|
my $decoded = decode_base64 (substr ($hash_in, 3));
|
|
|
|
$salt = substr ($decoded, 0, 12);
|
|
$salt = unpack ("H*", $salt);
|
|
}
|
|
# macOS 10.* : $something$iter$salt$
|
|
elsif ($mode == 7100)
|
|
{
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $index2 = index ($hash_in, "\$", 5);
|
|
|
|
next if $index2 < 1;
|
|
|
|
my $index3 = index ($hash_in, "\$", $index2 + 1);
|
|
|
|
$salt = substr ($hash_in, $index2 + 1, $index3 - $index2 - 1);
|
|
|
|
$iter = substr ($hash_in, 4, $index2 - 4);
|
|
|
|
next if (int ($iter) < 1);
|
|
}
|
|
# grub: something1.something2.something3.iter.salt.
|
|
elsif ($mode == 7200)
|
|
{
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $index2 = index ($hash_in, ".", 19);
|
|
|
|
next if $index2 < 1;
|
|
|
|
my $index3 = index ($hash_in, ".", $index2 + 1);
|
|
|
|
$salt = substr ($hash_in, $index2 + 1, $index3 - $index2 - 1);
|
|
|
|
$iter = substr ($hash_in, 19, $index2 - 19);
|
|
|
|
next if (int ($iter) < 1);
|
|
}
|
|
# $something1$something2$something3$something4$salt$
|
|
elsif ($mode == 7500 )
|
|
{
|
|
my $index1 = index ($line, "\$", 11);
|
|
|
|
next if $index1 < 1;
|
|
|
|
my $index2 = index ($line, "\$", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
my $index3 = index ($line, "\$", $index2 + 1);
|
|
|
|
next if $index3 < 1;
|
|
|
|
$index2 = index ($line, ":", $index3 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index2);
|
|
$word = substr ($line, $index2 + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$salt = substr ($hash_in, 11, $index3 - 10);
|
|
$salt .= substr ($hash_in, $index2 - 32) . "\$\$";
|
|
$salt .= substr ($hash_in, $index3 + 1, $index2 - $index3 - 32 - 1);
|
|
}
|
|
# $salt$$hash
|
|
elsif ($mode == 7700 || $mode == 7800 || $mode == 7701 || $mode == 7801)
|
|
{
|
|
my $index1 = index ($line, ":");
|
|
|
|
next if $index1 < 1;
|
|
|
|
my @split1 = split (":", $line);
|
|
|
|
my @split2 = split ('\$', $split1[0]);
|
|
|
|
next unless scalar @split2 == 2;
|
|
|
|
$hash_in = $split1[0];
|
|
|
|
if (scalar @split1 > 1)
|
|
{
|
|
$word = $split1[1];
|
|
}
|
|
else
|
|
{
|
|
$word = "";
|
|
}
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$salt = $split2[0];
|
|
}
|
|
# DNSSEC
|
|
elsif ($mode == 8300)
|
|
{
|
|
my @datas = split (":", $line);
|
|
|
|
next if scalar @datas != 5;
|
|
|
|
my $hash;
|
|
my $domain;
|
|
|
|
($hash, $domain, $salt, $iter, $word) = @datas;
|
|
|
|
$hash_in = $hash . ":" . $domain . ":" . $salt . ":" . $iter;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
$salt = $domain . ":" . $salt;
|
|
}
|
|
# RACF
|
|
elsif ($mode == 8500)
|
|
{
|
|
my @line_elements = split (":", $line);
|
|
|
|
next if scalar @line_elements < 2;
|
|
|
|
# get hash and word
|
|
|
|
$hash_in = shift @line_elements;
|
|
|
|
$word = join (":", @line_elements);
|
|
|
|
# get signature
|
|
|
|
my @hash_elements = split ('\*', $hash_in);
|
|
|
|
next unless ($hash_elements[0] eq '$racf$');
|
|
|
|
$salt = $hash_elements[1];
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# DOMINO 6
|
|
elsif ($mode == 8700)
|
|
{
|
|
# split hash and plain
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $plain_base64 = substr ($hash_in, 2, -1);
|
|
|
|
($_, $salt, $param) = domino_decode ($plain_base64);
|
|
}
|
|
# PHPS
|
|
elsif ($mode == 2612)
|
|
{
|
|
next unless (substr ($line, 0, 6) eq '$PHPS$');
|
|
|
|
# get hash
|
|
my $index1 = index ($line, "\$", 6);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$salt = substr ($line, 6, $index1 - 6);
|
|
|
|
$salt = pack ("H*", $salt);
|
|
|
|
my $index2 = index ($line, "\:", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$word = substr ($line, $index2 + 1);
|
|
|
|
$hash_in = substr ($line, 0, $index2);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Mediawiki B type
|
|
elsif ($mode == 3711)
|
|
{
|
|
next unless (substr ($line, 0, 3) eq '$B$');
|
|
|
|
# get hash
|
|
my $index1 = index ($line, "\$", 3);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$salt = substr ($line, 3, $index1 - 3);
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$word = substr ($line, $index2 + 1);
|
|
|
|
$hash_in = substr ($line, 0, $index2);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# scrypt
|
|
elsif ($mode == 8900)
|
|
{
|
|
next unless (substr ($line, 0, 7) eq 'SCRYPT:');
|
|
|
|
# get hash
|
|
my $index1 = index ($line, ":", 7);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# N
|
|
my $N = substr ($line, 7, $index1 - 7);
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
# r
|
|
my $r = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# p
|
|
my $p = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
$param = $N;
|
|
$param2 = $r;
|
|
$param3 = $p;
|
|
|
|
$index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
# salt
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$salt = decode_base64 ($salt);
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# digest
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# LOTUS 8
|
|
elsif ($mode == 9100)
|
|
{
|
|
# split hash and plain
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $base64_part = substr ($hash_in, 2, -1);
|
|
|
|
($_, $salt, $iter, $param) = domino_85x_decode ($base64_part);
|
|
|
|
next if ($iter < 1);
|
|
}
|
|
# Cisco $8$ - PBKDF2-HMAC-SHA256
|
|
elsif ($mode == 9200)
|
|
{
|
|
next unless (substr ($line, 0, 3) eq '$8$');
|
|
|
|
# get hash
|
|
my $index1 = index ($line, "\$", 3);
|
|
|
|
next if $index1 != 17;
|
|
|
|
my $index2 = index ($line, "\$", $index1 + 1);
|
|
|
|
# salt
|
|
$salt = substr ($line, 3, $index1 - 3);
|
|
|
|
$index1 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# digest
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Cisco $9$ - scrypt
|
|
elsif ($mode == 9300)
|
|
{
|
|
next unless (substr ($line, 0, 3) eq '$9$');
|
|
|
|
# get hash
|
|
my $index1 = index ($line, "\$", 3);
|
|
|
|
next if $index1 != 17;
|
|
|
|
my $index2 = index ($line, "\$", $index1 + 1);
|
|
|
|
# salt
|
|
$salt = substr ($line, 3, $index1 - 3);
|
|
|
|
$index1 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# digest
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Office 2007
|
|
elsif ($mode == 9400)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data == 8;
|
|
|
|
next unless (shift @data eq '$office$');
|
|
next unless (shift @data eq '2007');
|
|
next unless (shift @data eq '20');
|
|
|
|
my $aes_key_size = shift @data;
|
|
|
|
next unless (($aes_key_size eq '128') || ($aes_key_size eq '256'));
|
|
next unless (shift @data eq '16');
|
|
|
|
next unless (length $data[0] == 32);
|
|
next unless (length $data[1] == 32);
|
|
next unless (length $data[2] == 40);
|
|
|
|
$salt = shift @data;
|
|
$param = shift @data;
|
|
$param2 = $aes_key_size;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Office 2010
|
|
elsif ($mode == 9500)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data == 8;
|
|
|
|
next unless (shift @data eq '$office$');
|
|
next unless (shift @data eq '2010');
|
|
next unless (shift @data eq '100000');
|
|
next unless (shift @data eq '128');
|
|
next unless (shift @data eq '16');
|
|
|
|
next unless (length $data[0] == 32);
|
|
next unless (length $data[1] == 32);
|
|
next unless (length $data[2] == 64);
|
|
|
|
$salt = shift @data;
|
|
$param = shift @data;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Office 2013
|
|
elsif ($mode == 9600)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data == 8;
|
|
|
|
next unless (shift @data eq '$office$');
|
|
next unless (shift @data eq '2013');
|
|
next unless (shift @data eq '100000');
|
|
next unless (shift @data eq '256');
|
|
next unless (shift @data eq '16');
|
|
|
|
next unless (length $data[0] == 32);
|
|
next unless (length $data[1] == 32);
|
|
next unless (length $data[2] == 64);
|
|
|
|
$salt = shift @data;
|
|
$param = shift @data;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Office Old $1 $2
|
|
elsif ($mode == 9700)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data == 4;
|
|
|
|
my $signature = shift @data;
|
|
|
|
next unless (($signature eq '$oldoffice$0') || ($signature eq '$oldoffice$1'));
|
|
|
|
next unless (length $data[0] == 32);
|
|
next unless (length $data[1] == 32);
|
|
next unless (length $data[2] == 32);
|
|
|
|
$salt = shift @data;
|
|
$param = shift @data;
|
|
$param2 = substr ($signature, 11, 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Office Old $3 $4
|
|
elsif ($mode == 9800)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data == 4;
|
|
|
|
my $signature = shift @data;
|
|
|
|
next unless (($signature eq '$oldoffice$3') || ($signature eq '$oldoffice$4'));
|
|
|
|
next unless (length $data[0] == 32);
|
|
next unless (length $data[1] == 32);
|
|
next unless (length $data[2] == 40);
|
|
|
|
$salt = shift @data;
|
|
$param = shift @data;
|
|
$param2 = substr ($signature, 11, 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Django (PBKDF2-SHA256)
|
|
elsif ($mode == 10000)
|
|
{
|
|
next unless (substr ($line, 0, 14) eq 'pbkdf2_sha256$');
|
|
|
|
# get hash
|
|
my $index1 = index ($line, "\$", 14);
|
|
|
|
next if $index1 < 1;
|
|
|
|
my $index2 = index ($line, "\$", $index1 + 1);
|
|
|
|
# iter
|
|
|
|
$iter = substr ($line, 14, $index1 - 14);
|
|
|
|
|
|
# salt
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
# digest
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# SipHash
|
|
elsif ($mode == 10100)
|
|
{
|
|
my $hash;
|
|
|
|
($hash, undef, undef, $salt, $word) = split ":", $line;
|
|
|
|
next unless defined $hash;
|
|
next unless defined $salt;
|
|
next unless defined $word;
|
|
|
|
next unless (length $hash == 16);
|
|
next unless (length $salt == 32);
|
|
|
|
my $hash_in = sprintf ("%s:2:4:%s", $hash, $salt);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Cram MD5
|
|
elsif ($mode == 10200)
|
|
{
|
|
next unless (substr ($line, 0, 10) eq '$cram_md5$');
|
|
|
|
# get hash
|
|
my $index1 = index ($line, "\$", 10);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# challenge
|
|
|
|
my $challengeb64 = substr ($line, 10, $index1 - 10);
|
|
$salt = decode_base64 ($challengeb64);
|
|
|
|
# response
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
my $responseb64 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
my $response = decode_base64 ($responseb64);
|
|
|
|
$param = substr ($response, 0, length ($response) - 32 - 1); # -1 is for space
|
|
|
|
$word = substr ($line, $index2 + 1);
|
|
$hash_in = substr ($line, 0, $index2);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# SAP CODVN H (PWDSALTEDHASH) iSSHA-1
|
|
elsif ($mode == 10300)
|
|
{
|
|
next unless (substr ($line, 0, 10) eq '{x-issha, ');
|
|
|
|
# get iterations
|
|
|
|
my $index1 = index ($line, "}", 10);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$iter = substr ($line, 10, $index1 - 10);
|
|
|
|
$iter = int ($iter);
|
|
|
|
# base64 substring
|
|
|
|
my $base64_encoded = substr ($line, $index1 + 1);
|
|
my $base64_decoded = decode_base64 ($base64_encoded);
|
|
|
|
$salt = substr ($base64_decoded, 20);
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$word = substr ($line, $index2 + 1);
|
|
$hash_in = substr ($line, 0, $index2);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PDF 1.1 - 1.3 (Acrobat 2 - 4)
|
|
elsif ($mode == 10400)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data == 11;
|
|
|
|
next unless (shift @data eq '$pdf$1');
|
|
next unless (shift @data eq '2');
|
|
next unless (shift @data eq '40');
|
|
my $P = shift @data;
|
|
next unless (shift @data eq '0');
|
|
next unless (shift @data eq '16');
|
|
my $id = shift @data;
|
|
next unless (shift @data eq '32');
|
|
my $u = shift @data;
|
|
next unless (shift @data eq '32');
|
|
my $o = shift @data;
|
|
|
|
$salt = $id;
|
|
$param = $u;
|
|
$param2 = $o;
|
|
$param3 = $P;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PDF 1.4 - 1.6 (Acrobat 5 - 8)
|
|
elsif ($mode == 10500)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data == 11;
|
|
|
|
my $V = shift @data; $V = substr ($V, 5, 1);
|
|
my $R = shift @data;
|
|
next unless (shift @data eq '128');
|
|
my $P = shift @data;
|
|
my $enc = shift @data;
|
|
next unless (shift @data eq '16');
|
|
my $id = shift @data;
|
|
next unless (shift @data eq '32');
|
|
my $u = shift @data;
|
|
next unless (shift @data eq '32');
|
|
my $o = shift @data;
|
|
|
|
$salt = $id;
|
|
$param = $u;
|
|
$param2 = $o;
|
|
$param3 = $P;
|
|
$param4 = $V;
|
|
$param5 = $R;
|
|
$param6 = $enc;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PDF 1.7 Level 3 (Acrobat 9)
|
|
elsif ($mode == 10600)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data >= 11;
|
|
|
|
next unless (shift @data eq '$pdf$5');
|
|
next unless (shift @data eq '5');
|
|
next unless (shift @data eq '256');
|
|
next unless (shift @data eq '-1028');
|
|
next unless (shift @data eq '1');
|
|
next unless (shift @data eq '16');
|
|
my $id = shift @data;
|
|
my $rest = join "*", @data;
|
|
|
|
$salt = $id;
|
|
$param = $rest;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PDF 1.7 Level 8 (Acrobat 10 - 11)
|
|
elsif ($mode == 10700)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\*/, $hash_in;
|
|
|
|
next unless scalar @data >= 11;
|
|
|
|
next unless (shift @data eq '$pdf$5');
|
|
next unless (shift @data eq '6');
|
|
next unless (shift @data eq '256');
|
|
next unless (shift @data eq '-1028');
|
|
next unless (shift @data eq '1');
|
|
next unless (shift @data eq '16');
|
|
my $id = shift @data;
|
|
my $rest = join "*", @data;
|
|
|
|
$salt = $id;
|
|
$param = $rest;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PBKDF2-HMAC-SHA256
|
|
elsif ($mode == 10900)
|
|
{
|
|
next unless (substr ($line, 0, 7) eq 'sha256:');
|
|
|
|
# iterations
|
|
my $index1 = index ($line, ":", 7);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$iter = substr ($line, 7, $index1 - 7);
|
|
|
|
# salt
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$salt = decode_base64 ($salt);
|
|
|
|
# end of digest
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# additional param = output len of pbkdf2
|
|
|
|
my $digest64_encoded = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
my $digest = decode_base64 ($digest64_encoded);
|
|
|
|
$param = length ($digest);
|
|
|
|
# word / hash
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PostgreSQL MD5 Authentication
|
|
elsif ($mode == 11100)
|
|
{
|
|
next unless (substr ($line, 0, 10) eq '$postgres$');
|
|
|
|
my $index1 = index ($line, "*", 10);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# the user name
|
|
|
|
$param = substr ($line, 10, $index1 - 10);
|
|
|
|
# get the 4 byte salt
|
|
|
|
my $index2 = index ($line, "*", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
# word / hash
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# MySQL MD5 Authentication
|
|
elsif ($mode == 11200)
|
|
{
|
|
next unless (substr ($line, 0, 9) eq '$mysqlna$');
|
|
|
|
my $index1 = index ($line, "*", 9);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# salt
|
|
|
|
$salt = substr ($line, 9, $index1 - 9);
|
|
|
|
# word / hash
|
|
|
|
$index1 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# WPA-EAPOL-PBKDF2
|
|
elsif ($mode == 2500)
|
|
{
|
|
print "ERROR: verify currently not supported for WPA-EAPOL-PBKDF2 (because of hashcat's output format)\n";
|
|
|
|
exit (1);
|
|
}
|
|
# Bitcoin/Litecoin wallet.dat
|
|
elsif ($mode == 11300)
|
|
{
|
|
print "ERROR: verify currently not supported for Bitcoin/Litecoin wallet.dat because of unknown crypt data\n";
|
|
|
|
exit (1);
|
|
}
|
|
# SIP digest authentication (MD5)
|
|
elsif ($mode == 11400)
|
|
{
|
|
next unless (substr ($line, 0, 6) eq '$sip$*');
|
|
|
|
# URI_server:
|
|
|
|
my $index1 = index ($line, "*", 6);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$param10 = substr ($line, 6, $index1 - 6);
|
|
|
|
next if (length ($param10) > 32);
|
|
|
|
# URI_client:
|
|
|
|
my $index2 = index ($line, "*", $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param11 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
next if (length ($param11) > 32);
|
|
|
|
# user:
|
|
|
|
$index1 = index ($line, "*", $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$param = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
next if (length ($param) > 12);
|
|
|
|
# realm:
|
|
|
|
$index2 = index ($line, "*", $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param2 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
next if (length ($param2) > 20);
|
|
|
|
# method:
|
|
|
|
$index1 = index ($line, "*", $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$param6 = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
next if (length ($param6) > 24);
|
|
|
|
# URI_prefix:
|
|
|
|
$index2 = index ($line, "*", $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param7 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
next if (length ($param7) > 10);
|
|
|
|
# URI_resource:
|
|
|
|
$index1 = index ($line, "*", $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$param8 = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
next if (length ($param8) > 32);
|
|
|
|
# URI_suffix:
|
|
|
|
$index2 = index ($line, "*", $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param9 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
next if (length ($param9) > 32);
|
|
|
|
# nonce:
|
|
|
|
$index1 = index ($line, "*", $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$salt = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
next if (length ($salt) > 34);
|
|
|
|
# nonce_client:
|
|
|
|
$index2 = index ($line, "*", $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param4 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
next if (length ($param4) > 12);
|
|
|
|
# nonce_count:
|
|
|
|
$index1 = index ($line, "*", $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$param3 = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
next if (length ($param3) > 10);
|
|
|
|
# qop:
|
|
|
|
$index2 = index ($line, "*", $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param5 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
next if (length ($param5) > 8);
|
|
|
|
# directive:
|
|
|
|
$index1 = index ($line, "*", $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
my $directive = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
next unless ($directive eq "MD5");
|
|
|
|
# hash_buf:
|
|
|
|
$index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
my $hex_digest = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
next unless (length ($hex_digest) == 32);
|
|
|
|
$word = substr ($line, $index2 + 1);
|
|
$hash_in = substr ($line, 0, $index2);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# 7-Zip
|
|
elsif ($mode == 11600)
|
|
{
|
|
next unless (substr ($line, 0, 4) eq '$7z$');
|
|
|
|
# p
|
|
|
|
my $index1 = index ($line, '$', 4);
|
|
|
|
next if $index1 < 0;
|
|
|
|
my $p = substr ($line, 4, $index1 - 4);
|
|
|
|
next unless ($p eq "0");
|
|
|
|
# num cycle power
|
|
|
|
my $index2 = index ($line, '$', $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$iter = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
# seven zip salt length
|
|
|
|
$index1 = index ($line, '$', $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$param = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
# seven zip salt
|
|
|
|
$index2 = index ($line, '$', $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param2 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
# salt len
|
|
|
|
$index1 = index ($line, '$', $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$param3 = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
# salt
|
|
|
|
$index2 = index ($line, '$', $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$salt = pack ("H*", $salt);
|
|
|
|
# crc / hash
|
|
|
|
$index1 = index ($line, '$', $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
my $crc = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
# ignore this crc, we don't need to pass it to gen_hash ()
|
|
|
|
# data len
|
|
|
|
$index2 = index ($line, '$', $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param4 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
# unpack size
|
|
|
|
$index1 = index ($line, '$', $index2 + 1);
|
|
|
|
next if $index1 < 0;
|
|
|
|
$param5 = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
# data
|
|
|
|
$index2 = index ($line, ':', $index1 + 1);
|
|
|
|
next if $index2 < 0;
|
|
|
|
$param6 = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
$param6 = pack ("H*", $param6);
|
|
|
|
$word = substr ($line, $index2 + 1);
|
|
$hash_in = substr ($line, 0, $index2);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PBKDF2-HMAC-MD5
|
|
elsif ($mode == 11900)
|
|
{
|
|
next unless (substr ($line, 0, 4) eq 'md5:');
|
|
|
|
# iterations
|
|
my $index1 = index ($line, ":", 4);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$iter = substr ($line, 4, $index1 - 4);
|
|
|
|
# salt
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$salt = decode_base64 ($salt);
|
|
|
|
# end of digest
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# additional param = output len of pbkdf2
|
|
|
|
my $digest64_encoded = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
my $digest = decode_base64 ($digest64_encoded);
|
|
|
|
$param = length ($digest);
|
|
|
|
# word / hash
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PBKDF2-HMAC-SHA1
|
|
elsif ($mode == 12000)
|
|
{
|
|
next unless (substr ($line, 0, 5) eq 'sha1:');
|
|
|
|
# iterations
|
|
my $index1 = index ($line, ":", 5);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$iter = substr ($line, 5, $index1 - 5);
|
|
|
|
# salt
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$salt = decode_base64 ($salt);
|
|
|
|
# end of digest
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# additional param = output len of pbkdf2
|
|
|
|
my $digest64_encoded = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
my $digest = decode_base64 ($digest64_encoded);
|
|
|
|
$param = length ($digest);
|
|
|
|
# word / hash
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# PBKDF2-HMAC-SHA512
|
|
elsif ($mode == 12100)
|
|
{
|
|
next unless (substr ($line, 0, 7) eq 'sha512:');
|
|
|
|
# iterations
|
|
my $index1 = index ($line, ":", 7);
|
|
|
|
next if $index1 < 1;
|
|
|
|
$iter = substr ($line, 7, $index1 - 7);
|
|
|
|
# salt
|
|
|
|
my $index2 = index ($line, ":", $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$salt = decode_base64 ($salt);
|
|
|
|
# end of digest
|
|
|
|
$index1 = index ($line, ":", $index2 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# additional param = output len of pbkdf2
|
|
|
|
my $digest64_encoded = substr ($line, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
my $digest = decode_base64 ($digest64_encoded);
|
|
|
|
$param = length ($digest);
|
|
|
|
# word / hash
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# ecryptfs
|
|
elsif ($mode == 12200)
|
|
{
|
|
next unless (substr ($line, 0, 12) eq '$ecryptfs$0$');
|
|
|
|
# check if default salt
|
|
|
|
$param = 1;
|
|
|
|
$param = 0 if (substr ($line, 12, 2) eq '1$');
|
|
|
|
# salt
|
|
|
|
$salt = "";
|
|
|
|
my $index1 = 12;
|
|
|
|
if ($param == 0) # we need to extract the salt
|
|
{
|
|
$index1 = index ($line, '$', $index1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
my $index2 = index ($line, '$', $index1 + 1);
|
|
|
|
next if $index2 < 1;
|
|
|
|
$salt = substr ($line, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$index1 = $index2;
|
|
}
|
|
|
|
$index1 = index ($line, ':', $index1 + 1);
|
|
|
|
next if $index1 < 1;
|
|
|
|
# word / hash
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Oracle T: Type (Oracle 12+)
|
|
elsif ($mode == 12300)
|
|
{
|
|
my $index1 = index ($line, ':');
|
|
|
|
next if ($index1 != 160);
|
|
|
|
# salt
|
|
|
|
$salt = substr ($line, 128, 32);
|
|
|
|
# word / hash
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# BSDi Crypt, Extended DES
|
|
elsif ($mode == 12400)
|
|
{
|
|
next unless (substr ($line, 0, 1) eq '_');
|
|
|
|
my $index1 = index ($line, ':', 20);
|
|
|
|
next if ($index1 != 20);
|
|
|
|
# iter
|
|
|
|
$iter = substr ($line, 1, 4);
|
|
|
|
$iter = base64_to_int24 ($iter);
|
|
|
|
# salt
|
|
|
|
$salt = substr ($line, 5, 4);
|
|
|
|
# word / hash
|
|
|
|
$word = substr ($line, $index1 + 1);
|
|
$hash_in = substr ($line, 0, $index1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Blockchain, My Wallet
|
|
elsif ($mode == 12700)
|
|
{
|
|
my $index1 = index ($line, ':');
|
|
|
|
next if ($index1 < 0);
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
my (undef, $signature, $data_len, $data_buf) = split '\$', $hash_in;
|
|
|
|
next unless ($signature eq "blockchain");
|
|
|
|
next unless (($data_len * 2) == length $data_buf);
|
|
|
|
$salt = substr ($data_buf, 0, 32);
|
|
$param = substr ($data_buf, 32);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 12800)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split /\,/, $hash_in;
|
|
|
|
next unless scalar @data == 4;
|
|
|
|
next unless (shift @data eq 'v1;PPH1_MD4');
|
|
|
|
$salt = shift @data;
|
|
$iter = shift @data;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 12900)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
next unless length $hash_in == 160;
|
|
|
|
$param = substr ($hash_in, 0, 64);
|
|
$salt = substr ($hash_in, 128, 32);
|
|
$iter = 4096;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 13000)
|
|
{
|
|
my $hash_line;
|
|
|
|
($hash_line, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_line;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\$', $hash_line);
|
|
|
|
next unless scalar @data == 8;
|
|
|
|
shift @data;
|
|
|
|
my $signature = shift @data;
|
|
my $salt_len = shift @data;
|
|
my $salt_buf = shift @data;
|
|
my $iterations = shift @data;
|
|
my $iv = shift @data;
|
|
my $pswcheck_len = shift @data;
|
|
my $pswcheck = shift @data;
|
|
|
|
next unless ($signature eq "rar5");
|
|
next unless ($salt_len == 16);
|
|
next unless ($pswcheck_len == 8);
|
|
|
|
$salt = $salt_buf;
|
|
$iter = $iterations;
|
|
$hash_in = $pswcheck;
|
|
$param = $iv;
|
|
|
|
next unless (exists ($db->{$hash_line}) and (! defined ($db->{$hash_line})));
|
|
}
|
|
elsif ($mode == 13100)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\$', $hash_in);
|
|
|
|
next unless scalar @data == 8;
|
|
|
|
shift @data;
|
|
|
|
my $signature = shift @data;
|
|
my $algorithm = shift @data;
|
|
my $user = shift @data;
|
|
$user = substr ($user, 1);
|
|
my $realm = shift @data;
|
|
my $spn = shift @data;
|
|
$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);
|
|
|
|
$salt = $user . '$' . $realm . '$' . $spn . '$';
|
|
|
|
$param = $checksum;
|
|
$param2 = $edata2;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 13200)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless scalar @data == 5;
|
|
|
|
my $signature = shift @data;
|
|
my $version = shift @data;
|
|
my $iteration = shift @data;
|
|
my $mysalt = shift @data;
|
|
my $digest = shift @data;
|
|
|
|
next unless ($signature eq '$axcrypt$');
|
|
next unless (length ($mysalt) == 32);
|
|
next unless (length ($digest) == 48);
|
|
|
|
$salt = $iteration . '*' . $mysalt;
|
|
$param = $digest;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 13300)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\$', $hash_in);
|
|
|
|
next unless scalar @data == 3;
|
|
|
|
shift @data;
|
|
|
|
my $signature = shift @data;
|
|
my $digest = shift @data;
|
|
|
|
$param = length ($digest);
|
|
|
|
next unless ($signature eq 'axcrypt_sha1');
|
|
next unless (($param == 32) || ($param == 40));
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 13400)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
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);
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
next unless (length ($final_random_seed) == 64);
|
|
}
|
|
|
|
my $transf_random_seed = shift @data;
|
|
next unless (length ($transf_random_seed) == 64);
|
|
|
|
my $enc_iv = shift @data;
|
|
next unless (length ($enc_iv) == 32);
|
|
|
|
if ($version == 1)
|
|
{
|
|
my $contents_hash = shift @data;
|
|
next unless (length ($contents_hash) == 64);
|
|
|
|
my $inline_flags = shift @data;
|
|
next unless ($inline_flags == 1);
|
|
|
|
my $contents_len = shift @data;
|
|
|
|
my $contents = shift @data;
|
|
next unless (length ($contents) == $contents_len * 2);
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
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);
|
|
$param = 1; # distinguish between encrypting vs decrypting
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 13600)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless scalar @data == 10;
|
|
|
|
my $tag_start = shift @data;
|
|
my $type = shift @data;
|
|
my $mode = shift @data;
|
|
my $magic = shift @data;
|
|
my $salt = shift @data;
|
|
my $verify_bytes = shift @data;
|
|
my $length = shift @data;
|
|
my $data = shift @data;
|
|
my $auth = shift @data;
|
|
my $tag_end = shift @data;
|
|
|
|
next unless ($tag_start eq '$zip2$');
|
|
next unless ($tag_end eq '$/zip2$');
|
|
|
|
$param = $type;
|
|
$param2 = $mode;
|
|
$param3 = $magic;
|
|
$param4 = $salt;
|
|
$param5 = $length;
|
|
$param6 = $data;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# itunes backup 9/10
|
|
elsif (($mode == 14700) || ($mode == 14800))
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
my $index1 = index ($hash_in, '*');
|
|
|
|
next unless ($index1 == 15);
|
|
|
|
# signature
|
|
|
|
my $signature = substr ($hash_in, 0, $index1);
|
|
|
|
next unless ($signature eq '$itunes_backup$');
|
|
|
|
my $index2 = index ($hash_in, '*', $index1 + 1);
|
|
|
|
next unless ($index2 >= 0);
|
|
|
|
# version
|
|
|
|
my $version = substr ($hash_in, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
if ($mode == 14700)
|
|
{
|
|
next unless ($version eq "9");
|
|
}
|
|
else
|
|
{
|
|
next unless ($version eq "10");
|
|
}
|
|
|
|
$index1 = index ($hash_in, '*', $index2 + 1);
|
|
|
|
next unless ($index1 >= 0);
|
|
|
|
# wpky
|
|
|
|
my $wpky = substr ($hash_in, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
next unless (length ($wpky) == 80);
|
|
|
|
$wpky = pack ("H*", $wpky);
|
|
|
|
$param = $wpky;
|
|
|
|
$index2 = index ($hash_in, '*', $index1 + 1);
|
|
|
|
next unless ($index2 >= 0);
|
|
|
|
# iterations
|
|
|
|
$iter = substr ($hash_in, $index1 + 1, $index2 - $index1 - 1);
|
|
$iter = int ($iter);
|
|
|
|
next unless ($iter > 0);
|
|
|
|
$index1 = index ($hash_in, '*', $index2 + 1);
|
|
|
|
next unless ($index1 >= 0);
|
|
|
|
# salt
|
|
|
|
$salt = substr ($hash_in, $index2 + 1, $index1 - $index2 - 1);
|
|
|
|
next unless (length ($salt) == 40);
|
|
|
|
# dpic and dpsl
|
|
|
|
if ($mode == 14700)
|
|
{
|
|
$index2 = index ($hash_in, '**', $index1 + 1);
|
|
|
|
next unless ($index2 != $index1 + 1);
|
|
}
|
|
else
|
|
{
|
|
$index2 = index ($hash_in, '*', $index1 + 1);
|
|
|
|
next unless ($index2 >= 0);
|
|
|
|
# dpic
|
|
|
|
my $dpic = substr ($hash_in, $index1 + 1, $index2 - $index1 - 1);
|
|
|
|
$dpic = int ($dpic);
|
|
|
|
next unless ($dpic > 0);
|
|
|
|
$param2 = $dpic;
|
|
|
|
# dpsl
|
|
|
|
my $dpsl = substr ($hash_in, $index2 + 1);
|
|
|
|
next unless (length ($dpsl) == 40);
|
|
|
|
$dpsl = pack ("H*", $dpsl);
|
|
|
|
$param3 = $dpsl;
|
|
}
|
|
}
|
|
# base64 and salt embedded SSHA256, salt length = total length - 32
|
|
elsif ($mode == 1411)
|
|
{
|
|
# split hash and plain
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
|
|
# remove signature
|
|
my $plain_base64 = substr ($hash_in, 9);
|
|
|
|
# base64 decode to extract salt
|
|
my $decoded = decode_base64 ($plain_base64);
|
|
|
|
$salt = substr ($decoded, 32);
|
|
}
|
|
# Atlassian (PBKDF2-HMAC-SHA1)
|
|
elsif ($mode == 12001)
|
|
{
|
|
my $index = index ($line, ":");
|
|
|
|
next if $index < 1;
|
|
|
|
$hash_in = substr ($line, 0, $index);
|
|
$word = substr ($line, $index + 1);
|
|
|
|
next unless (substr ($hash_in, 0, 9) eq '{PKCS5S2}');
|
|
|
|
# base64 buf
|
|
|
|
my $base64_buf = substr ($hash_in, 9);
|
|
my $base64_buf_decoded = decode_base64 ($base64_buf);
|
|
|
|
next if (length ($base64_buf_decoded) != (16 + 32));
|
|
|
|
$salt = substr ($base64_buf_decoded, 0, 16);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 15100)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\$', $hash_in);
|
|
|
|
next unless scalar @data == 5;
|
|
|
|
shift @data;
|
|
|
|
my $signature = shift @data;
|
|
|
|
next unless ($signature eq 'sha1');
|
|
|
|
$iter = shift @data;
|
|
$salt = shift @data;
|
|
$param = shift @data;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 15200)
|
|
{
|
|
my $index1 = index ($line, ':');
|
|
|
|
next if ($index1 < 0);
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
my (undef, $signature, $version, $iter_count, $data_len, $data_buf) = split '\$', $hash_in;
|
|
|
|
next unless ($signature eq "blockchain");
|
|
|
|
next unless ($version eq "v2");
|
|
|
|
next unless (($data_len * 2) == length $data_buf);
|
|
|
|
$iter = $iter_count;
|
|
$salt = substr ($data_buf, 0, 32);
|
|
$param = substr ($data_buf, 32);
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 15300 || $mode == 15900)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @tmp_data = split ('\$', $hash_in);
|
|
|
|
my $signature = $tmp_data[1];
|
|
|
|
next unless ($signature eq 'DPAPImk');
|
|
|
|
my @data = split ('\*', $tmp_data[2]);
|
|
|
|
next unless (scalar @data == 9);
|
|
|
|
my $version = shift @data;
|
|
|
|
next unless ($version == 1 || $version == 2);
|
|
|
|
my $context = shift @data;
|
|
|
|
my $SID = shift @data;
|
|
|
|
my $cipher_algorithm = shift @data;
|
|
|
|
my $hash_algorithm = shift @data;
|
|
|
|
my $iteration = shift @data;
|
|
|
|
my $iv = shift @data;
|
|
|
|
my $cipher_len = shift @data;
|
|
|
|
my $cipher = shift @data;
|
|
|
|
next unless (length ($cipher) == $cipher_len);
|
|
|
|
if ($version == 1)
|
|
{
|
|
next unless ($cipher_len == 208);
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
next unless ($cipher_len == 288);
|
|
}
|
|
|
|
$salt = substr ($hash_in, length ('$DPAPImk$'));
|
|
|
|
$param = $cipher;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# chacha
|
|
elsif ($mode == 15400)
|
|
{
|
|
my $index1 = index ($line, ':');
|
|
|
|
next if ($index1 < 0);
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next if (length ($hash_in) < 11);
|
|
|
|
next unless (substr ($hash_in, 0, 11) eq "\$chacha20\$\*");
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless (scalar (@data) == 6);
|
|
|
|
$param = $data[1]; # counter
|
|
$param2 = $data[2]; # offset
|
|
$param3 = $data[3]; # iv
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# jksprivk
|
|
elsif ($mode == 15500)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless scalar @data == 7;
|
|
|
|
my $signature = shift @data;
|
|
|
|
next unless ($signature eq '$jksprivk$');
|
|
|
|
my $checksum = shift @data;
|
|
my $iv = shift @data;
|
|
my $enc_key = shift @data;
|
|
my $DER1 = shift @data;
|
|
my $DER2 = shift @data;
|
|
my $alias = shift @data;
|
|
|
|
$param = $iv;
|
|
$param2 = $enc_key;
|
|
$param3 = $alias;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Ethereum - PBKDF2
|
|
elsif ($mode == 15600)
|
|
{
|
|
my $index1 = index ($line, ':');
|
|
|
|
next if ($index1 < 0);
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next if (length ($hash_in) < 12);
|
|
|
|
next unless (substr ($hash_in, 0, 12) eq "\$ethereum\$p\*");
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless (scalar (@data) == 5);
|
|
|
|
$iter = $data[1];
|
|
|
|
$salt = pack ("H*", $data[2]);
|
|
|
|
$param = pack ("H*", $data[3]); # ciphertext
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Ethereum - Scrypt
|
|
elsif ($mode == 15700)
|
|
{
|
|
my $index1 = index ($line, ':');
|
|
|
|
next if ($index1 < 0);
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next if (length ($hash_in) < 12);
|
|
|
|
next unless (substr ($hash_in, 0, 12) eq "\$ethereum\$s\*");
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless (scalar (@data) == 7);
|
|
|
|
$param = $data[1]; # scrypt_N
|
|
$param2 = $data[2]; # scrypt_r
|
|
$param3 = $data[3]; # scrypt_p
|
|
|
|
$salt = pack ("H*", $data[4]);
|
|
|
|
$param4 = pack ("H*", $data[5]); # ciphertext
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# tacacs-plus
|
|
elsif ($mode == 16100)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\$', $hash_in);
|
|
|
|
next unless scalar @data == 6;
|
|
|
|
shift @data;
|
|
|
|
my $signature = shift @data;
|
|
|
|
next unless ($signature eq "tacacs-plus");
|
|
|
|
my $auth_version = shift @data;
|
|
|
|
next unless ($auth_version eq "0");
|
|
|
|
my $session_id = shift @data;
|
|
my $encrypted_data = shift @data;
|
|
my $sequence = shift @data;
|
|
|
|
$param = $session_id;
|
|
$param2 = $encrypted_data;
|
|
$param3 = $sequence;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# apple secure notes
|
|
elsif ($mode == 16200)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless scalar @data == 5;
|
|
|
|
my $signature = shift @data;
|
|
|
|
next unless ($signature eq '$ASN$');
|
|
|
|
my ($Z_PK, $ZCRYPTOITERATIONCOUNT, $ZCRYPTOSALT, $ZCRYPTOWRAPPEDKEY) = @data;
|
|
|
|
$salt = $ZCRYPTOSALT;
|
|
$iter = $ZCRYPTOITERATIONCOUNT;
|
|
|
|
$param = $Z_PK;
|
|
$param2 = $ZCRYPTOWRAPPEDKEY;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Ethereum Pre-Sale - PBKDF2
|
|
elsif ($mode == 16300)
|
|
{
|
|
my $index1 = index ($line, ':');
|
|
|
|
next if ($index1 < 0);
|
|
|
|
$hash_in = substr ($line, 0, $index1);
|
|
$word = substr ($line, $index1 + 1);
|
|
|
|
next if (length ($hash_in) < 12);
|
|
|
|
next unless (substr ($hash_in, 0, 12) eq "\$ethereum\$w\*");
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless (scalar (@data) == 4);
|
|
|
|
$param = pack ("H*", $data[1]); # encseed
|
|
|
|
$salt = $data[2]; # ethaddr
|
|
|
|
$param2 = pack ("H*", $data[3]); # bpk (the iv + keccak digest)
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# JWT
|
|
elsif ($mode == 16500)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split (/\./, $hash_in);
|
|
|
|
next unless scalar @data == 3;
|
|
|
|
my ($header, $payload, $signature) = @data;
|
|
|
|
$salt = $header . "." . $payload;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Electrum Wallet (Salt-Type 1-3)
|
|
elsif ($mode == 16600)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split (/\*/, $hash_in);
|
|
|
|
next unless scalar @data == 3;
|
|
|
|
my ($mode, $iv, $encrypted) = @data;
|
|
|
|
my (undef, $signature, $salt_type) = split ('\$', $mode);
|
|
|
|
next unless ($signature eq "electrum");
|
|
|
|
$param = $salt_type;
|
|
$param2 = $iv;
|
|
$param3 = $encrypted;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# FileVault 2
|
|
elsif ($mode == 16700)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\$', $hash_in);
|
|
|
|
next unless scalar @data == 7;
|
|
|
|
shift @data;
|
|
|
|
my $signature = shift @data;
|
|
|
|
next unless ($signature eq 'fvde');
|
|
|
|
my $Z_PK = shift @data;
|
|
|
|
next unless ($Z_PK eq '1');
|
|
|
|
my $salt_length = shift @data;
|
|
|
|
next unless ($salt_length eq '16');
|
|
|
|
my ($ZCRYPTOSALT, $ZCRYPTOITERATIONCOUNT, $ZCRYPTOWRAPPEDKEY) = @data;
|
|
|
|
$salt = $ZCRYPTOSALT;
|
|
$iter = $ZCRYPTOITERATIONCOUNT;
|
|
|
|
$param = $Z_PK;
|
|
$param2 = $ZCRYPTOWRAPPEDKEY;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# WPA-PMKID-PMKDF2
|
|
elsif ($mode == 16800)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split (/\*/, $hash_in);
|
|
|
|
next unless scalar @data == 4;
|
|
|
|
my ($pmkid, $macap, $macsta, $essid) = @data;
|
|
|
|
$param = $macap;
|
|
$param2 = $macsta;
|
|
$param3 = $essid;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# Ansible Vault
|
|
elsif ($mode == 16900)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless scalar @data == 5;
|
|
|
|
my ($signature_tmp, $cipher, $salt, $ciphertext, $hmac) = @data;
|
|
|
|
my ($signature, undef) = split ('\$', $signature_tmp);
|
|
|
|
next unless ($signature eq "ansible");
|
|
|
|
$param = $ciphertext;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 18200)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\$', $hash_in);
|
|
|
|
next unless scalar @data == 8;
|
|
|
|
shift @data;
|
|
|
|
my $signature = shift @data;
|
|
my $algorithm = shift @data;
|
|
my $user_principal_name = shift @data;
|
|
my $checksum = shift @data;
|
|
my $edata2 = shift @data;
|
|
|
|
next unless ($signature eq "krb5asrep");
|
|
next unless (length ($checksum) == 32);
|
|
next unless (length ($edata2) >= 64);
|
|
|
|
$salt = $user_principal_name;
|
|
|
|
$param = $checksum;
|
|
$param2 = $edata2;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
# FileVault 2
|
|
elsif ($mode == 18300)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
my @data = split ('\$', $hash_in);
|
|
|
|
next unless scalar @data == 7;
|
|
|
|
shift @data;
|
|
|
|
my $signature = shift @data;
|
|
|
|
next unless ($signature eq 'fvde');
|
|
|
|
my $Z_PK = shift @data;
|
|
|
|
next unless ($Z_PK eq '2');
|
|
|
|
my $salt_length = shift @data;
|
|
|
|
next unless ($salt_length eq '16');
|
|
|
|
my ($ZCRYPTOSALT, $ZCRYPTOITERATIONCOUNT, $ZCRYPTOWRAPPEDKEY) = @data;
|
|
|
|
$salt = $ZCRYPTOSALT;
|
|
$iter = $ZCRYPTOITERATIONCOUNT;
|
|
|
|
$param = $Z_PK;
|
|
$param2 = $ZCRYPTOWRAPPEDKEY;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
elsif ($mode == 18400)
|
|
{
|
|
($hash_in, $word) = split ":", $line;
|
|
|
|
next unless defined $hash_in;
|
|
next unless defined $word;
|
|
|
|
# tokenize
|
|
my @data = split ('\*', $hash_in);
|
|
|
|
next unless scalar @data == 12;
|
|
|
|
my $signature = shift @data;
|
|
my $cipher_type = shift @data;
|
|
my $cs_type = shift @data;
|
|
$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;
|
|
$salt = shift @data;
|
|
my $unused = shift @data;
|
|
my $ciphertext = shift @data;
|
|
|
|
# validate
|
|
next unless ($signature eq '$odf$');
|
|
next unless ($cipher_type eq '1');
|
|
next unless ($cs_type eq '1');
|
|
next unless ($cs_len eq '32');
|
|
next unless ($iv_len eq '16');
|
|
next unless ($salt_len eq '16');
|
|
next unless ($unused eq '0');
|
|
next unless defined $ciphertext;
|
|
|
|
# decrypt
|
|
my $b_iv = pack ("H*", $iv);
|
|
my $b_salt = pack ("H*", $salt);
|
|
my $b_ciphertext = pack ("H*", $ciphertext);
|
|
|
|
my $kdf = Crypt::PBKDF2->new
|
|
(
|
|
hash_class => 'HMACSHA1',
|
|
iterations => $iter,
|
|
output_len => 32
|
|
);
|
|
|
|
my $pass_hash = sha256 ($word);
|
|
my $derived_key = $kdf->PBKDF2 ($b_salt, $pass_hash);
|
|
my $cbc = Crypt::Mode::CBC->new ('AES', 0);
|
|
my $b_plaintext = $cbc->decrypt ($b_ciphertext, $derived_key, $b_iv);
|
|
|
|
my $plaintext = unpack ("H*", $b_plaintext);
|
|
|
|
$param = $iv;
|
|
$param2 = $plaintext;
|
|
|
|
next unless (exists ($db->{$hash_in}) and (! defined ($db->{$hash_in})));
|
|
}
|
|
## STEP 2c: Add your custom salt branch here
|
|
else
|
|
{
|
|
print "ERROR: hash mode is not supported\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
if ($word =~ m/^\$HEX\[[0-9a-fA-F]*\]$/)
|
|
{
|
|
$word = pack ("H*", substr ($word, 5, -1));
|
|
}
|
|
|
|
# finally generate the hash
|
|
|
|
# special case:
|
|
if ($mode == 6800)
|
|
{
|
|
# check both variations
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, 1);
|
|
|
|
$len = length $hash_out; # == length $alternative
|
|
|
|
if (substr ($line, 0, $len) ne $hash_out)
|
|
{
|
|
my $alternative = gen_hash ($mode, $word, $salt, $iter, 2);
|
|
|
|
return unless (substr ($line, 0, $len) eq $alternative);
|
|
}
|
|
}
|
|
elsif ($mode == 8700)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 8900)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param, $param2, $param3);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 9100)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 3300)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 5100)
|
|
{
|
|
# check 3 variants (start, middle, end)
|
|
|
|
my $idx = 0;
|
|
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $idx++);
|
|
|
|
$len = length $hash_out; # == length $alternative
|
|
|
|
if (substr ($line, 0, $len) ne $hash_out)
|
|
{
|
|
my $alternative = gen_hash ($mode, $word, $salt, $iter, $idx++);
|
|
|
|
if (substr ($line, 0, $len) ne $alternative)
|
|
{
|
|
my $alternative = gen_hash ($mode, $word, $salt, $iter, $idx++);
|
|
|
|
return unless (substr ($line, 0, $len) eq $alternative);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 9400)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 50000, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 9500)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 100000, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 9600)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 100000, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 9700)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 9800)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 10200)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 10400)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param, $param2, $param3);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 10500)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param, $param2, $param3, $param4, $param5, $param6);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 10600)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 10700)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 10900)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 11100)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 11400)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2, $param3, $param4, $param5, $param6, $param7, $param8, $param9, $param10, $param11);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 11600)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2, $param3, $param4, $param5, $param6);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 11900)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 12000)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 12100)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 12200)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 12700)
|
|
{
|
|
# this is very special, we can't call gen_hash () because the param part is not always the same
|
|
# we only know that it should contain the letters "guid" at the beginning of the decryted string
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hash_class => 'HMACSHA1',
|
|
iterations => 10,
|
|
output_len => 32
|
|
);
|
|
|
|
my $salt_bin = pack ("H*", $salt);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt_bin, $word);
|
|
|
|
my $cipher = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $salt_bin,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32
|
|
});
|
|
|
|
my $param_bin = pack ("H*", $param);
|
|
|
|
my $decrypted = $cipher->decrypt ($param_bin);
|
|
|
|
my $decrypted_part = substr ($decrypted, 1, 16);
|
|
|
|
return unless ($decrypted_part =~ /"guid"/);
|
|
|
|
$hash_out = $hash_in;
|
|
}
|
|
elsif ($mode == 12900)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 13000)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 13100)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 13200)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 13300)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 13400)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 13600)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, undef, undef, $param, $param2, $param3, $param4, $param5, $param6);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 14700)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 14800)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2, $param3);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 15100)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 15200)
|
|
{
|
|
# this is very special, we can't call gen_hash () because the param part is not always the same
|
|
# we only know that it should contain the letters "guid" at the beginning of the decryted string
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hash_class => 'HMACSHA1',
|
|
iterations => 5000,
|
|
output_len => 32
|
|
);
|
|
|
|
my $salt_bin = pack ("H*", $salt);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt_bin, $word);
|
|
|
|
my $cipher = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $salt_bin,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32
|
|
});
|
|
|
|
my $param_bin = pack ("H*", $param);
|
|
|
|
my $decrypted = $cipher->decrypt ($param_bin);
|
|
|
|
my $decrypted_part = substr ($decrypted, 1, 16);
|
|
|
|
return unless ($decrypted_part =~ /"guid"/);
|
|
|
|
$hash_out = $hash_in;
|
|
}
|
|
elsif ($mode == 15300 || $mode == 15900)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 15400)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param, $param2, $param3);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 15500)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, undef, undef, $param, $param2, $param3);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 15600)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 15700)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param, $param2, $param3, $param4);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 16100)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, undef, 0, $param, $param2, $param3);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 16200)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 16300)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 16600)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, undef, 0, $param, $param2, $param3);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 16700)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 16800)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, undef, 0, $param, $param2, $param3);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 16900)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, 0, $param);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 18200)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 18300)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
elsif ($mode == 18400)
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter, $param, $param2);
|
|
|
|
$len = length $hash_out;
|
|
|
|
return unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
## STEP 2c: Add your custom gen_hash call here
|
|
else
|
|
{
|
|
$hash_out = gen_hash ($mode, $word, $salt, $iter);
|
|
|
|
$len = length $hash_out;
|
|
|
|
# special cases:
|
|
if ($mode == 400)
|
|
{
|
|
# allow $P$ and $H$ for -m 400
|
|
next unless (substr ($line, 3, $len - 3) eq substr ($hash_out, 3));
|
|
}
|
|
elsif ($mode == 5600)
|
|
{
|
|
# hashcat outputs the user name always upper-case, we need
|
|
next unless (substr ($line, 0, $len) eq $hash_out);
|
|
|
|
my $found = 0;
|
|
|
|
my $hash_out_lower = lc ($hash_out);
|
|
|
|
for my $key (keys %{$db})
|
|
{
|
|
if (lc ($key) eq $hash_out_lower)
|
|
{
|
|
$found = 1;
|
|
|
|
last;
|
|
}
|
|
}
|
|
|
|
next unless $found;
|
|
}
|
|
else
|
|
{
|
|
next unless (substr ($line, 0, $len) eq $hash_out);
|
|
}
|
|
}
|
|
|
|
# do not forget "exists ($db->$hash_out)" should be done above!
|
|
$db->{$hash_out} = $word;
|
|
print OUT $line . "\n";
|
|
}
|
|
|
|
close (IN);
|
|
close (OUT);
|
|
}
|
|
|
|
sub passthrough
|
|
{
|
|
my $mode = shift || 0;
|
|
|
|
while (my $word_buf = <>)
|
|
{
|
|
chomp ($word_buf);
|
|
|
|
next if length ($word_buf) > 256;
|
|
|
|
##
|
|
## gen salt
|
|
##
|
|
|
|
my @salt_arr;
|
|
|
|
for (my $i = 0; $i < 256; $i++)
|
|
{
|
|
my $c = get_random_chr (0x30, 0x39);
|
|
|
|
push (@salt_arr, $c);
|
|
}
|
|
|
|
my $salt_buf = join ("", @salt_arr);
|
|
|
|
##
|
|
## gen hash
|
|
##
|
|
|
|
my $tmp_hash;
|
|
|
|
# unsalted
|
|
if (is_in_array ($mode, $COMMON_UNSALTED_MODES)
|
|
|| $mode == 2400 || $mode == 13300)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, "");
|
|
}
|
|
elsif (is_in_array ($mode, $COMMON_DEFAULT_SALTED_MODES)
|
|
|| $mode == 1411 || $mode == 1711 || $mode == 3711 || $mode == 3800
|
|
|| $mode == 4900 || $mode == 8900 || $mode == 10000 || $mode == 10200
|
|
|| $mode == 10900 || $mode == 11900 || $mode == 12000 || $mode == 12100)
|
|
{
|
|
my $salt_len = get_random_num (1, 15);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 11 || $mode == 12)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 21)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 2));
|
|
}
|
|
elsif ($mode == 22)
|
|
{
|
|
my $salt_len = get_random_num (1, 11);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 111 || $mode == 122 || $mode == 131 || $mode == 132
|
|
|| $mode == 400 || $mode == 500 || $mode == 1600 || $mode == 1722
|
|
|| $mode == 1731 || $mode == 1800 || $mode == 6300 || $mode == 7900
|
|
|| $mode == 8100 || $mode == 11100)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 8));
|
|
}
|
|
elsif ($mode == 112)
|
|
{
|
|
next if length ($word_buf) > 30;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 20));
|
|
}
|
|
elsif ($mode == 121)
|
|
{
|
|
my $salt_len = get_random_num (1, 9);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 125)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 8));
|
|
}
|
|
elsif ($mode == 141 || $mode == 1441)
|
|
{
|
|
my $salt_len = get_random_num (1, 15);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 1100)
|
|
{
|
|
my $salt_len = get_random_num (1, 19);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 1500)
|
|
{
|
|
next if length ($word_buf) > 8;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 2));
|
|
}
|
|
elsif ($mode == 2100)
|
|
{
|
|
next if length ($word_buf) > 13;
|
|
|
|
my $salt_len = get_random_num (1, 19);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 2410)
|
|
{
|
|
my $salt_len = get_random_num (1, 4);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 2500)
|
|
{
|
|
next if length ($word_buf) < 8;
|
|
|
|
my $salt_len = get_random_num (0, 32);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 2611)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 3));
|
|
}
|
|
elsif ($mode == 2612)
|
|
{
|
|
my $salt_len = get_random_num (1, 22);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 2711)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 30));
|
|
}
|
|
elsif ($mode == 2811)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 5));
|
|
}
|
|
elsif ($mode == 3000)
|
|
{
|
|
next if length ($word_buf) > 7;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, "");
|
|
}
|
|
elsif ($mode == 3100)
|
|
{
|
|
next if length ($word_buf) > 30;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 10));
|
|
}
|
|
elsif ($mode == 3200 || $mode == 5800 || $mode == 6400 || $mode == 6500 || $mode == 6700 || $mode == 7400 || $mode == 3300 || $mode == 8000 || $mode == 9100 || $mode == 12001 || $mode == 12200 || $mode == 15600)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 16));
|
|
}
|
|
elsif ($mode == 3800 || $mode == 4900)
|
|
{
|
|
my $salt_len = get_random_num (1, 11);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 4520)
|
|
{
|
|
my $salt_len = get_random_num (1, 50);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 4521 || $mode == 15700)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 4522)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 12));
|
|
}
|
|
elsif ($mode == 4800)
|
|
{
|
|
$salt_buf = get_random_md5chap_salt (substr ($salt_buf, 0, 16));
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 5300 || $mode == 5400)
|
|
{
|
|
$salt_buf = get_random_ike_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 5500)
|
|
{
|
|
my $user_len = get_random_num (0, 15);
|
|
my $domain_len = get_random_num (0, 15);
|
|
|
|
$salt_buf = get_random_netntlmv1_salt ($user_len, $domain_len);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 5600)
|
|
{
|
|
my $user_len = get_random_num (0, 15);
|
|
my $domain_len = get_random_num (0, 15);
|
|
|
|
$salt_buf = get_random_netntlmv2_salt ($user_len, $domain_len);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 6600)
|
|
{
|
|
$salt_buf = get_random_agilekeychain_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 6800)
|
|
{
|
|
my $email_len = get_random_num (1, 15);
|
|
|
|
my $email = "";
|
|
|
|
for (my $i = 0; $i < $email_len; $i++)
|
|
{
|
|
$email .= get_random_chr (0x61, 0x7a);
|
|
}
|
|
|
|
$email .= '@trash-mail.com';
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $email);
|
|
}
|
|
elsif ($mode == 7000)
|
|
{
|
|
next if length ($word_buf) > 19;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 24));
|
|
}
|
|
elsif ($mode == 7100)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 64));
|
|
}
|
|
elsif ($mode == 7200)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 128));
|
|
}
|
|
elsif ($mode == 7300)
|
|
{
|
|
my $salt_len = get_random_num (32, 256);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 7500)
|
|
{
|
|
$salt_buf = get_random_kerberos5_salt (substr ($salt_buf, 0, 16));
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 7700 || $mode == 7701)
|
|
{
|
|
next if length ($word_buf) > 8;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 12));
|
|
}
|
|
elsif ($mode == 7800 || $mode == 7801)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 12));
|
|
}
|
|
elsif ($mode == 8200)
|
|
{
|
|
$salt_buf = get_random_cloudkeychain_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 8300)
|
|
{
|
|
$salt_buf = get_random_dnssec_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 8400 || $mode == 11200 || $mode == 16300)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 40));
|
|
}
|
|
elsif ($mode == 8500)
|
|
{
|
|
next if length ($word_buf) > 8;
|
|
|
|
my $salt_len = get_random_num (1, 9);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 8600)
|
|
{
|
|
next if length ($word_buf) > 16;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, "");
|
|
}
|
|
elsif ($mode == 8700)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 5));
|
|
}
|
|
elsif ($mode == 9200 || $mode == 9300)
|
|
{
|
|
my $salt_len = 14;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 9400 || $mode == 9500 || $mode == 9600)
|
|
{
|
|
next if length ($word_buf) > 19;
|
|
|
|
my $salt_len = 32;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 9700 || $mode == 9800)
|
|
{
|
|
next if length ($word_buf) > 15;
|
|
|
|
my $salt_len = 32;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 10100)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 10300)
|
|
{
|
|
my $salt_len = get_random_num (4, 15);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 10400)
|
|
{
|
|
next if length ($word_buf) > 31;
|
|
|
|
my $salt_len = 32;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 10500)
|
|
{
|
|
next if length ($word_buf) > 15;
|
|
|
|
my $salt_len = 32;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 10600)
|
|
{
|
|
next if length ($word_buf) > 31;
|
|
|
|
my $salt_len = 32;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 10700)
|
|
{
|
|
next if length ($word_buf) > 15;
|
|
|
|
my $salt_len = 32;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 11000)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 56));
|
|
}
|
|
elsif ($mode == 11300)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 16));
|
|
}
|
|
elsif ($mode == 11400)
|
|
{
|
|
next if length ($word_buf) > 24;
|
|
|
|
my $salt_len = get_random_num (1, 15);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 11600)
|
|
{
|
|
my $salt_len = get_random_num (0, 16);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, $salt_len));
|
|
}
|
|
elsif ($mode == 12300)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 12400)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 4));
|
|
}
|
|
elsif ($mode == 12600 || $mode == 15000)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 64));
|
|
}
|
|
elsif ($mode == 12700)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 12800)
|
|
{
|
|
next if length ($word_buf) > 24;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 20));
|
|
}
|
|
elsif ($mode == 12900)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 13000)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 13100)
|
|
{
|
|
$salt_buf = get_random_kerberos5_tgs_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 13200)
|
|
{
|
|
$salt_buf = get_random_axcrypt_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 13400)
|
|
{
|
|
$salt_buf = get_random_keepass_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 13500)
|
|
{
|
|
$salt_buf = get_pstoken_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 13600)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 13800)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 256));
|
|
}
|
|
elsif ($mode == 13900)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 9));
|
|
}
|
|
elsif ($mode == 14000)
|
|
{
|
|
next if length ($word_buf) != 8;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 16));
|
|
}
|
|
elsif ($mode == 14100)
|
|
{
|
|
next if length ($word_buf) != 24;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 16));
|
|
}
|
|
elsif ($mode == 14400)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 20));
|
|
}
|
|
elsif (($mode == 14700) || ($mode == 14800))
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 40));
|
|
}
|
|
elsif ($mode == 14900)
|
|
{
|
|
next if length ($word_buf) != 10;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 8));
|
|
}
|
|
elsif ($mode == 15100)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 8));
|
|
}
|
|
elsif ($mode == 15200)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 15300 || $mode == 15900)
|
|
{
|
|
my $version = 2;
|
|
|
|
if ($mode == 15300)
|
|
{
|
|
$version = 1;
|
|
}
|
|
|
|
$salt_buf = get_random_dpapimk_salt ($version);
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 15400)
|
|
{
|
|
next if length ($word_buf) != 32;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, "");
|
|
}
|
|
elsif ($mode == 15500)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 40));
|
|
}
|
|
elsif ($mode == 16000)
|
|
{
|
|
next if length ($word_buf) > 8;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, "");
|
|
}
|
|
elsif ($mode == 16100)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, undef);
|
|
}
|
|
elsif ($mode == 16200)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 16500)
|
|
{
|
|
$salt_buf = get_random_jwt_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 16600)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 16700)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 16800)
|
|
{
|
|
next if length ($word_buf) < 8;
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 16900)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 64));
|
|
}
|
|
elsif ($mode == 18200)
|
|
{
|
|
$salt_buf = get_random_kerberos5_as_rep_salt ();
|
|
|
|
$tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 18300)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 18400)
|
|
{
|
|
$tmp_hash = gen_hash ($mode, $word_buf, substr ($salt_buf, 0, 32));
|
|
}
|
|
## STEP 2c: Add your custom salt branch here
|
|
else
|
|
{
|
|
print "ERROR: Unsupported hash type\n";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
print $tmp_hash, "\n";
|
|
}
|
|
}
|
|
|
|
sub single
|
|
{
|
|
my $mode = shift;
|
|
|
|
if (defined $mode)
|
|
{
|
|
@{$MODES} = ($mode);
|
|
}
|
|
|
|
for (my $j = 0; $j < scalar @{$MODES}; $j++)
|
|
{
|
|
my $mode = $MODES->[$j];
|
|
|
|
if (is_in_array ($mode, $COMMON_UNSALTED_MODES)
|
|
|| $mode == 5300 || $mode == 5400 || $mode == 6600
|
|
|| $mode == 8200 || $mode == 8300 || $mode == 13300)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 0);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 0);
|
|
}
|
|
}
|
|
}
|
|
elsif (is_in_array ($mode, $COMMON_DEFAULT_SALTED_MODES)
|
|
|| $mode == 121 || $mode == 1411 || $mode == 1711 || $mode == 3711
|
|
|| $mode == 8900 || $mode == 10000 || $mode == 10200 || $mode == 10900
|
|
|| $mode == 11900 || $mode == 12000 || $mode == 12100 || $mode == 16500)
|
|
{
|
|
my $salt_len = get_random_num (1, 15);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 11 || $mode == 12)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 21 || $mode == 22)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 2);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 2);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 111 || $mode == 122 || $mode == 125 || $mode == 131
|
|
|| $mode == 132 || $mode == 400 || $mode == 500 || $mode == 1600
|
|
|| $mode == 1722 || $mode == 1731 || $mode == 6300 || $mode == 7900
|
|
|| $mode == 8100 || $mode == 11100)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 8);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 8);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 112)
|
|
{
|
|
for (my $i = 1; $i < 31; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 20);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 20);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 141 || $mode == 3300 || $mode == 1441 || $mode == 1800
|
|
|| $mode == 3200 || $mode == 4800 || $mode == 6400 || $mode == 6500
|
|
|| $mode == 6700 || $mode == 7400 || $mode == 8000 || $mode == 9100
|
|
|| $mode == 12001 || $mode == 12200 || $mode == 15600)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 1100)
|
|
{
|
|
my $salt_len = get_random_num (1, 19);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 1500)
|
|
{
|
|
for (my $i = 1; $i < 9; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 2);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 2);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 2100)
|
|
{
|
|
my $salt_len = get_random_num (1, 19);
|
|
|
|
for (my $i = 1; $i < 13; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 2400)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 0);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 0);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 2410)
|
|
{
|
|
my $salt_len = get_random_num (3, 4);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 2500)
|
|
{
|
|
my $salt_len = get_random_num (0, 32);
|
|
|
|
for (my $i = 8; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
if ($len < 8)
|
|
{
|
|
$len += 7;
|
|
}
|
|
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 2611)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 3);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 3);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 2612)
|
|
{
|
|
my $salt_len = get_random_num (1, 22);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 2711)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 30);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 30);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 2811)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 5);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 5);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 3000)
|
|
{
|
|
for (my $i = 1; $i < 8; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 0);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 0);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 3100)
|
|
{
|
|
for (my $i = 1; $i < 31; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 10);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 10);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 3800 || $mode == 4900)
|
|
{
|
|
my $salt_len = get_random_num (1, 11);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 4520)
|
|
{
|
|
my $salt_len = get_random_num (1, 50);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 4521 || $mode == 15700)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 4522)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 12);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 12);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 5500 || $mode == 5600)
|
|
{
|
|
my $salt_len;
|
|
|
|
for (my $i = 1; $i < 27; $i++)
|
|
{
|
|
$salt_len = get_random_num (1, 15);
|
|
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 5800)
|
|
{
|
|
for (my $i = 1; $i < 14; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 6800)
|
|
{
|
|
my $salt_len = get_random_num (8, 25);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 7000)
|
|
{
|
|
for (my $i = 1; $i < 19; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 24);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 24);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 7100)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 64);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 64);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 7200)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 128);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 128);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 7300)
|
|
{
|
|
my $salt_len = get_random_num (32, 255);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 7500)
|
|
{
|
|
for (my $i = 1; $i < 27; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 7700 || $mode == 7701)
|
|
{
|
|
my $salt_len = get_random_num (1, 12);
|
|
|
|
for (my $i = 1; $i < 9; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 7800 || $mode == 7801)
|
|
{
|
|
my $salt_len = get_random_num (1, 12);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 8400 || $mode == 11200 || $mode == 14700 || $mode == 14800 || $mode == 16300)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 40);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 40);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 8500)
|
|
{
|
|
my $salt_len = get_random_num (1, 8);
|
|
|
|
for (my $i = 1; $i < 9; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 8600)
|
|
{
|
|
for (my $i = 1; $i < 17; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 0);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 0);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 8700)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 5);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 5);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 9200 || $mode == 9300)
|
|
{
|
|
my $salt_len = 14;
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 9400 || $mode == 9500 || $mode == 9600)
|
|
{
|
|
my $salt_len = 32;
|
|
|
|
for (my $i = 1; $i < 20; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 9700 || $mode == 9800)
|
|
{
|
|
my $salt_len = 32;
|
|
|
|
for (my $i = 1; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 10100)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 10300)
|
|
{
|
|
my $salt_len = get_random_num (4, 15);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 10400 || $mode == 10600)
|
|
{
|
|
my $salt_len = 32;
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 10500 || $mode == 10700)
|
|
{
|
|
my $salt_len = 32;
|
|
|
|
for (my $i = 1; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 11000)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 56);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 56);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 11300)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 11400)
|
|
{
|
|
for (my $i = 1; $i < 24; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 11600)
|
|
{
|
|
my $salt_len = get_random_num (0, 16);
|
|
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 12300)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 12400)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 4);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 4);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 12600 || $mode == 15000)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 64);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 64);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 12700)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 12800)
|
|
{
|
|
for (my $i = 1; $i < 25; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 20);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 20);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 12900)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 13000)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 13100)
|
|
{
|
|
for (my $i = 1; $i < 27; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 13200)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 13400)
|
|
{
|
|
for (my $i = 1; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 13500)
|
|
{
|
|
for (my $i = 1; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 13600)
|
|
{
|
|
for (my $i = 1; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 13800)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 256);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 256);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 13900)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 9);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 9);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 14000)
|
|
{
|
|
rnd ($mode, 8, 16);
|
|
}
|
|
elsif ($mode == 14100)
|
|
{
|
|
rnd ($mode, 24, 16);
|
|
}
|
|
elsif ($mode == 14400)
|
|
{
|
|
for (my $i = 1; $i < 24; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 20);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 20);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 14900)
|
|
{
|
|
rnd ($mode, 10, 8);
|
|
}
|
|
elsif ($mode == 15100)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 8);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 8);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 15200)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 15300 || $mode == 15900)
|
|
{
|
|
for (my $i = 1; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 15400)
|
|
{
|
|
rnd ($mode, 32, 0);
|
|
}
|
|
elsif ($mode == 15500)
|
|
{
|
|
for (my $i = 1; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 40);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 40);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 16000)
|
|
{
|
|
for (my $i = 1; $i < 9; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 0);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 0);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 16100)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 0);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 0);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 16200)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 16600)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 16700)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 16800)
|
|
{
|
|
my $salt_len = get_random_num (0, 32);
|
|
|
|
for (my $i = 8; $i < 16; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
if ($len < 8)
|
|
{
|
|
$len += 7;
|
|
}
|
|
|
|
rnd ($mode, $len, $salt_len);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, $salt_len);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 16900)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 64);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 64);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 18200)
|
|
{
|
|
for (my $i = 1; $i < 27; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 16);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 16);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 18300)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
elsif ($mode == 18400)
|
|
{
|
|
for (my $i = 1; $i < 32; $i++)
|
|
{
|
|
if ($len != 0)
|
|
{
|
|
rnd ($mode, $len, 32);
|
|
}
|
|
else
|
|
{
|
|
rnd ($mode, $i, 32);
|
|
}
|
|
}
|
|
}
|
|
## STEP 2c: Add your custom salt branch here
|
|
}
|
|
}
|
|
|
|
exit;
|
|
|
|
## STEP 3: Implement hash generation for your hash mode here.
|
|
#
|
|
# For an example of how to use python, see mode 11700.
|
|
# For an example of how to use PHP, see mode 11900.
|
|
#
|
|
# Don't forget to add the modules you depend on to the
|
|
# installation script.
|
|
#
|
|
##
|
|
sub gen_hash
|
|
{
|
|
my $mode = shift;
|
|
|
|
my $word_buf = shift;
|
|
|
|
my $salt_buf = shift;
|
|
|
|
my $iter = shift;
|
|
|
|
my $additional_param = shift;
|
|
|
|
my $additional_param2 = shift;
|
|
|
|
my $additional_param3 = shift;
|
|
|
|
my $additional_param4 = shift;
|
|
|
|
my $additional_param5 = shift;
|
|
|
|
my $additional_param6 = shift;
|
|
|
|
my $additional_param7 = shift;
|
|
|
|
my $additional_param8 = shift;
|
|
|
|
my $additional_param9 = shift;
|
|
|
|
my $additional_param10 = shift;
|
|
|
|
my $additional_param11 = shift;
|
|
|
|
##
|
|
## gen hash
|
|
##
|
|
|
|
my $tmp_hash;
|
|
|
|
my $hash_buf;
|
|
|
|
if ($mode == 0)
|
|
{
|
|
$hash_buf = md5_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 10)
|
|
{
|
|
$hash_buf = md5_hex ($word_buf . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 11)
|
|
{
|
|
$hash_buf = md5_hex ($word_buf . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 12)
|
|
{
|
|
$hash_buf = md5_hex ($word_buf . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 20)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 21)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 22)
|
|
{
|
|
my $itoa64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
my $salt_suffix = "Administration Tools";
|
|
|
|
my $pass = sprintf ("%s:%s:%s", $salt_buf, $salt_suffix, $word_buf);
|
|
|
|
$hash_buf = md5 ($pass);
|
|
|
|
my $res = "";
|
|
|
|
for (my $pos = 0; $pos < 16; $pos += 2)
|
|
{
|
|
my $octet1 = ord (substr ($hash_buf, $pos + 0, 1));
|
|
my $octet2 = ord (substr ($hash_buf, $pos + 1, 1));
|
|
|
|
my $num = ($octet1 <<8 & 0xff00) | ($octet2 & 0xff);
|
|
|
|
my $idx1 = $num >> 12 & 0x0f;
|
|
my $idx2 = $num >> 6 & 0x3f;
|
|
my $idx3 = $num & 0x3f;
|
|
|
|
$res = $res . substr ($itoa64, $idx1, 1) . substr ($itoa64, $idx2, 1) . substr ($itoa64, $idx3, 1);
|
|
}
|
|
|
|
my $obfuscate_str = "nrcstn";
|
|
my @obfuscate_pos = (0, 6, 12, 17, 23, 29);
|
|
|
|
foreach my $pos (keys @obfuscate_pos)
|
|
{
|
|
my $idx = $obfuscate_pos[$pos];
|
|
my $before = substr ($res, 0, $idx);
|
|
my $char = substr ($obfuscate_str, $pos, 1);
|
|
my $after = substr ($res, $idx);
|
|
|
|
$res = sprintf ("%s%s%s", $before, $char, $after);
|
|
}
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $res, $salt_buf);
|
|
}
|
|
elsif ($mode == 23)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . "\nskyper\n" . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 30)
|
|
{
|
|
$hash_buf = md5_hex (encode ("UTF-16LE", $word_buf) . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 40)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 50)
|
|
{
|
|
$hash_buf = hmac_hex ($salt_buf, $word_buf, \&md5, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 60)
|
|
{
|
|
$hash_buf = hmac_hex ($word_buf, $salt_buf, \&md5, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 100)
|
|
{
|
|
$hash_buf = sha1_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 101)
|
|
{
|
|
$hash_buf = sha1 ($word_buf);
|
|
|
|
my $base64_buf = encode_base64 ($hash_buf, "");
|
|
|
|
$tmp_hash = sprintf ("{SHA}%s", $base64_buf);
|
|
}
|
|
elsif ($mode == 110)
|
|
{
|
|
$hash_buf = sha1_hex ($word_buf . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 111)
|
|
{
|
|
$hash_buf = sha1 ($word_buf . $salt_buf);
|
|
|
|
my $base64_buf = encode_base64 ($hash_buf . $salt_buf, "");
|
|
|
|
$tmp_hash = sprintf ("{SSHA}%s", $base64_buf);
|
|
}
|
|
elsif ($mode == 112)
|
|
{
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
$hash_buf = sha1_hex ($word_buf . $salt_buf_bin);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 120)
|
|
{
|
|
$hash_buf = sha1_hex ($salt_buf . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 121)
|
|
{
|
|
$hash_buf = sha1_hex (lc ($salt_buf) . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 122)
|
|
{
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
$hash_buf = sha1_hex ($salt_buf_bin . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 125)
|
|
{
|
|
my $signature = "01";
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf . $signature);
|
|
|
|
$hash_buf = sha1_hex ($salt_buf_bin . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s%s%s", $salt_buf, $signature, $hash_buf);
|
|
}
|
|
elsif ($mode == 130)
|
|
{
|
|
$hash_buf = sha1_hex (encode ("UTF-16LE", $word_buf) . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 131)
|
|
{
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
$hash_buf = sha1_hex (encode ("UTF-16LE", uc ($word_buf)) . $salt_buf_bin);
|
|
|
|
$tmp_hash = sprintf ("0x0100%s%s%s", $salt_buf, "0" x 40, $hash_buf);
|
|
}
|
|
elsif ($mode == 132)
|
|
{
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
$hash_buf = sha1_hex (encode ("UTF-16LE", $word_buf) . $salt_buf_bin);
|
|
|
|
$tmp_hash = sprintf ("0x0100%s%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 133)
|
|
{
|
|
$hash_buf = sha1 (encode ("UTF-16LE", $word_buf));
|
|
|
|
$hash_buf = encode_base64 ($hash_buf, "");
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 140)
|
|
{
|
|
$hash_buf = sha1_hex ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 141)
|
|
{
|
|
$hash_buf = sha1 ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
my $base64_salt_buf = encode_base64 ($salt_buf, "");
|
|
my $base64_hash_buf = encode_base64 ($hash_buf, "");
|
|
|
|
$base64_hash_buf = substr ($base64_hash_buf, 0, 27);
|
|
|
|
$tmp_hash = sprintf ("\$episerver\$*0*%s*%s", $base64_salt_buf, $base64_hash_buf);
|
|
}
|
|
elsif ($mode == 150)
|
|
{
|
|
$hash_buf = hmac_hex ($salt_buf, $word_buf, \&sha1, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 160)
|
|
{
|
|
$hash_buf = hmac_hex ($word_buf, $salt_buf, \&sha1, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 200)
|
|
{
|
|
my $ppr = Authen::Passphrase::MySQL323->new (passphrase => $word_buf);
|
|
|
|
$hash_buf = $ppr->hash_hex;
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 300)
|
|
{
|
|
$hash_buf = substr (password41 ($word_buf), 1);
|
|
|
|
$hash_buf = lc ($hash_buf); # useful for 'not matched' check only
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 400)
|
|
{
|
|
my $cost = 11;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$cost = $iter;
|
|
}
|
|
|
|
my $ppr = Authen::Passphrase::PHPass->new
|
|
(
|
|
cost => $cost,
|
|
salt => $salt_buf,
|
|
passphrase => $word_buf,
|
|
);
|
|
|
|
$hash_buf = $ppr->as_rfc2307;
|
|
|
|
$tmp_hash = sprintf ("%s", substr ($hash_buf, 7));
|
|
}
|
|
elsif ($mode == 500)
|
|
{
|
|
my $iterations = 1000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
if ($iter > 0)
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
}
|
|
|
|
$hash_buf = md5_crypt ('$1$', $iterations, $word_buf, $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 600)
|
|
{
|
|
$hash_buf = lc blake2b_hex ($word_buf);
|
|
$tmp_hash = sprintf ("\$BLAKE2\$" . $hash_buf);
|
|
}
|
|
elsif ($mode == 900)
|
|
{
|
|
$hash_buf = md4_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 1000)
|
|
{
|
|
$hash_buf = md4_hex (encode ("UTF-16LE", $word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 1100)
|
|
{
|
|
$hash_buf = md4_hex (md4 (encode ("UTF-16LE", $word_buf)) . encode ("UTF-16LE", lc ($salt_buf)));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1300)
|
|
{
|
|
$hash_buf = sha224_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 1400)
|
|
{
|
|
$hash_buf = sha256_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 1410)
|
|
{
|
|
$hash_buf = sha256_hex ($word_buf . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1411)
|
|
{
|
|
$hash_buf = sha256_hex ($word_buf . $salt_buf);
|
|
|
|
my $base64_buf = encode_base64 (pack ("H*", $hash_buf) . $salt_buf, "");
|
|
|
|
$tmp_hash = sprintf ("{SSHA256}%s", $base64_buf);
|
|
}
|
|
elsif ($mode == 1420)
|
|
{
|
|
$hash_buf = sha256_hex ($salt_buf . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1430)
|
|
{
|
|
$hash_buf = sha256_hex (encode ("UTF-16LE", $word_buf) . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1440)
|
|
{
|
|
$hash_buf = sha256_hex ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1441)
|
|
{
|
|
$hash_buf = sha256 ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
my $base64_salt_buf = encode_base64 ($salt_buf, "");
|
|
my $base64_hash_buf = encode_base64 ($hash_buf, "");
|
|
|
|
$base64_hash_buf = substr ($base64_hash_buf, 0, 43);
|
|
|
|
$tmp_hash = sprintf ("\$episerver\$*1*%s*%s", $base64_salt_buf, $base64_hash_buf);
|
|
}
|
|
elsif ($mode == 1450)
|
|
{
|
|
$hash_buf = hmac_hex ($salt_buf, $word_buf, \&sha256, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1460)
|
|
{
|
|
$hash_buf = hmac_hex ($word_buf, $salt_buf, \&sha256, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1500)
|
|
{
|
|
$hash_buf = crypt ($word_buf, $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 1600)
|
|
{
|
|
my $iterations = 1000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
if ($iter > 0)
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
}
|
|
|
|
$hash_buf = md5_crypt ('$apr1$', $iterations, $word_buf, $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 1700)
|
|
{
|
|
$hash_buf = sha512_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 1710 || $mode == 15000)
|
|
{
|
|
$hash_buf = sha512_hex ($word_buf . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1711)
|
|
{
|
|
$hash_buf = sha512_hex ($word_buf . $salt_buf);
|
|
|
|
my $base64_buf = encode_base64 (pack ("H*", $hash_buf) . $salt_buf, "");
|
|
|
|
$tmp_hash = sprintf ("{SSHA512}%s", $base64_buf);
|
|
}
|
|
elsif ($mode == 1720)
|
|
{
|
|
$hash_buf = sha512_hex ($salt_buf . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1730)
|
|
{
|
|
$hash_buf = sha512_hex (encode ("UTF-16LE", $word_buf) . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1740)
|
|
{
|
|
$hash_buf = sha512_hex ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1722)
|
|
{
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
$hash_buf = sha512_hex ($salt_buf_bin . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 1731)
|
|
{
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
$hash_buf = sha512_hex (encode ("UTF-16LE", $word_buf) . $salt_buf_bin);
|
|
|
|
$tmp_hash = sprintf ("0x0200%s%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 1750)
|
|
{
|
|
$hash_buf = hmac_hex ($salt_buf, $word_buf, \&sha512, 128);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1760)
|
|
{
|
|
$hash_buf = hmac_hex ($word_buf, $salt_buf, \&sha512, 128);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 1800)
|
|
{
|
|
my $iterations = 5000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
if ($iter > 0)
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
}
|
|
|
|
$hash_buf = sha512_crypt ($iterations, $word_buf, $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 2100)
|
|
{
|
|
my $iterations = 10240;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $salt = encode ("UTF-16LE", lc ($salt_buf));
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hash_class => 'HMACSHA1',
|
|
iterations => $iterations,
|
|
output_len => 16,
|
|
salt_len => length ($salt),
|
|
);
|
|
|
|
$hash_buf = unpack ("H*", $pbkdf2->PBKDF2 ($salt, md4 (md4 (encode ("UTF-16LE", $word_buf)) . $salt)));
|
|
|
|
$tmp_hash = sprintf ("\$DCC2\$%i#%s#%s", $iterations, $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 2400)
|
|
{
|
|
my $word_len = length ($word_buf);
|
|
|
|
my $pad_len = ceil ($word_len / 16) * 16;
|
|
|
|
my $hash_buf = Digest::MD5::md5 ($word_buf . "\0" x ($pad_len - $word_len));
|
|
|
|
$tmp_hash = sprintf ("%s", pseudo_base64 ($hash_buf));
|
|
}
|
|
elsif ($mode == 2410)
|
|
{
|
|
my $word_salt_buf = $word_buf . $salt_buf;
|
|
|
|
my $word_salt_len = length ($word_salt_buf);
|
|
|
|
my $pad_len = ceil ($word_salt_len / 16) * 16;
|
|
|
|
my $hash_buf = Digest::MD5::md5 ($word_buf . $salt_buf . "\0" x ($pad_len - $word_salt_len));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", pseudo_base64 ($hash_buf), $salt_buf);
|
|
}
|
|
elsif ($mode == 2500)
|
|
{
|
|
my ($bssid, $stmac, $snonce, $anonce, $eapol, $keyver, $eapol_len, $essid_len);
|
|
|
|
if (! defined ($additional_param))
|
|
{
|
|
# random stuff
|
|
|
|
$bssid = randbytes (6);
|
|
$stmac = randbytes (6);
|
|
$snonce = randbytes (32);
|
|
$anonce = randbytes (32);
|
|
|
|
$keyver = get_random_num (1, 4); # 1, 2 or 3
|
|
|
|
# eapol:
|
|
# should be "validly" generated, but in theory could be anything for us also:
|
|
# $eapol = "\x00" x 121; # works too, but let's generate it correctly
|
|
|
|
$eapol = gen_random_wpa_eapol ($keyver, $snonce);
|
|
}
|
|
else
|
|
{
|
|
$bssid = $additional_param;
|
|
$stmac = $additional_param2;
|
|
$snonce = $additional_param3;
|
|
$anonce = $additional_param4;
|
|
$keyver = $additional_param5;
|
|
$eapol = $additional_param6;
|
|
}
|
|
|
|
$eapol_len = length ($eapol);
|
|
|
|
# constants
|
|
|
|
my $iterations = 4096;
|
|
|
|
#
|
|
# START
|
|
#
|
|
|
|
# generate the Pairwise Master Key (PMK)
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hash_class => 'HMACSHA1',
|
|
iterations => $iterations,
|
|
output_len => 32,
|
|
);
|
|
|
|
my $pmk = $pbkdf2->PBKDF2 ($salt_buf, $word_buf);
|
|
|
|
# Pairwise Transient Key (PTK) transformation
|
|
|
|
my $ptk = wpa_prf_512 ($keyver, $pmk, $stmac, $bssid, $snonce, $anonce);
|
|
|
|
# generate the Message Integrity Code (MIC)
|
|
|
|
my $mic = "";
|
|
|
|
if ($keyver == 1) # WPA1 => MD5
|
|
{
|
|
$mic = hmac ($eapol, $ptk, \&md5);
|
|
}
|
|
elsif ($keyver == 2) # WPA2 => SHA1
|
|
{
|
|
$mic = hmac ($eapol, $ptk, \&sha1);
|
|
}
|
|
elsif ($keyver == 3) # WPA2 => SHA256 + AES-CMAC
|
|
{
|
|
my $omac1 = Digest::CMAC->new ($ptk, 'Crypt::Rijndael');
|
|
|
|
$omac1->add ($eapol);
|
|
|
|
$mic = $omac1->digest;
|
|
}
|
|
|
|
$mic = substr ($mic, 0, 16);
|
|
|
|
#
|
|
# format the binary output
|
|
#
|
|
|
|
my $HCCAPX_VERSION = 4;
|
|
|
|
# signature
|
|
$hash_buf = "HCPX";
|
|
|
|
# format version
|
|
$hash_buf .= pack ("L<", $HCCAPX_VERSION);
|
|
|
|
# authenticated
|
|
$hash_buf .= pack ("C", 0);
|
|
|
|
# essid length
|
|
$essid_len = length ($salt_buf);
|
|
$hash_buf .= pack ("C", $essid_len);
|
|
|
|
# essid (NULL-padded up to the first 32 bytes)
|
|
$hash_buf .= $salt_buf;
|
|
$hash_buf .= "\x00" x (32 - $essid_len);
|
|
|
|
# key version
|
|
$hash_buf .= pack ("C", $keyver);
|
|
|
|
# key mic
|
|
$hash_buf .= $mic;
|
|
|
|
# access point MAC
|
|
$hash_buf .= $bssid;
|
|
|
|
# access point nonce
|
|
$hash_buf .= $snonce;
|
|
|
|
# client MAC
|
|
$hash_buf .= $stmac;
|
|
|
|
# client nonce
|
|
$hash_buf .= $anonce;
|
|
|
|
# eapol length
|
|
$hash_buf .= pack ("S<", $eapol_len);
|
|
|
|
# eapol
|
|
$hash_buf .= $eapol;
|
|
$hash_buf .= "\x00" x (256 - $eapol_len);
|
|
|
|
# base64 encode the output
|
|
$tmp_hash = encode_base64 ($hash_buf, "");
|
|
}
|
|
elsif ($mode == 2600)
|
|
{
|
|
$hash_buf = md5_hex (md5_hex ($word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 2611)
|
|
{
|
|
$hash_buf = md5_hex (md5_hex ($word_buf) . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 2612)
|
|
{
|
|
my $salt_buf_hex = unpack ("H*", $salt_buf);
|
|
|
|
$hash_buf = md5_hex (md5_hex ($word_buf) . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("\$PHPS\$%s\$%s", $salt_buf_hex, $hash_buf);
|
|
}
|
|
elsif ($mode == 2711)
|
|
{
|
|
$hash_buf = md5_hex (md5_hex ($word_buf) . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 2811)
|
|
{
|
|
$hash_buf = md5_hex (md5_hex ($salt_buf) . md5_hex ($word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 3000)
|
|
{
|
|
my $ppr = Authen::Passphrase::LANManager->new ("passphrase" => $word_buf);
|
|
|
|
$hash_buf = $ppr->hash_hex;
|
|
|
|
$tmp_hash = sprintf ("%s", substr ($hash_buf, 0, 16));
|
|
}
|
|
elsif ($mode == 3100)
|
|
{
|
|
$hash_buf = oracle_hash ($salt_buf, $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 3200)
|
|
{
|
|
my $cost = "05";
|
|
|
|
if (length ($iter))
|
|
{
|
|
$cost = $iter;
|
|
}
|
|
|
|
$tmp_hash = bcrypt ($word_buf, sprintf ('$2a$%s$%s$', $cost, en_base64 ($salt_buf)));
|
|
}
|
|
elsif ($mode == 3300)
|
|
{
|
|
my $iterations = 904;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $variant = "\$";
|
|
|
|
if (defined ($additional_param))
|
|
{
|
|
$variant = $additional_param;
|
|
}
|
|
|
|
my $prefix = sprintf ("\$md5%srounds=%i\$%s", $variant, $iterations, $salt_buf);
|
|
|
|
$iterations += 4096;
|
|
|
|
$hash_buf = sun_md5 ($word_buf, $prefix, $iterations);
|
|
|
|
$tmp_hash = sprintf ("%s\$%s", $prefix, $hash_buf);
|
|
}
|
|
elsif ($mode == 3500)
|
|
{
|
|
$hash_buf = md5_hex (md5_hex (md5_hex ($word_buf)));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 3610)
|
|
{
|
|
$hash_buf = md5_hex (md5_hex ($salt_buf) . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 3710)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . md5_hex ($word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 3711)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . "-" . md5_hex ($word_buf));
|
|
|
|
$tmp_hash = sprintf ("\$B\$%s\$%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 3720)
|
|
{
|
|
$hash_buf = md5_hex ($word_buf . md5_hex ($salt_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 3800)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . $word_buf . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 3910)
|
|
{
|
|
$hash_buf = md5_hex (md5_hex ($word_buf) . md5_hex ($salt_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 4010)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . md5_hex ($salt_buf . $word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 4110)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . md5_hex ($word_buf . $salt_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 4210)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . "\x00" . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 4300)
|
|
{
|
|
$hash_buf = md5_hex (uc (md5_hex ($word_buf)));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 4400)
|
|
{
|
|
$hash_buf = md5_hex (sha1_hex ($word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 4500)
|
|
{
|
|
$hash_buf = sha1_hex (sha1_hex ($word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif (($mode == 4520) || ($mode == 4521) || ($mode == 4522))
|
|
{
|
|
$hash_buf = sha1_hex ($salt_buf . sha1_hex ($word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 4600)
|
|
{
|
|
$hash_buf = sha1_hex (sha1_hex (sha1_hex ($word_buf)));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 4700)
|
|
{
|
|
$hash_buf = sha1_hex (md5_hex ($word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 4800)
|
|
{
|
|
my $index = rindex ($salt_buf, ":");
|
|
|
|
my $salt = substr ($salt_buf, 0, $index);
|
|
my $salt_bin = pack ("H*", $salt);
|
|
my $chap_sign = substr ($salt_buf, $index + 1);
|
|
my $chap_sign_bin = pack ("H*", $chap_sign);
|
|
|
|
$hash_buf = md5_hex ($chap_sign_bin . $word_buf . $salt_bin);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 4900)
|
|
{
|
|
$hash_buf = sha1_hex ($salt_buf . $word_buf . $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 5100)
|
|
{
|
|
my $pos;
|
|
|
|
if (! defined ($additional_param))
|
|
{
|
|
$pos = 0;
|
|
}
|
|
else
|
|
{
|
|
$pos = $additional_param * 8 unless ($additional_param > 2);
|
|
}
|
|
|
|
$hash_buf = md5_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", substr ($hash_buf, $pos, 16));
|
|
}
|
|
elsif ($mode == 5300)
|
|
{
|
|
my @salt_arr = split (":", $salt_buf);
|
|
|
|
my $msg_buf = pack ("H*", $salt_arr[0] . $salt_arr[1] . $salt_arr[2] . $salt_arr[3] . $salt_arr[4] . $salt_arr[5]);
|
|
my $nr_buf = pack ("H*", $salt_arr[6] . $salt_arr[7]);
|
|
|
|
my $hash_buf = hmac ($nr_buf , $word_buf, \&md5, 64);
|
|
$hash_buf = hmac_hex ($msg_buf, $hash_buf, \&md5, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 5400)
|
|
{
|
|
my @salt_arr = split (":", $salt_buf);
|
|
|
|
my $msg_buf = pack ("H*", $salt_arr[0] . $salt_arr[1] . $salt_arr[2] . $salt_arr[3] . $salt_arr[4] . $salt_arr[5]);
|
|
my $nr_buf = pack ("H*", $salt_arr[6] . $salt_arr[7]);
|
|
|
|
my $hash_buf = hmac ($nr_buf , $word_buf, \&sha1, 64);
|
|
$hash_buf = hmac_hex ($msg_buf, $hash_buf, \&sha1, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 5500)
|
|
{
|
|
my $index1 = index ($salt_buf, "::");
|
|
my $user = substr ($salt_buf, 0, $index1);
|
|
|
|
my $index2 = index ($salt_buf, ":", $index1 + 2);
|
|
my $domain = substr ($salt_buf, $index1 + 2, $index2 - $index1 - 2);
|
|
|
|
my $len = length (substr ($salt_buf, $index2 + 1));
|
|
|
|
my $c_challenge_hex;
|
|
|
|
if ($len > 32)
|
|
{
|
|
$c_challenge_hex = substr ($salt_buf, $index2 + 1, 48);
|
|
$index2 += 32;
|
|
}
|
|
else
|
|
{
|
|
$c_challenge_hex = substr ($salt_buf, $index2 + 1, 16);
|
|
$c_challenge_hex .= 00 x 32;
|
|
}
|
|
|
|
my $c_challenge = pack ("H*", substr ($c_challenge_hex, 0, 16));
|
|
my $s_challenge_hex = substr ($salt_buf, $index2 + 17, 16);
|
|
my $s_challenge = pack ("H*", $s_challenge_hex);
|
|
|
|
my $challenge = substr (md5 ($s_challenge . $c_challenge), 0, 8);
|
|
|
|
my $ntresp;
|
|
|
|
my $nthash = Authen::Passphrase::NTHash->new (passphrase => $word_buf)->hash . "\x00" x 5;
|
|
|
|
$ntresp .= Crypt::ECB::encrypt (setup_des_key (substr ($nthash, 0, 7)), "DES", $challenge, "none");
|
|
$ntresp .= Crypt::ECB::encrypt (setup_des_key (substr ($nthash, 7, 7)), "DES", $challenge, "none");
|
|
$ntresp .= Crypt::ECB::encrypt (setup_des_key (substr ($nthash, 14, 7)), "DES", $challenge, "none");
|
|
|
|
$tmp_hash = sprintf ("%s::%s:%s:%s:%s", $user, $domain, $c_challenge_hex, unpack ("H*", $ntresp), $s_challenge_hex);
|
|
}
|
|
elsif ($mode == 5600)
|
|
{
|
|
my $index1 = index ($salt_buf, "::");
|
|
my $user = substr ($salt_buf, 0, $index1);
|
|
|
|
my $index2 = index ($salt_buf, ":", $index1 + 2);
|
|
my $domain = substr ($salt_buf, $index1 + 2, $index2 - $index1 - 2);
|
|
|
|
my $s_challenge_hex = substr ($salt_buf, $index2 + 1, 16);
|
|
my $s_challenge = pack ("H*", $s_challenge_hex);
|
|
|
|
my $temp_hex = substr ($salt_buf, $index2 + 17);
|
|
my $temp = pack ("H*", $temp_hex);
|
|
|
|
my $nthash = Authen::Passphrase::NTHash->new (passphrase => $word_buf)->hash;
|
|
my $identity = Encode::encode ("UTF-16LE", uc ($user) . $domain);
|
|
|
|
$hash_buf = hmac_hex ($s_challenge . $temp, hmac ($identity, $nthash, \&md5, 64), \&md5, 64);
|
|
|
|
$tmp_hash = sprintf ("%s::%s:%s:%s:%s", $user, $domain, $s_challenge_hex, $hash_buf, $temp_hex);
|
|
}
|
|
elsif ($mode == 5700)
|
|
{
|
|
$hash_buf = sha256 ($word_buf);
|
|
|
|
my $base64_buf = encode_base64 ($hash_buf, "");
|
|
|
|
$tmp_hash = "";
|
|
|
|
for (my $i = 0; $i < 43; $i++)
|
|
{
|
|
$tmp_hash .= $CISCO_BASE64_MAPPING->{substr ($base64_buf, $i, 1)};
|
|
}
|
|
}
|
|
elsif ($mode == 5800)
|
|
{
|
|
$hash_buf = androidpin_hash ($word_buf, $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 6000)
|
|
{
|
|
$hash_buf = ripemd160_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 6100)
|
|
{
|
|
$hash_buf = whirlpool_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 6300)
|
|
{
|
|
my $iterations = 1000; # hard coded by the AIX format
|
|
|
|
$hash_buf = md5_crypt ('', $iterations, $word_buf, $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("{smd5}%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 6400)
|
|
{
|
|
my $iterations = 64;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = 1 << int ($iter);
|
|
}
|
|
|
|
$hash_buf = aix_ssha256_pbkdf2 ($word_buf, $salt_buf, $iterations);
|
|
|
|
$tmp_hash = sprintf ("{ssha256}%02i\$%s\$%s", log ($iterations) / log (2), $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 6500)
|
|
{
|
|
my $iterations = 64;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = 1 << int ($iter);
|
|
}
|
|
|
|
$hash_buf = aix_ssha512_pbkdf2 ($word_buf, $salt_buf, $iterations);
|
|
|
|
$tmp_hash = sprintf ("{ssha512}%02i\$%s\$%s", log ($iterations) / log (2), $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 6600)
|
|
{
|
|
my $iterations = 1000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $salt_hex = substr ($salt_buf, 0, 16);
|
|
my $salt = pack ("H*", $salt_hex);
|
|
|
|
my $prefix = substr ($salt_buf, 16, 2016);
|
|
|
|
my $iv_hex = substr ($salt_buf, 2032);
|
|
my $iv = pack ("H*", $iv_hex);
|
|
|
|
my $data = pack ("H*", "10101010101010101010101010101010");
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1');
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
output_len => 16
|
|
);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt, $word_buf);
|
|
|
|
my $cipher = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $iv,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 16
|
|
});
|
|
|
|
my $encrypted = unpack ("H*", $cipher->encrypt ($data));
|
|
|
|
$hash_buf = substr ($encrypted, 0, 32);
|
|
|
|
$tmp_hash = sprintf ("%i:%s:%s%s%s", $iterations, $salt_hex, $prefix, $iv_hex, $hash_buf);
|
|
}
|
|
elsif ($mode == 6700)
|
|
{
|
|
my $iterations = 64;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = 1 << int ($iter);
|
|
}
|
|
|
|
$hash_buf = aix_ssha1_pbkdf2 ($word_buf, $salt_buf, $iterations);
|
|
|
|
$tmp_hash = sprintf ("{ssha1}%02i\$%s\$%s", log ($iterations) / log (2), $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 6800)
|
|
{
|
|
my $variant = $additional_param;
|
|
|
|
if (! defined ($variant))
|
|
{
|
|
$variant = int (rand (2));
|
|
}
|
|
|
|
my $iterations = 500;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256);
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt_buf, $word_buf);
|
|
|
|
my $cipher = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $iv,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32
|
|
});
|
|
|
|
if ($variant == 1)
|
|
{
|
|
my $encrypt = $cipher->encrypt (substr ($salt_buf, 0, 16));
|
|
|
|
$hash_buf = substr (unpack ("H*", $encrypt), 0, 32);
|
|
}
|
|
else
|
|
{
|
|
my $verifier = "lastpass rocks\x02\x02";
|
|
|
|
$hash_buf = unpack ("H*", substr ($cipher->encrypt ($verifier), 0, 16));
|
|
}
|
|
|
|
$tmp_hash = sprintf ("%s:%i:%s", $hash_buf, $iterations, $salt_buf);
|
|
}
|
|
elsif ($mode == 6900)
|
|
{
|
|
$hash_buf = gost_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 7000)
|
|
{
|
|
my $FORTIGATE_SIGNATURE = "AK1";
|
|
my $FORTIGATE_MAGIC = pack ("H*", "a388ba2e424cb04a537930c13107cc3fa1329029a9815b70");
|
|
|
|
my $salt_bin = pack ("H*", $salt_buf);
|
|
|
|
my $hash = sha1 ($salt_bin . $word_buf . $FORTIGATE_MAGIC);
|
|
|
|
$hash = encode_base64 ($salt_bin . $hash, "");
|
|
|
|
$tmp_hash = sprintf ("%s%s", $FORTIGATE_SIGNATURE, $hash);
|
|
}
|
|
elsif ($mode == 7100)
|
|
{
|
|
my $iterations = 1024;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 512),
|
|
iterations => $iterations
|
|
);
|
|
|
|
$hash_buf = unpack ("H*", $pbkdf2->PBKDF2 (pack ("H*", $salt_buf), $word_buf));
|
|
|
|
$tmp_hash = sprintf ("\$ml\$%i\$%s\$%0128s", $iterations, $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 7200)
|
|
{
|
|
my $iterations = 1024;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 512),
|
|
iterations => $iterations
|
|
);
|
|
|
|
$hash_buf = unpack ("H*", $pbkdf2->PBKDF2 (pack ("H*", $salt_buf), $word_buf));
|
|
|
|
$tmp_hash = sprintf ("grub.pbkdf2.sha512.%i.%s.%0128s", $iterations, $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 7300)
|
|
{
|
|
$hash_buf = hmac_hex ($salt_buf, $word_buf, \&sha1);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", unpack ("H*", $salt_buf), $hash_buf);
|
|
}
|
|
elsif ($mode == 7400)
|
|
{
|
|
my $iterations = 5000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
if ($iter > 0)
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
}
|
|
|
|
$hash_buf = sha256_crypt ($iterations, $word_buf, $salt_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 7500)
|
|
{
|
|
my @salt_arr = split ("\\\$", $salt_buf);
|
|
|
|
my $user = $salt_arr[0];
|
|
|
|
my $realm = $salt_arr[1];
|
|
|
|
my $salt = $salt_arr[2];
|
|
|
|
my $hmac_salt = $salt_arr[3];
|
|
my $hmac_salt_bin = pack ("H*", $hmac_salt);
|
|
|
|
my $clear_data = $salt_arr[4];
|
|
|
|
my $k = md4 (encode ("UTF-16LE", $word_buf));
|
|
|
|
my $k1 = hmac_md5 ("\x01\x00\x00\x00", $k);
|
|
|
|
my $k3 = hmac_md5 ($hmac_salt_bin, $k1);
|
|
|
|
if (length ($clear_data) > 1)
|
|
{
|
|
my $clear_data_bin = pack ("H*", $clear_data);
|
|
|
|
$hash_buf = RC4 ($k3, $clear_data_bin);
|
|
}
|
|
else
|
|
{
|
|
my $hash = $salt_arr[5];
|
|
|
|
my $hash_bin = pack ("H*", $hash);
|
|
|
|
my $clear_data = RC4 ($k3, $hash_bin);
|
|
|
|
my $timestamp = substr ($clear_data, 14, 14);
|
|
|
|
my $is_numeric = 1;
|
|
|
|
if ($timestamp !~ /^[[:digit:]]{14}$/)
|
|
{
|
|
$is_numeric = 0;
|
|
}
|
|
|
|
if (! $is_numeric)
|
|
{
|
|
$hash_buf = "\x00" x 36;
|
|
|
|
if ($hash_buf eq $hash_bin)
|
|
{
|
|
$hash_buf = "\x01" x 36;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$hash_buf = $hash_bin;
|
|
}
|
|
}
|
|
|
|
$tmp_hash = sprintf ("\$krb5pa\$23\$%s\$%s\$%s\$%s%s", $user, $realm, $salt, unpack ("H*", $hash_buf), $hmac_salt);
|
|
}
|
|
elsif ($mode == 7700 || $mode == 7701)
|
|
{
|
|
$word_buf = uc $word_buf;
|
|
$salt_buf = uc $salt_buf;
|
|
|
|
my $word_buf_t = sapb_transcode ($word_buf);
|
|
my $salt_buf_t = sapb_transcode ($salt_buf);
|
|
|
|
my $digest1 = md5 ($word_buf_t . $salt_buf_t);
|
|
|
|
my $data = sapb_waldorf ($digest1, $word_buf_t, $salt_buf_t);
|
|
|
|
my $digest2 = md5 ($data);
|
|
|
|
my ($a, $b, $c, $d) = unpack ("N4", $digest2);
|
|
|
|
$a ^= $c;
|
|
$b ^= $d;
|
|
|
|
if ($mode == 7700)
|
|
{
|
|
$tmp_hash = sprintf ("%s\$%08X%08X", $salt_buf, $a, $b);
|
|
}
|
|
else
|
|
{
|
|
$tmp_hash = sprintf ("%s\$%08X%08X", $salt_buf, $a, 0);
|
|
}
|
|
}
|
|
elsif ($mode == 7800 || $mode == 7801)
|
|
{
|
|
my $theMagicArray_s =
|
|
"\x91\xac\x51\x14\x9f\x67\x54\x43\x24\xe7\x3b\xe0\x28\x74\x7b\xc2" .
|
|
"\x86\x33\x13\xeb\x5a\x4f\xcb\x5c\x08\x0a\x73\x37\x0e\x5d\x1c\x2f" .
|
|
"\x33\x8f\xe6\xe5\xf8\x9b\xae\xdd\x16\xf2\x4b\x8d\x2c\xe1\xd4\xdc" .
|
|
"\xb0\xcb\xdf\x9d\xd4\x70\x6d\x17\xf9\x4d\x42\x3f\x9b\x1b\x11\x94" .
|
|
"\x9f\x5b\xc1\x9b\x06\x05\x9d\x03\x9d\x5e\x13\x8a\x1e\x9a\x6a\xe8" .
|
|
"\xd9\x7c\x14\x17\x58\xc7\x2a\xf6\xa1\x99\x63\x0a\xd7\xfd\x70\xc3" .
|
|
"\xf6\x5e\x74\x13\x03\xc9\x0b\x04\x26\x98\xf7\x26\x8a\x92\x93\x25" .
|
|
"\xb0\xa2\x0d\x23\xed\x63\x79\x6d\x13\x32\xfa\x3c\x35\x02\x9a\xa3" .
|
|
"\xb3\xdd\x8e\x0a\x24\xbf\x51\xc3\x7c\xcd\x55\x9f\x37\xaf\x94\x4c" .
|
|
"\x29\x08\x52\x82\xb2\x3b\x4e\x37\x9f\x17\x07\x91\x11\x3b\xfd\xcd";
|
|
|
|
$salt_buf = uc $salt_buf;
|
|
|
|
my $digest = sha1 ($word_buf . $salt_buf);
|
|
|
|
my ($a, $b, $c, $d, $e) = unpack ("I*", $digest);
|
|
|
|
my $lengthMagicArray = 0x20;
|
|
my $offsetMagicArray = 0;
|
|
|
|
$lengthMagicArray += (($a >> 0) & 0xff) % 6;
|
|
$lengthMagicArray += (($a >> 8) & 0xff) % 6;
|
|
$lengthMagicArray += (($a >> 16) & 0xff) % 6;
|
|
$lengthMagicArray += (($a >> 24) & 0xff) % 6;
|
|
$lengthMagicArray += (($b >> 0) & 0xff) % 6;
|
|
$lengthMagicArray += (($b >> 8) & 0xff) % 6;
|
|
$lengthMagicArray += (($b >> 16) & 0xff) % 6;
|
|
$lengthMagicArray += (($b >> 24) & 0xff) % 6;
|
|
$lengthMagicArray += (($c >> 0) & 0xff) % 6;
|
|
$lengthMagicArray += (($c >> 8) & 0xff) % 6;
|
|
$offsetMagicArray += (($c >> 16) & 0xff) % 8;
|
|
$offsetMagicArray += (($c >> 24) & 0xff) % 8;
|
|
$offsetMagicArray += (($d >> 0) & 0xff) % 8;
|
|
$offsetMagicArray += (($d >> 8) & 0xff) % 8;
|
|
$offsetMagicArray += (($d >> 16) & 0xff) % 8;
|
|
$offsetMagicArray += (($d >> 24) & 0xff) % 8;
|
|
$offsetMagicArray += (($e >> 0) & 0xff) % 8;
|
|
$offsetMagicArray += (($e >> 8) & 0xff) % 8;
|
|
$offsetMagicArray += (($e >> 16) & 0xff) % 8;
|
|
$offsetMagicArray += (($e >> 24) & 0xff) % 8;
|
|
|
|
my $hash_buf = sha1_hex ($word_buf . substr ($theMagicArray_s, $offsetMagicArray, $lengthMagicArray) . $salt_buf);
|
|
|
|
if ($mode == 7800)
|
|
{
|
|
$tmp_hash = sprintf ("%s\$%s", $salt_buf, uc $hash_buf);
|
|
}
|
|
else
|
|
{
|
|
$tmp_hash = sprintf("%s\$%.20s%020X", $salt_buf, uc $hash_buf, 0);
|
|
}
|
|
}
|
|
elsif ($mode == 7900)
|
|
{
|
|
my $cost = 14;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$cost = $iter;
|
|
}
|
|
|
|
my $phpass_it = 1 << $cost;
|
|
|
|
$hash_buf = sha512 ($salt_buf . $word_buf);
|
|
|
|
for (my $i = 0; $i < $phpass_it; $i++)
|
|
{
|
|
$hash_buf = sha512 ($hash_buf . $word_buf);
|
|
}
|
|
|
|
my $base64_buf = substr (Authen::Passphrase::PHPass::_en_base64 ($hash_buf), 0, 43);
|
|
|
|
my $base64_digits = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
my $cost_str = substr ($base64_digits , $cost, 1);
|
|
|
|
$tmp_hash = sprintf ('$S$%s%s%s', $cost_str, $salt_buf, $base64_buf);
|
|
}
|
|
elsif ($mode == 8000)
|
|
{
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $word_buf_utf = encode ("UTF-16BE", $word_buf);
|
|
|
|
$hash_buf = sha256_hex ($word_buf_utf . "\x00" x (510 - (length ($word_buf) * 2)) . $salt_buf_bin);
|
|
|
|
$tmp_hash = sprintf ("0xc007%s%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 8100)
|
|
{
|
|
$hash_buf = sha1_hex ($salt_buf . $word_buf . "\x00");
|
|
|
|
$tmp_hash = sprintf ("1%s%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 8200)
|
|
{
|
|
my $iterations = 40000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
my $salt_hex = substr ($salt_buf, 0, 32);
|
|
my $salt = pack ("H*", $salt_hex);
|
|
|
|
my $data_hex = substr ($salt_buf, 32);
|
|
my $data = pack ("H*", $data_hex);
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 512),
|
|
iterations => int $iterations
|
|
);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt, $word_buf);
|
|
|
|
$hash_buf = hmac_hex ($data, substr ($key, 32, 32), \&sha256, 64);
|
|
|
|
$tmp_hash = sprintf ("%s:%s:%d:%s", $hash_buf, $salt_hex, $iterations, $data_hex);
|
|
}
|
|
elsif ($mode == 8300)
|
|
{
|
|
my ($domain, $salt_hex) = split (":", $salt_buf);
|
|
|
|
my $hashalg = Net::DNS::SEC->digtype ("SHA1");
|
|
|
|
my $salt = pack ("H*", $salt_hex);
|
|
|
|
my $iterations = 1;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
my $name = lc ($word_buf . $domain);
|
|
|
|
my $hash_buf = Net::DNS::RR::NSEC3::name2hash ($hashalg, $name, $iterations, $salt);
|
|
|
|
$tmp_hash = sprintf ("%s:%s:%s:%d", $hash_buf, $domain, $salt_hex, $iterations);
|
|
}
|
|
elsif ($mode == 8400 || $mode == 13900)
|
|
{
|
|
$hash_buf = sha1_hex ($salt_buf . sha1_hex ($salt_buf . sha1_hex ($word_buf)));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 8500)
|
|
{
|
|
$hash_buf = racf_hash (uc $salt_buf, $word_buf);
|
|
|
|
$tmp_hash = sprintf ('$racf$*%s*%s', uc $salt_buf, uc $hash_buf);
|
|
}
|
|
elsif ($mode == 8600)
|
|
{
|
|
my @saved_key = map { ord $_; } split "", $word_buf;
|
|
|
|
my $len = scalar @saved_key;
|
|
|
|
my @state = domino_big_md (\@saved_key, $len);
|
|
|
|
$tmp_hash = sprintf ('%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x',
|
|
$state[ 0],
|
|
$state[ 1],
|
|
$state[ 2],
|
|
$state[ 3],
|
|
$state[ 4],
|
|
$state[ 5],
|
|
$state[ 6],
|
|
$state[ 7],
|
|
$state[ 8],
|
|
$state[ 9],
|
|
$state[10],
|
|
$state[11],
|
|
$state[12],
|
|
$state[13],
|
|
$state[14],
|
|
$state[15],
|
|
);
|
|
}
|
|
elsif ($mode == 8700)
|
|
{
|
|
my $domino_char = undef;
|
|
|
|
if (defined ($additional_param))
|
|
{
|
|
$domino_char = $additional_param;
|
|
}
|
|
|
|
my @saved_key = map { ord $_; } split "", $word_buf;
|
|
|
|
my $len = scalar @saved_key;
|
|
|
|
my @state = domino_big_md (\@saved_key, $len);
|
|
|
|
my $str = "(" . unpack ("H*", join ("", (map { chr $_; } @state))) . ")";
|
|
|
|
@saved_key = map { ord $_; } split "", $salt_buf . uc $str;
|
|
|
|
@state = domino_big_md (\@saved_key, 34);
|
|
|
|
$hash_buf = join ("", (map { chr $_; } @state));
|
|
|
|
$tmp_hash = sprintf ('(G%s)', domino_encode ($salt_buf . $hash_buf, $domino_char));
|
|
}
|
|
elsif ($mode == 8900)
|
|
{
|
|
my $N = 1024;
|
|
my $r = 1;
|
|
my $p = 1;
|
|
|
|
if (defined ($additional_param))
|
|
{
|
|
$N = $additional_param;
|
|
$r = $additional_param2;
|
|
$p = $additional_param3;
|
|
}
|
|
|
|
$hash_buf = scrypt_hash ($word_buf, $salt_buf, $N, $r, $p, 32);
|
|
|
|
$tmp_hash = sprintf ('%s', $hash_buf);
|
|
}
|
|
elsif ($mode == 9100)
|
|
{
|
|
my $iterations = 5000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
my $domino_char = undef;
|
|
|
|
# domino 5 hash - SEC_pwddigest_V1 - -m 8600
|
|
|
|
my @saved_key = map { ord $_; } split "", $word_buf;
|
|
|
|
my $len = scalar @saved_key;
|
|
|
|
my @state = domino_big_md (\@saved_key, $len);
|
|
|
|
|
|
# domino 6 hash - SEC_pwddigest_V2 - -m 8700
|
|
|
|
my $salt_part = substr ($salt_buf, 0, 5);
|
|
|
|
my $str = "(" . unpack ("H*", join ("", (map { chr $_; } @state))) . ")";
|
|
|
|
@saved_key = map { ord $_; } split "", $salt_part . uc $str;
|
|
|
|
@state = domino_big_md (\@saved_key, 34);
|
|
|
|
$hash_buf = join ("", (map { chr $_; } @state));
|
|
|
|
$tmp_hash = sprintf ('(G%s)', domino_encode ($salt_part . $hash_buf, $domino_char));
|
|
|
|
|
|
# domino 8(.5.x) hash - SEC_pwddigest_V3 - -m 9100
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hash_class => 'HMACSHA1',
|
|
iterations => $iterations,
|
|
output_len => 8,
|
|
salt_len => 16,
|
|
);
|
|
|
|
my $chars = "02";
|
|
|
|
if (defined ($additional_param))
|
|
{
|
|
$chars = $additional_param;
|
|
}
|
|
|
|
my $digest_new = $pbkdf2->PBKDF2 ($salt_buf, $tmp_hash);
|
|
|
|
for (my $i = length ($iterations); $i < 10; $i++)
|
|
{
|
|
$iterations = "0" . $iterations;
|
|
}
|
|
|
|
$tmp_hash = sprintf ('(H%s)', domino_85x_encode ($salt_buf . $iterations . $chars . $digest_new, $domino_char));
|
|
}
|
|
elsif ($mode == 9200)
|
|
{
|
|
my $iterations = 20000;
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations
|
|
);
|
|
|
|
$hash_buf = encode_base64 ($pbkdf2->PBKDF2 ($salt_buf, $word_buf), "");
|
|
|
|
$tmp_hash = "";
|
|
|
|
for (my $i = 0; $i < 43; $i++)
|
|
{
|
|
$tmp_hash .= $CISCO_BASE64_MAPPING->{substr ($hash_buf, $i, 1)};
|
|
}
|
|
|
|
$tmp_hash = sprintf ("\$8\$%s\$%s", $salt_buf, $tmp_hash);
|
|
}
|
|
elsif ($mode == 9300)
|
|
{
|
|
my $N = 16384;
|
|
my $r = 1;
|
|
my $p = 1;
|
|
|
|
$hash_buf = scrypt_b64 ($word_buf, $salt_buf, $N, $r, $p, 32);
|
|
|
|
$tmp_hash = "";
|
|
|
|
for (my $i = 0; $i < 43; $i++)
|
|
{
|
|
$tmp_hash .= $CISCO_BASE64_MAPPING->{substr ($hash_buf, $i, 1)};
|
|
}
|
|
|
|
$tmp_hash = sprintf ('$9$%s$%s', $salt_buf, $tmp_hash);
|
|
}
|
|
elsif ($mode == 9400)
|
|
{
|
|
my $iterations = 50000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $aes_key_size = 128; # or 256
|
|
|
|
if (defined ($additional_param2))
|
|
{
|
|
$aes_key_size = $additional_param2;
|
|
}
|
|
|
|
$salt_buf = pack ("H*", $salt_buf);
|
|
|
|
my $tmp = sha1 ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
for (my $i = 0; $i < $iterations; $i++)
|
|
{
|
|
my $num32 = pack ("L", $i);
|
|
|
|
$tmp = sha1 ($num32 . $tmp);
|
|
}
|
|
|
|
my $zero32 = pack ("L", 0x00);
|
|
|
|
my $derivation_array1 = pack ("C", 0x36) x 64;
|
|
my $derivation_array2 = pack ("C", 0x5C) x 64;
|
|
|
|
$tmp = sha1 ($tmp . $zero32);
|
|
|
|
my $tmp2 = sha1 ($derivation_array1 ^ $tmp);
|
|
my $tmp3 = sha1 ($derivation_array2 ^ $tmp);
|
|
|
|
my $key = substr ($tmp2 . $tmp3, 0, $aes_key_size / 8);
|
|
|
|
my $m = Crypt::Mode::ECB->new ('AES', 0);
|
|
|
|
my $encdata;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$encdata = $m->decrypt (pack ("H*", $additional_param), $key);
|
|
}
|
|
else
|
|
{
|
|
$encdata = "A" x 16; ## can be anything
|
|
}
|
|
|
|
my $data1_buf = $encdata;
|
|
my $data2_buf = sha1 (substr ($data1_buf, 0, 16));
|
|
|
|
$data1_buf = substr ($data1_buf . ("\x00" x 16), 0, 16);
|
|
$data2_buf = substr ($data2_buf . ("\x00" x 16), 0, 32);
|
|
|
|
my $encrypted1 = unpack ("H*", $m->encrypt ($data1_buf, $key));
|
|
my $encrypted2 = unpack ("H*", $m->encrypt ($data2_buf, $key));
|
|
|
|
$encrypted1 = substr ($encrypted1, 0, 32);
|
|
$encrypted2 = substr ($encrypted2, 0, 40);
|
|
|
|
$tmp_hash = sprintf ("\$office\$*%d*%d*%d*%d*%s*%s*%s", 2007, 20, $aes_key_size, 16, unpack ("H*", $salt_buf), $encrypted1, $encrypted2);
|
|
}
|
|
elsif ($mode == 9500)
|
|
{
|
|
my $iterations = 100000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
$salt_buf = pack ("H*", $salt_buf);
|
|
|
|
my $tmp = sha1 ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
for (my $i = 0; $i < $iterations; $i++)
|
|
{
|
|
my $num32 = pack ("L", $i);
|
|
|
|
$tmp = sha1 ($num32 . $tmp);
|
|
}
|
|
|
|
my $encryptedVerifierHashInputBlockKey = "\xfe\xa7\xd2\x76\x3b\x4b\x9e\x79";
|
|
my $encryptedVerifierHashValueBlockKey = "\xd7\xaa\x0f\x6d\x30\x61\x34\x4e";
|
|
|
|
my $final1 = sha1 ($tmp . $encryptedVerifierHashInputBlockKey);
|
|
my $final2 = sha1 ($tmp . $encryptedVerifierHashValueBlockKey);
|
|
|
|
my $key1 = substr ($final1, 0, 16);
|
|
my $key2 = substr ($final2, 0, 16);
|
|
|
|
my $cipher1 = Crypt::CBC->new ({
|
|
key => $key1,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $salt_buf,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 16,
|
|
padding => "null",
|
|
});
|
|
|
|
my $cipher2 = Crypt::CBC->new ({
|
|
key => $key2,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $salt_buf,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 16,
|
|
padding => "null",
|
|
});
|
|
|
|
my $encdata;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$encdata = $cipher1->decrypt (pack ("H*", $additional_param));
|
|
}
|
|
else
|
|
{
|
|
$encdata = "A" x 16; ## can be anything
|
|
}
|
|
|
|
my $data1_buf = $encdata;
|
|
my $data2_buf = sha1 (substr ($data1_buf, 0, 16));
|
|
|
|
my $encrypted1 = unpack ("H*", $cipher1->encrypt ($data1_buf));
|
|
my $encrypted2 = unpack ("H*", $cipher2->encrypt ($data2_buf));
|
|
|
|
$encrypted2 = substr ($encrypted2, 0, 64);
|
|
|
|
$tmp_hash = sprintf ("\$office\$*%d*%d*%d*%d*%s*%s*%s", 2010, 100000, 128, 16, unpack ("H*", $salt_buf), $encrypted1, $encrypted2);
|
|
}
|
|
elsif ($mode == 9600)
|
|
{
|
|
my $iterations = 100000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
$salt_buf = pack ("H*", $salt_buf);
|
|
|
|
my $tmp = sha512 ($salt_buf . encode ("UTF-16LE", $word_buf));
|
|
|
|
for (my $i = 0; $i < $iterations; $i++)
|
|
{
|
|
my $num32 = pack ("L", $i);
|
|
|
|
$tmp = sha512 ($num32 . $tmp);
|
|
}
|
|
|
|
my $encryptedVerifierHashInputBlockKey = "\xfe\xa7\xd2\x76\x3b\x4b\x9e\x79";
|
|
my $encryptedVerifierHashValueBlockKey = "\xd7\xaa\x0f\x6d\x30\x61\x34\x4e";
|
|
|
|
my $final1 = sha512 ($tmp . $encryptedVerifierHashInputBlockKey);
|
|
my $final2 = sha512 ($tmp . $encryptedVerifierHashValueBlockKey);
|
|
|
|
my $key1 = substr ($final1, 0, 32);
|
|
my $key2 = substr ($final2, 0, 32);
|
|
|
|
my $cipher1 = Crypt::CBC->new ({
|
|
key => $key1,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $salt_buf,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32,
|
|
padding => "null",
|
|
});
|
|
|
|
my $cipher2 = Crypt::CBC->new ({
|
|
key => $key2,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $salt_buf,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32,
|
|
padding => "null",
|
|
});
|
|
|
|
my $encdata;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$encdata = $cipher1->decrypt (pack ("H*", $additional_param));
|
|
}
|
|
else
|
|
{
|
|
$encdata = "A" x 16; ## can be anything
|
|
}
|
|
|
|
my $data1_buf = $encdata;
|
|
my $data2_buf = sha512 (substr ($data1_buf, 0, 16));
|
|
|
|
my $encrypted1 = unpack ("H*", $cipher1->encrypt ($data1_buf));
|
|
my $encrypted2 = unpack ("H*", $cipher2->encrypt ($data2_buf));
|
|
|
|
$encrypted2 = substr ($encrypted2, 0, 64);
|
|
|
|
$tmp_hash = sprintf ("\$office\$*%d*%d*%d*%d*%s*%s*%s", 2013, 100000, 256, 16, unpack ("H*", $salt_buf), $encrypted1, $encrypted2);
|
|
}
|
|
elsif ($mode == 9700)
|
|
{
|
|
$salt_buf = pack ("H*", $salt_buf);
|
|
|
|
my $tmp = md5 (encode ("UTF-16LE", $word_buf));
|
|
|
|
$tmp = substr ($tmp, 0, 5);
|
|
|
|
my $data;
|
|
|
|
for (my $i = 0; $i < 16; $i++)
|
|
{
|
|
$data .= $tmp;
|
|
$data .= $salt_buf;
|
|
}
|
|
|
|
$tmp = md5 ($data);
|
|
|
|
$tmp = substr ($tmp, 0, 5);
|
|
|
|
my $version;
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$version = $additional_param2;
|
|
}
|
|
else
|
|
{
|
|
$version = (unpack ("L", $tmp) & 1) ? 0 : 1;
|
|
}
|
|
|
|
my $rc4_key = md5 ($tmp . "\x00\x00\x00\x00");
|
|
|
|
my $m = Crypt::RC4->new (substr ($rc4_key, 0, 16));
|
|
|
|
my $encdata;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$encdata = $m->RC4 (pack ("H*", $additional_param));
|
|
}
|
|
else
|
|
{
|
|
$encdata = "A" x 16; ## can be anything
|
|
}
|
|
|
|
my $data1_buf = $encdata;
|
|
my $data2_buf = md5 (substr ($data1_buf, 0, 16));
|
|
|
|
$m = Crypt::RC4->new (substr ($rc4_key, 0, 16));
|
|
|
|
my $encrypted1 = $m->RC4 ($data1_buf);
|
|
my $encrypted2 = $m->RC4 ($data2_buf);
|
|
|
|
$tmp_hash = sprintf ("\$oldoffice\$%d*%s*%s*%s", $version, unpack ("H*", $salt_buf), unpack ("H*", $encrypted1), unpack ("H*", $encrypted2));
|
|
}
|
|
elsif ($mode == 9800)
|
|
{
|
|
$salt_buf = pack ("H*", $salt_buf);
|
|
|
|
my $tmp = sha1 ($salt_buf. encode ("UTF-16LE", $word_buf));
|
|
|
|
my $version;
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$version = $additional_param2;
|
|
}
|
|
else
|
|
{
|
|
$version = (unpack ("L", $tmp) & 1) ? 3 : 4;
|
|
}
|
|
|
|
my $rc4_key = sha1 ($tmp . "\x00\x00\x00\x00");
|
|
|
|
if ($version == 3)
|
|
{
|
|
$rc4_key = substr ($rc4_key, 0, 5) . "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
|
}
|
|
|
|
my $m = Crypt::RC4->new (substr ($rc4_key, 0, 16));
|
|
|
|
my $encdata;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$encdata = $m->RC4 (pack ("H*", $additional_param));
|
|
}
|
|
else
|
|
{
|
|
$encdata = "A" x 16; ## can be anything
|
|
}
|
|
|
|
my $data1_buf = $encdata;
|
|
my $data2_buf = sha1 (substr ($data1_buf, 0, 16));
|
|
|
|
$m = Crypt::RC4->new (substr ($rc4_key, 0, 16));
|
|
|
|
my $encrypted1 = $m->RC4 ($data1_buf);
|
|
my $encrypted2 = $m->RC4 ($data2_buf);
|
|
|
|
$tmp_hash = sprintf ("\$oldoffice\$%d*%s*%s*%s", $version, unpack ("H*", $salt_buf), unpack ("H*", $encrypted1), unpack ("H*", $encrypted2));
|
|
}
|
|
elsif ($mode == 9900)
|
|
{
|
|
$tmp_hash = sprintf ("%s", md5_hex ($word_buf . "\0" x (100 - length ($word_buf))));
|
|
}
|
|
elsif ($mode == 10000)
|
|
{
|
|
my $iterations = 10000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations
|
|
);
|
|
|
|
$hash_buf = encode_base64 ($pbkdf2->PBKDF2 ($salt_buf, $word_buf), "");
|
|
|
|
$tmp_hash = sprintf ("pbkdf2_sha256\$%i\$%s\$%s", $iterations, $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 10100)
|
|
{
|
|
my $seed = pack ("H*", $salt_buf);
|
|
|
|
my ($hi, $lo) = siphash ($word_buf, $seed);
|
|
|
|
my $hi_s = sprintf ("%08x", $hi);
|
|
my $lo_s = sprintf ("%08x", $lo);
|
|
|
|
$hi_s =~ s/^(..)(..)(..)(..)$/$4$3$2$1/;
|
|
$lo_s =~ s/^(..)(..)(..)(..)$/$4$3$2$1/;
|
|
|
|
$tmp_hash = sprintf ("%s%s:2:4:%s", $hi_s, $lo_s, $salt_buf);
|
|
}
|
|
elsif ($mode == 10200)
|
|
{
|
|
my $challengeb64 = encode_base64 ($salt_buf, "");
|
|
|
|
my $username;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$username = $additional_param;
|
|
}
|
|
else
|
|
{
|
|
$username = "user";
|
|
}
|
|
|
|
$hash_buf = hmac_hex ($salt_buf, $word_buf, \&md5);
|
|
|
|
my $responseb64 = encode_base64 ($username . " " . $hash_buf, "");
|
|
|
|
$tmp_hash = sprintf ('$cram_md5$%s$%s', $challengeb64, $responseb64);
|
|
}
|
|
elsif ($mode == 10300)
|
|
{
|
|
my $iterations = 1024;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $hash_buf = $salt_buf;
|
|
|
|
for (my $pos = 0; $pos < $iterations; $pos++)
|
|
{
|
|
$hash_buf = sha1 ($word_buf . $hash_buf);
|
|
}
|
|
|
|
$hash_buf = encode_base64 ($hash_buf . $salt_buf, "");
|
|
|
|
$tmp_hash = sprintf ("{x-issha, %i}%s", $iterations, $hash_buf);
|
|
}
|
|
elsif ($mode == 10400)
|
|
{
|
|
my $id = $salt_buf;
|
|
my $u = $additional_param;
|
|
my $o = $additional_param2;
|
|
my $P = $additional_param3;
|
|
|
|
if (defined $u == 0)
|
|
{
|
|
$u = "0" x 64;
|
|
}
|
|
|
|
if (defined $o == 0)
|
|
{
|
|
$o = "0" x 64;
|
|
}
|
|
|
|
if (defined $P == 0)
|
|
{
|
|
$P = -1;
|
|
}
|
|
|
|
my $padding;
|
|
|
|
for (my $i = 0; $i < 32; $i++)
|
|
{
|
|
$padding .= pack ("C", $PDF_PADDING->[$i]);
|
|
}
|
|
|
|
my $res = pdf_compute_encryption_key ($word_buf, $padding, $id, $u, $o, $P, 1, 2, 0);
|
|
|
|
my $m = Crypt::RC4->new (substr ($res, 0, 5));
|
|
|
|
$u = $m->RC4 ($padding);
|
|
|
|
$tmp_hash = sprintf ('$pdf$%d*%d*40*%d*%d*16*%s*32*%s*32*%s', 1, 2, $P, 0, $id, unpack ("H*", $u), $o);
|
|
}
|
|
elsif ($mode == 10500)
|
|
{
|
|
my $id = $salt_buf;
|
|
my $u = $additional_param;
|
|
my $o = $additional_param2;
|
|
my $P = $additional_param3;
|
|
my $V = $additional_param4;
|
|
my $R = $additional_param5;
|
|
my $enc = $additional_param6;
|
|
|
|
if (defined $u == 0)
|
|
{
|
|
$u = "0" x 64;
|
|
}
|
|
|
|
my $u_save = $u;
|
|
|
|
if (defined $o == 0)
|
|
{
|
|
$o = "0" x 64;
|
|
}
|
|
|
|
if (defined $R == 0)
|
|
{
|
|
$R = get_random_num (3, 5);
|
|
}
|
|
|
|
if (defined $V == 0)
|
|
{
|
|
$V = ($R == 3) ? 2 : 4;
|
|
}
|
|
|
|
if (defined $P == 0)
|
|
{
|
|
$P = ($R == 3) ? -4 : -1028;
|
|
}
|
|
|
|
if (defined $enc == 0)
|
|
{
|
|
$enc = ($R == 3) ? 1 : get_random_num (0, 2);
|
|
}
|
|
|
|
my $padding;
|
|
|
|
for (my $i = 0; $i < 32; $i++)
|
|
{
|
|
$padding .= pack ("C", $PDF_PADDING->[$i]);
|
|
}
|
|
|
|
my $res = pdf_compute_encryption_key ($word_buf, $padding, $id, $u, $o, $P, $V, $R, $enc);
|
|
|
|
my $digest = md5 ($padding . pack ("H*", $id));
|
|
|
|
my $m = Crypt::RC4->new ($res);
|
|
|
|
$u = $m->RC4 ($digest);
|
|
|
|
my @ress = split "", $res;
|
|
|
|
for (my $x = 1; $x <= 19; $x++)
|
|
{
|
|
my @xor;
|
|
|
|
for (my $i = 0; $i < 16; $i++)
|
|
{
|
|
$xor[$i] = chr (ord ($ress[$i]) ^ $x);
|
|
}
|
|
|
|
my $s = join ("", @xor);
|
|
|
|
my $m2 = Crypt::RC4->new ($s);
|
|
|
|
$u = $m2->RC4 ($u);
|
|
}
|
|
|
|
$u .= substr (pack ("H*", $u_save), 16, 16);
|
|
|
|
$tmp_hash = sprintf ('$pdf$%d*%d*128*%d*%d*16*%s*32*%s*32*%s', $V, $R, $P, $enc, $id, unpack ("H*", $u), $o);
|
|
}
|
|
elsif ($mode == 10600)
|
|
{
|
|
my $id = $salt_buf;
|
|
my $rest = $additional_param;
|
|
|
|
if (defined $id == 0)
|
|
{
|
|
$id = "0" x 32;
|
|
}
|
|
|
|
if (defined $rest == 0)
|
|
{
|
|
$rest = "127*";
|
|
$rest .= "0" x 64;
|
|
$rest .= $id;
|
|
$rest .= "0" x 158;
|
|
$rest .= "*127*00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*32*0000000000000000000000000000000000000000000000000000000000000000*32*0000000000000000000000000000000000000000000000000000000000000000";
|
|
}
|
|
|
|
my @data = split /\*/, $rest;
|
|
|
|
my $u = pack ("H*", $data[1]);
|
|
|
|
my $h = sha256 ($word_buf . substr ($u, 32, 8));
|
|
|
|
$data[1] = unpack ("H*", $h . substr ($u, 32));
|
|
|
|
$rest = join ("*", @data);
|
|
|
|
$tmp_hash = sprintf ('$pdf$5*5*256*-1028*1*16*%s*%s', $id, $rest);
|
|
}
|
|
elsif ($mode == 10700)
|
|
{
|
|
my $id = $salt_buf;
|
|
my $rest = $additional_param;
|
|
|
|
if (defined $id == 0)
|
|
{
|
|
$id = "0" x 32;
|
|
}
|
|
|
|
if (defined $rest == 0)
|
|
{
|
|
$rest = "127*";
|
|
$rest .= "0" x 64;
|
|
$rest .= $id;
|
|
$rest .= "0" x 158;
|
|
$rest .= "*127*00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*32*0000000000000000000000000000000000000000000000000000000000000000*32*0000000000000000000000000000000000000000000000000000000000000000";
|
|
}
|
|
|
|
my @datax = split /\*/, $rest;
|
|
|
|
my $u = pack ("H*", $datax[1]);
|
|
|
|
my $block = sha256 ($word_buf . substr ($u, 32, 8));
|
|
|
|
my $block_size = 32;
|
|
|
|
my $data = 0x00 x 64;
|
|
|
|
my $data_len = 1;
|
|
|
|
my $data63 = 0;
|
|
|
|
for (my $i = 0; $i < 64 || $i < $data63 + 32; $i++)
|
|
{
|
|
$data = $word_buf . $block;
|
|
|
|
$data_len = length ($data);
|
|
|
|
for (my $k = 1; $k < 64; $k++)
|
|
{
|
|
$data .= $word_buf . $block;
|
|
}
|
|
|
|
my $aes = Crypt::CBC->new ({
|
|
key => substr ($block, 0, 16),
|
|
cipher => "Crypt::Rijndael",
|
|
iv => substr ($block, 16, 16),
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 16,
|
|
padding => "null",
|
|
});
|
|
|
|
my $data = $aes->encrypt ($data);
|
|
|
|
my $sum = 0;
|
|
|
|
for (my $j = 0; $j < 16; $j++)
|
|
{
|
|
$sum += ord (substr ($data, $j, 1));
|
|
}
|
|
|
|
$block_size = 32 + ($sum % 3) * 16;
|
|
|
|
if ($block_size == 32)
|
|
{
|
|
$block = sha256 (substr ($data, 0, $data_len * 64));
|
|
}
|
|
elsif ($block_size == 48)
|
|
{
|
|
$block = sha384 (substr ($data, 0, $data_len * 64));
|
|
}
|
|
elsif ($block_size == 64)
|
|
{
|
|
$block = sha512 (substr ($data, 0, $data_len * 64));
|
|
}
|
|
|
|
$data63 = ord (substr ($data, $data_len * 64 - 1, 1));
|
|
}
|
|
|
|
$datax[1] = unpack ("H*", substr ($block, 0, 32) . substr ($u, 32));
|
|
|
|
$rest = join ("*", @datax);
|
|
|
|
$tmp_hash = sprintf ('$pdf$5*6*256*-1028*1*16*%s*%s', $id, $rest);
|
|
}
|
|
elsif ($mode == 10800)
|
|
{
|
|
$hash_buf = sha384_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 10900)
|
|
{
|
|
my $iterations = 1000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $out_len = 24;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$out_len = $additional_param;
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations,
|
|
output_len => $out_len
|
|
);
|
|
|
|
$hash_buf = encode_base64 ($pbkdf2->PBKDF2 ($salt_buf, $word_buf), "");
|
|
|
|
my $base64_salt_buf = encode_base64 ($salt_buf, "");
|
|
|
|
$tmp_hash = sprintf ("sha256:%i:%s:%s", $iterations, $base64_salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 16900)
|
|
{
|
|
my $iterations = 10000;
|
|
|
|
my $salt_hex = substr ($salt_buf, 0, 64);
|
|
my $salt = pack ("H*", $salt_hex);
|
|
|
|
my $ciphertext = randbytes(32);
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
my $ciphertext_hex = $additional_param;
|
|
$ciphertext = pack ("H*", $ciphertext_hex);
|
|
}
|
|
|
|
# actually 80 but the last 16 bytes are the IV which we don't need
|
|
my $out_len = 64;
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations,
|
|
output_len => $out_len
|
|
);
|
|
|
|
my $derived_key = $pbkdf2->PBKDF2 ($salt, $word_buf);
|
|
|
|
$hash_buf = hmac_hex ($ciphertext, substr ($derived_key, 32, 32), \&sha256);
|
|
|
|
$tmp_hash = sprintf ('$ansible$0*0*%s*%s*%s', unpack ("H*", $salt), unpack ("H*", $ciphertext), $hash_buf);
|
|
}
|
|
elsif ($mode == 11000)
|
|
{
|
|
$hash_buf = md5_hex ($salt_buf . $word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 11100)
|
|
{
|
|
my $user = "postgres";
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$user = $additional_param;
|
|
}
|
|
|
|
$hash_buf = md5_hex (md5_hex ($word_buf . $user) . pack ("H*", $salt_buf));
|
|
|
|
$tmp_hash = sprintf ("\$postgres\$%s*%s*%s", $user, $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 11200)
|
|
{
|
|
my $sha1_pass = sha1 ($word_buf);
|
|
my $double_sha1 = sha1 ($sha1_pass);
|
|
|
|
my $xor_part1 = $sha1_pass;
|
|
my $xor_part2 = sha1 (pack ("H*", $salt_buf) . $double_sha1);
|
|
|
|
my $hash_buf = "";
|
|
|
|
for (my $i = 0; $i < 20; $i++)
|
|
{
|
|
my $first_byte = substr ($xor_part1, $i, 1);
|
|
my $second_byte = substr ($xor_part2, $i, 1);
|
|
|
|
my $xor_result = $first_byte ^ $second_byte;
|
|
|
|
$hash_buf .= unpack ("H*", $xor_result);
|
|
}
|
|
|
|
$tmp_hash = sprintf ("\$mysqlna\$%s*%s", $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 11300)
|
|
{
|
|
my $ckey_buf = get_random_string (96);
|
|
|
|
if (length ($additional_param))
|
|
{
|
|
$ckey_buf = $additional_param;
|
|
}
|
|
|
|
my $public_key_buf = get_random_string (66);
|
|
|
|
if (length ($additional_param2))
|
|
{
|
|
$public_key_buf = $additional_param2;
|
|
}
|
|
|
|
my $salt_iter = get_random_num (150000, 250000);
|
|
|
|
if (length ($iter))
|
|
{
|
|
$salt_iter = int ($iter);
|
|
}
|
|
|
|
my $hash_buf = sha512 ($word_buf . pack ("H*", $salt_buf));
|
|
|
|
for (my $i = 1; $i < $salt_iter; $i++)
|
|
{
|
|
$hash_buf = sha512 ($hash_buf);
|
|
}
|
|
|
|
my $data = get_random_string (32);
|
|
|
|
my $aes = Crypt::CBC->new ({
|
|
key => substr ($hash_buf, 0, 32),
|
|
cipher => "Crypt::Rijndael",
|
|
iv => substr ($hash_buf, 32, 16),
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32,
|
|
padding => "standard",
|
|
});
|
|
|
|
my $cry_master_buf = (unpack ("H*", $aes->encrypt ($data)));
|
|
|
|
$tmp_hash = sprintf ('$bitcoin$%d$%s$%d$%s$%d$%d$%s$%d$%s',
|
|
length ($cry_master_buf),
|
|
$cry_master_buf,
|
|
length ($salt_buf),
|
|
$salt_buf,
|
|
$salt_iter,
|
|
length ($ckey_buf),
|
|
$ckey_buf,
|
|
length ($public_key_buf),
|
|
$public_key_buf);
|
|
}
|
|
elsif ($mode == 11400)
|
|
{
|
|
my ($directive, $URI_server, $URI_client, $user, $realm, $nonce, $nonce_count, $nonce_client, $qop, $method, $URI, $URI_prefix, $URI_resource, $URI_suffix);
|
|
|
|
$directive = "MD5"; # only directive currently supported
|
|
|
|
if (defined ($additional_param))
|
|
{
|
|
$user = $additional_param;
|
|
$realm = $additional_param2;
|
|
$nonce = $salt_buf;
|
|
$nonce_count = $additional_param3;
|
|
$nonce_client = $additional_param4;
|
|
$qop = $additional_param5;
|
|
$method = $additional_param6;
|
|
|
|
$URI_prefix = $additional_param7;
|
|
$URI_resource = $additional_param8;
|
|
$URI_suffix = $additional_param9;
|
|
|
|
# not needed information
|
|
|
|
$URI_server = $additional_param10;
|
|
$URI_client = $additional_param11;
|
|
}
|
|
else
|
|
{
|
|
$user = get_random_string (get_random_num (0, 12 + 1));
|
|
|
|
# special limit: (user_len + 1 + realm_len + 1 + word_buf_len) < 56
|
|
my $realm_max_len = 55 - length ($user) - 1 - length ($word_buf) - 1;
|
|
|
|
if ($realm_max_len < 1) # should never happen
|
|
{
|
|
$realm_max_len = 1;
|
|
}
|
|
|
|
$realm_max_len = min (20, $realm_max_len);
|
|
|
|
$realm = get_random_string (get_random_num (0, $realm_max_len + 1));
|
|
|
|
$nonce = $salt_buf;
|
|
|
|
if (get_random_num (0, 1 + 1) == 1)
|
|
{
|
|
$qop = "auth";
|
|
|
|
$nonce_count = get_random_string (get_random_num (0, 10 + 1));
|
|
$nonce_client = get_random_string (get_random_num (0, 12 + 1));
|
|
}
|
|
else
|
|
{
|
|
$qop = "";
|
|
|
|
$nonce_count = "";
|
|
$nonce_client = "";
|
|
}
|
|
|
|
$method = get_random_string (get_random_num (0, 24 + 1));
|
|
|
|
$URI_prefix = get_random_string (get_random_num (0, 10 + 1));
|
|
$URI_resource = get_random_string (get_random_num (1, 32 + 1));
|
|
$URI_suffix = get_random_string (get_random_num (0, 32 + 1));
|
|
|
|
# not needed information
|
|
|
|
$URI_server = get_random_string (get_random_num (0, 32 + 1));
|
|
$URI_client = $URI_resource; # simplification
|
|
}
|
|
|
|
# start
|
|
|
|
$URI = "";
|
|
|
|
if (length ($URI_prefix) > 0)
|
|
{
|
|
$URI = $URI_prefix . ":";
|
|
}
|
|
|
|
$URI .= $URI_resource;
|
|
|
|
if (length ($URI_suffix) > 0)
|
|
{
|
|
$URI .= ":" . $URI_suffix;
|
|
}
|
|
|
|
my $HA2 = md5_hex ($method . ":" . $URI);
|
|
|
|
my $HA1 = md5_hex ($user . ":" . $realm . ":" . $word_buf);
|
|
|
|
my $tmp_buf;
|
|
|
|
if (($qop eq "auth") || ($qop eq "auth-int"))
|
|
{
|
|
$tmp_buf = $nonce . ":" . $nonce_count . ":" . $nonce_client . ":" . $qop;
|
|
}
|
|
else
|
|
{
|
|
$tmp_buf = $nonce;
|
|
}
|
|
|
|
my $hash_buf = md5_hex ($HA1 . ":" . $tmp_buf . ":" . $HA2);
|
|
|
|
$tmp_hash = sprintf ("\$sip\$*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s", $URI_server, $URI_resource, $user, $realm, $method, $URI_prefix, $URI_resource, $URI_suffix, $nonce, $nonce_client, $nonce_count, $qop, $directive, $hash_buf);
|
|
}
|
|
elsif ($mode == 11500)
|
|
{
|
|
$hash_buf = crc32 ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%08x:00000000", $hash_buf);
|
|
}
|
|
elsif ($mode == 11600)
|
|
{
|
|
my ($p, $num_cycle_power, $seven_zip_salt_len, $seven_zip_salt_buf, $salt_len, $data_len, $unpack_size, $data_buf);
|
|
|
|
$p = 0; # is fixed
|
|
|
|
my $validation_only = 0;
|
|
|
|
$validation_only = 1 if (defined ($additional_param));
|
|
|
|
if ($validation_only == 1)
|
|
{
|
|
$num_cycle_power = int ($iter);
|
|
$seven_zip_salt_len = $additional_param;
|
|
$seven_zip_salt_buf = $additional_param2;
|
|
$salt_len = $additional_param3;
|
|
# $salt_buf set in parser
|
|
# $hash_buf (resulting crc)
|
|
$data_len = $additional_param4;
|
|
$unpack_size = $additional_param5;
|
|
$data_buf = $additional_param6;
|
|
}
|
|
else
|
|
{
|
|
$num_cycle_power = 14; # by default it is 19
|
|
$seven_zip_salt_len = 0;
|
|
$seven_zip_salt_buf = "";
|
|
$salt_len = length ($salt_buf);
|
|
# $salt_buf set automatically
|
|
# $hash_buf (resulting crc)
|
|
# $data_len will be set when encrypting
|
|
$unpack_size = get_random_num (1, 32 + 1);
|
|
$data_buf = get_random_string ($unpack_size);
|
|
}
|
|
|
|
#
|
|
# 2 ^ NumCyclesPower "iterations" of SHA256 (only one final SHA256)
|
|
#
|
|
|
|
$word_buf = encode ("UTF-16LE", $word_buf);
|
|
|
|
my $rounds = 1 << $num_cycle_power;
|
|
|
|
my $pass_buf = "";
|
|
|
|
for (my $i = 0; $i < $rounds; $i++)
|
|
{
|
|
my $num_buf = "";
|
|
|
|
$num_buf .= pack ("V", $i);
|
|
$num_buf .= "\x00" x 4;
|
|
|
|
# this would be better but only works on 64-bit systems:
|
|
# $num_buf = pack ("q", $i);
|
|
|
|
$pass_buf .= sprintf ("%s%s", $word_buf, $num_buf);
|
|
}
|
|
|
|
my $key = sha256 ($pass_buf);
|
|
|
|
# the salt_buf is our IV for AES CBC
|
|
# pad the salt_buf
|
|
|
|
my $salt_buf_len = length ($salt_buf);
|
|
my $salt_padding_len = 0;
|
|
|
|
if ($salt_buf_len < 16)
|
|
{
|
|
$salt_padding_len = 16 - $salt_buf_len;
|
|
}
|
|
|
|
$salt_buf .= "\x00" x $salt_padding_len;
|
|
|
|
my $aes = Crypt::CBC->new ({
|
|
cipher => "Crypt::Rijndael",
|
|
key => $key,
|
|
keysize => 32,
|
|
literal_key => 1,
|
|
iv => $salt_buf,
|
|
header => "none",
|
|
});
|
|
|
|
if ($validation_only == 1)
|
|
{
|
|
# decrypt
|
|
|
|
my $decrypted_data = $aes->decrypt ($data_buf);
|
|
|
|
$decrypted_data = substr ($decrypted_data, 0, $unpack_size);
|
|
|
|
$hash_buf = crc32 ($decrypted_data);
|
|
}
|
|
else
|
|
{
|
|
# encrypt
|
|
|
|
$hash_buf = crc32 ($data_buf);
|
|
|
|
$data_buf = $aes->encrypt ($data_buf);
|
|
|
|
$data_len = length ($data_buf);
|
|
}
|
|
|
|
$tmp_hash = sprintf ("\$7z\$%i\$%i\$%i\$%s\$%i\$%08s\$%u\$%u\$%u\$%s", $p, $num_cycle_power, $seven_zip_salt_len, $seven_zip_salt_buf, $salt_len, unpack ("H*", $salt_buf), $hash_buf, $data_len, $unpack_size, unpack ("H*", $data_buf));
|
|
}
|
|
elsif ($mode == 11700)
|
|
{
|
|
# PyGOST outputs digests in little-endian order, while the kernels
|
|
# expect them in big-endian; hence the digest[::-1] mirroring.
|
|
# Using sys.stdout.write instead of print to disable \n character.
|
|
my $python_code = <<"END_CODE";
|
|
|
|
import binascii
|
|
import sys
|
|
from pygost import gost34112012256
|
|
digest = gost34112012256.new(b"$word_buf").digest()
|
|
sys.stdout.write(binascii.hexlify(digest[::-1]))
|
|
|
|
END_CODE
|
|
|
|
$tmp_hash = `python2 -c '$python_code'`;
|
|
}
|
|
elsif ($mode == 11750)
|
|
{
|
|
my $python_code = <<"END_CODE";
|
|
|
|
import binascii
|
|
import hmac
|
|
import sys
|
|
from pygost import gost34112012256
|
|
key = b"$word_buf"
|
|
msg = b"$salt_buf"
|
|
digest = hmac.new(key, msg, gost34112012256).digest()
|
|
sys.stdout.write(binascii.hexlify(digest[::-1]))
|
|
|
|
END_CODE
|
|
|
|
$hash_buf = `python2 -c '$python_code'`;
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 11760)
|
|
{
|
|
my $python_code = <<"END_CODE";
|
|
|
|
import binascii
|
|
import hmac
|
|
import sys
|
|
from pygost import gost34112012256
|
|
key = b"$salt_buf"
|
|
msg = b"$word_buf"
|
|
digest = hmac.new(key, msg, gost34112012256).digest()
|
|
sys.stdout.write(binascii.hexlify(digest[::-1]))
|
|
|
|
END_CODE
|
|
|
|
$hash_buf = `python2 -c '$python_code'`;
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 11800)
|
|
{
|
|
my $python_code = <<"END_CODE";
|
|
|
|
import binascii
|
|
import sys
|
|
from pygost import gost34112012512
|
|
digest = gost34112012512.new(b"$word_buf").digest()
|
|
sys.stdout.write(binascii.hexlify(digest[::-1]))
|
|
|
|
END_CODE
|
|
|
|
$tmp_hash = `python2 -c '$python_code'`;
|
|
}
|
|
elsif ($mode == 11850)
|
|
{
|
|
my $python_code = <<"END_CODE";
|
|
|
|
import binascii
|
|
import hmac
|
|
import sys
|
|
from pygost import gost34112012512
|
|
key = b"$word_buf"
|
|
msg = b"$salt_buf"
|
|
digest = hmac.new(key, msg, gost34112012512).digest()
|
|
sys.stdout.write(binascii.hexlify(digest[::-1]))
|
|
|
|
END_CODE
|
|
|
|
$hash_buf = `python2 -c '$python_code'`;
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 11860)
|
|
{
|
|
my $python_code = <<"END_CODE";
|
|
|
|
import binascii
|
|
import hmac
|
|
import sys
|
|
from pygost import gost34112012512
|
|
key = b"$salt_buf"
|
|
msg = b"$word_buf"
|
|
digest = hmac.new(key, msg, gost34112012512).digest()
|
|
sys.stdout.write(binascii.hexlify(digest[::-1]))
|
|
|
|
END_CODE
|
|
|
|
$hash_buf = `python2 -c '$python_code'`;
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 11900)
|
|
{
|
|
my $iterations = 1000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $out_len = 32;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$out_len = $additional_param;
|
|
}
|
|
|
|
#
|
|
# call PHP here - WTF
|
|
#
|
|
|
|
# sanitize $word_buf and $salt_buf:
|
|
|
|
my $word_buf_base64 = encode_base64 ($word_buf, "");
|
|
my $salt_buf_base64 = encode_base64 ($salt_buf, "");
|
|
|
|
# sanitize lenghs
|
|
|
|
$out_len = int ($out_len);
|
|
|
|
# output is in hex encoding, otherwise it could be screwed (but shouldn't)
|
|
|
|
my $php_code = <<'END_CODE';
|
|
|
|
function pbkdf2 ($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
|
|
{
|
|
$algorithm = strtolower ($algorithm);
|
|
|
|
if (! in_array ($algorithm, hash_algos (), true))
|
|
{
|
|
trigger_error ("PBKDF2 ERROR: Invalid hash algorithm.", E_USER_ERROR);
|
|
}
|
|
|
|
if ($count <= 0 || $key_length <= 0)
|
|
{
|
|
trigger_error ("PBKDF2 ERROR: Invalid parameters.", E_USER_ERROR);
|
|
}
|
|
|
|
if (function_exists ("hash_pbkdf2"))
|
|
{
|
|
if (!$raw_output)
|
|
{
|
|
$key_length = $key_length * 2;
|
|
}
|
|
|
|
return hash_pbkdf2 ($algorithm, $password, $salt, $count, $key_length, $raw_output);
|
|
}
|
|
|
|
$hash_length = strlen (hash ($algorithm, "", true));
|
|
$block_count = ceil ($key_length / $hash_length);
|
|
|
|
$output = "";
|
|
|
|
for ($i = 1; $i <= $block_count; $i++)
|
|
{
|
|
$last = $salt . pack ("N", $i);
|
|
|
|
$last = $xorsum = hash_hmac ($algorithm, $last, $password, true);
|
|
|
|
for ($j = 1; $j < $count; $j++)
|
|
{
|
|
$xorsum ^= ($last = hash_hmac ($algorithm, $last, $password, true));
|
|
}
|
|
|
|
$output .= $xorsum;
|
|
}
|
|
|
|
if ($raw_output)
|
|
{
|
|
return substr ($output, 0, $key_length);
|
|
}
|
|
else
|
|
{
|
|
return bin2hex (substr ($output, 0, $key_length));
|
|
}
|
|
}
|
|
|
|
print pbkdf2 ("md5", base64_decode ("$word_buf_base64"), base64_decode ("$salt_buf_base64"), $iterations, $out_len, False);
|
|
|
|
END_CODE
|
|
|
|
# replace with these command line arguments
|
|
|
|
$php_code =~ s/\$word_buf_base64/$word_buf_base64/;
|
|
$php_code =~ s/\$salt_buf_base64/$salt_buf_base64/;
|
|
$php_code =~ s/\$iterations/$iterations/;
|
|
$php_code =~ s/\$out_len/$out_len/;
|
|
|
|
my $php_output = `php -r '$php_code'`;
|
|
|
|
$hash_buf = pack ("H*", $php_output);
|
|
|
|
$hash_buf = encode_base64 ($hash_buf, "");
|
|
|
|
my $base64_salt_buf = encode_base64 ($salt_buf, "");
|
|
|
|
$tmp_hash = sprintf ("md5:%i:%s:%s", $iterations, $base64_salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 12000)
|
|
{
|
|
my $iterations = 1000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $out_len = 16;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$out_len = $additional_param;
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1'),
|
|
iterations => $iterations,
|
|
output_len => $out_len
|
|
);
|
|
|
|
$hash_buf = encode_base64 ($pbkdf2->PBKDF2 ($salt_buf, $word_buf), "");
|
|
|
|
my $base64_salt_buf = encode_base64 ($salt_buf, "");
|
|
|
|
$tmp_hash = sprintf ("sha1:%i:%s:%s", $iterations, $base64_salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 12001)
|
|
{
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1'),
|
|
iterations => 10000,
|
|
output_len => 32
|
|
);
|
|
|
|
my $base64_buf = encode_base64 ($salt_buf . $pbkdf2->PBKDF2 ($salt_buf, $word_buf), "");
|
|
|
|
$tmp_hash = sprintf ("{PKCS5S2}%s", $base64_buf);
|
|
}
|
|
elsif ($mode == 12100)
|
|
{
|
|
my $iterations = 1000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $out_len = 16;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$out_len = $additional_param;
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 512),
|
|
iterations => $iterations,
|
|
output_len => $out_len
|
|
);
|
|
|
|
$hash_buf = encode_base64 ($pbkdf2->PBKDF2 ($salt_buf, $word_buf), "");
|
|
|
|
my $base64_salt_buf = encode_base64 ($salt_buf, "");
|
|
|
|
$tmp_hash = sprintf ("sha512:%i:%s:%s", $iterations, $base64_salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 12200)
|
|
{
|
|
my $iterations = 65536;
|
|
|
|
my $default_salt = 0;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$default_salt = int ($additional_param);
|
|
}
|
|
|
|
if ($default_salt == 1)
|
|
{
|
|
$salt_buf = "0011223344556677";
|
|
}
|
|
|
|
$hash_buf = sha512 (pack ("H*", $salt_buf) . $word_buf);
|
|
|
|
for (my $i = 0; $i < $iterations; $i++)
|
|
{
|
|
$hash_buf = sha512 ($hash_buf);
|
|
}
|
|
|
|
$hash_buf = unpack ("H*", $hash_buf);
|
|
$hash_buf = substr ($hash_buf, 0, 16);
|
|
|
|
if ($default_salt == 0)
|
|
{
|
|
$tmp_hash = sprintf ("\$ecryptfs\$0\$1\$%s\$%s", $salt_buf, $hash_buf);
|
|
}
|
|
else
|
|
{
|
|
$tmp_hash = sprintf ("\$ecryptfs\$0\$%s", $hash_buf);
|
|
}
|
|
}
|
|
elsif ($mode == 12300)
|
|
{
|
|
my $iterations = 4096;
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 512);
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
output_len => 64
|
|
);
|
|
|
|
my $salt_bin = pack ("H*", $salt_buf);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt_bin. "AUTH_PBKDF2_SPEEDY_KEY", $word_buf);
|
|
|
|
$hash_buf = sha512_hex ($key . $salt_bin);
|
|
|
|
$tmp_hash = sprintf ("%s%s", uc ($hash_buf), uc ($salt_buf));
|
|
}
|
|
elsif ($mode == 12400)
|
|
{
|
|
my $iterations;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
else
|
|
{
|
|
$iterations = get_random_num (1, 5001 + 1);
|
|
}
|
|
|
|
my $key_value = fold_password ($word_buf);
|
|
|
|
my $data = "\x00\x00\x00\x00\x00\x00\x00\x00";
|
|
my $salt_value = base64_to_int24 ($salt_buf);
|
|
|
|
$hash_buf = crypt_rounds ($key_value, $iterations, $salt_value, $data);
|
|
|
|
$tmp_hash = sprintf ("_%s%s%s", int24_to_base64 ($iterations), $salt_buf, block_to_base64 ($hash_buf));
|
|
}
|
|
elsif ($mode == 12600)
|
|
{
|
|
$hash_buf = sha1_hex ($word_buf);
|
|
|
|
$hash_buf = sha256_hex ($salt_buf . uc $hash_buf);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 12700)
|
|
{
|
|
my $iterations = 10;
|
|
|
|
my $data = qq|{
|
|
"guid" : "00000000-0000-0000-0000-000000000000",
|
|
"sharedKey" : "00000000-0000-0000-0000-000000000000",
|
|
"options" : {"pbkdf2_iterations":10,"fee_policy":0,"html5_notifications":false,"logout_time":600000,"tx_display":0,"always_keep_local_backup":false}|;
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1');
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt_buf_bin, $word_buf);
|
|
|
|
my $cipher = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $salt_buf_bin,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32
|
|
});
|
|
|
|
my $encrypted = unpack ("H*", $cipher->encrypt ($data));
|
|
|
|
$tmp_hash = sprintf ("\$blockchain\$%s\$%s", length ($salt_buf . $encrypted) / 2, $salt_buf . $encrypted);
|
|
}
|
|
elsif ($mode == 12800)
|
|
{
|
|
my $iterations = 100;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $nt = md4_hex (encode ("UTF-16LE", $word_buf));
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $hash = $pbkdf2->PBKDF2 ($salt_buf_bin, uc (encode ("UTF-16LE", $nt)));
|
|
|
|
$tmp_hash = sprintf ("v1;PPH1_MD4,%s,%d,%s", $salt_buf, $iterations, unpack ("H*", $hash));
|
|
}
|
|
elsif ($mode == 12900)
|
|
{
|
|
my $iterations = 4096;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $salt2 = $salt_buf . $salt_buf;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$salt2 = $additional_param;
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $hash = $pbkdf2->PBKDF2 ($salt_buf_bin, $word_buf);
|
|
|
|
my $salt2_bin = pack ("H*", $salt2);
|
|
|
|
my $hash_hmac = hmac_hex ($salt2_bin, $hash, \&sha256, 64);
|
|
|
|
$tmp_hash = sprintf ("%s%s%s", $salt2, $hash_hmac, $salt_buf);
|
|
}
|
|
elsif ($mode == 13000)
|
|
{
|
|
my $iterations = 15;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $iv = "0" x 32;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$iv = $additional_param;
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => (1 << $iterations) + 32,
|
|
output_len => 32
|
|
);
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $hash = $pbkdf2->PBKDF2 ($salt_buf_bin, $word_buf);
|
|
|
|
my $hash_final = substr ($hash, 0, 8)
|
|
^ substr ($hash, 8, 8)
|
|
^ substr ($hash, 16, 8)
|
|
^ substr ($hash, 24, 8);
|
|
|
|
$tmp_hash = sprintf ('$rar5$16$%s$%d$%s$8$%s', $salt_buf, $iterations, $iv, unpack ("H*", $hash_final));
|
|
}
|
|
elsif ($mode == 13100)
|
|
{
|
|
my @salt_arr = split ('\$', $salt_buf);
|
|
|
|
my $user = $salt_arr[0];
|
|
|
|
my $realm = $salt_arr[1];
|
|
|
|
my $spn = $salt_arr[2];
|
|
|
|
my $k = md4 (encode ("UTF-16LE", $word_buf));
|
|
|
|
my $k1 = hmac_md5 ("\x02\x00\x00\x00", $k);
|
|
|
|
my $cleartext_ticket = '6381b03081ada00703050050a00000a11b3019a003020117a1'.
|
|
'12041058e0d77776e8b8e03991f2966939222aa2171b154d594b5242544553542e434f4e5'.
|
|
'44f534f2e434f4da3133011a003020102a10a30081b067472616e6365a40b3009a0030201'.
|
|
'01a1020400a511180f32303136303231353134343735305aa611180f32303136303231353'.
|
|
'134343735305aa711180f32303136303231363030343735305aa811180f32303136303232'.
|
|
'323134343735305a';
|
|
|
|
my $checksum = "";
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$checksum = pack ("H*", $additional_param);
|
|
}
|
|
else
|
|
{
|
|
my $nonce = $salt_arr[3];
|
|
|
|
$cleartext_ticket = $nonce . $cleartext_ticket;
|
|
|
|
$checksum = hmac_md5 (pack ("H*", $cleartext_ticket), $k1);
|
|
}
|
|
|
|
my $k3 = hmac_md5 ($checksum, $k1);
|
|
|
|
my $edata2 = "";
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$edata2 = $additional_param2;
|
|
|
|
my $cipher_decrypt = Crypt::RC4->new ($k3);
|
|
|
|
my $ticket_decrypt = unpack ("H*", $cipher_decrypt->RC4 (pack ("H*", $edata2)));
|
|
|
|
my $check_correct = ((substr ($ticket_decrypt, 16, 4) eq "6381" && substr ($ticket_decrypt, 22, 2) eq "30") ||
|
|
(substr ($ticket_decrypt, 16, 4) eq "6382")) &&
|
|
((substr ($ticket_decrypt, 32, 6) eq "030500") ||
|
|
(substr ($ticket_decrypt, 32, 8) eq "050307A0"));
|
|
|
|
if ($check_correct == 1)
|
|
{
|
|
$cleartext_ticket = $ticket_decrypt;
|
|
}
|
|
else # validation failed
|
|
{
|
|
# fake/wrong ticket (otherwise if we just decrypt/encrypt we end up with false positives all the time)
|
|
$cleartext_ticket = "0" x (length ($cleartext_ticket) + 16);
|
|
}
|
|
}
|
|
|
|
my $cipher = Crypt::RC4->new ($k3);
|
|
|
|
$edata2 = $cipher->RC4 (pack ("H*", $cleartext_ticket));
|
|
|
|
$tmp_hash = sprintf ('$krb5tgs$23$*%s$%s$%s*$%s$%s', $user, $realm, $spn, unpack ("H*", $checksum), unpack ("H*", $edata2));
|
|
}
|
|
elsif ($mode == 13200)
|
|
{
|
|
my @salt_arr = split ('\*', $salt_buf);
|
|
|
|
my $iteration = $salt_arr[0];
|
|
|
|
my $mysalt = $salt_arr[1];
|
|
|
|
$mysalt = pack ("H*", $mysalt);
|
|
|
|
my $iv = "a6a6a6a6a6a6a6a6";
|
|
|
|
my $KEK = sha1 ($word_buf);
|
|
|
|
$KEK = substr ($KEK ^ $mysalt, 0, 16);
|
|
|
|
my $aes = Crypt::Mode::ECB->new ('AES');
|
|
|
|
my $B;
|
|
|
|
my $A;
|
|
|
|
my @R = ();
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$additional_param = pack ("H*", $additional_param);
|
|
|
|
$A = substr ($additional_param, 0, 8);
|
|
$B = 0x00 x 8;
|
|
|
|
$R[1] = substr ($additional_param, 8, 8);
|
|
$R[2] = substr ($additional_param, 16, 8);
|
|
|
|
for (my $j = $iteration - 1; $j >= 0; $j--)
|
|
{
|
|
$A = substr ($A, 0, 8) ^ pack ("l", (2 * $j + 2));
|
|
|
|
$B = $R[2];
|
|
|
|
$A = $aes->decrypt ($A . $B . "\x00" x 16, $KEK);
|
|
|
|
$R[2] = substr ($A, 8, 16);
|
|
|
|
$A = substr ($A, 0, 8) ^ pack ("l", (2 * $j + 1));
|
|
|
|
$B = $R[1];
|
|
|
|
$A = $aes->decrypt ($A . $B . "\x00" x 16, $KEK);
|
|
|
|
$R[1] = substr ($A, 8, 16);
|
|
}
|
|
|
|
# check if valid
|
|
if (index ($A, "\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6") != 0)
|
|
{
|
|
# fake wrong @R and $A values
|
|
|
|
@R = ('', "\x00" x 8, "\x00" x 8);
|
|
|
|
$A = "\x00" x 16;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $DEK = randbytes (16);
|
|
|
|
@R = ('', substr (pack ("H*", $DEK), 0, 8), substr (pack ("H*", $DEK), 8, 16));
|
|
|
|
$A = pack ("H*", $iv);
|
|
}
|
|
|
|
for (my $j = 0; $j < $iteration; $j++)
|
|
{
|
|
$B = $aes->encrypt ($A . $R[1], $KEK);
|
|
|
|
$A = substr ($B, 0, 8) ^ pack ("q", (2 * $j + 1));
|
|
|
|
$R[1] = substr ($B, 8, 16);
|
|
|
|
$B = $aes->encrypt ($A . $R[2], $KEK);
|
|
|
|
$A = substr ($B, 0, 8) ^ pack ("q", (2 * $j + 2));
|
|
|
|
$R[2] = substr ($B, 8, 16);
|
|
}
|
|
|
|
my $wrapped_key = unpack ("H*", $A . substr ($R[1], 0 ,8) . substr ($R[2], 0 ,8));
|
|
|
|
$mysalt = unpack ("H*", $mysalt);
|
|
|
|
$tmp_hash = sprintf ('$axcrypt$*1*%s*%s*%s', $iteration, $mysalt, $wrapped_key);
|
|
}
|
|
elsif ($mode == 13300)
|
|
{
|
|
my $length = 32;
|
|
|
|
if ($additional_param)
|
|
{
|
|
$length = $additional_param;
|
|
}
|
|
|
|
$hash_buf = sha1_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ('$axcrypt_sha1$%s', substr ($hash_buf, 0, $length));
|
|
}
|
|
elsif ($mode == 13400)
|
|
{
|
|
my @salt_arr = split ('\*', $salt_buf);
|
|
|
|
my $version = $salt_arr[0];
|
|
|
|
my $iteration = $salt_arr[1];
|
|
|
|
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;
|
|
|
|
# specific to version 1
|
|
my $inline_flag;
|
|
my $contents_len;
|
|
my $contents;
|
|
|
|
# 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);
|
|
|
|
$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);
|
|
}
|
|
|
|
my $aes = Crypt::Mode::ECB->new ('AES', 1);
|
|
|
|
for (my $j = 0; $j < $iteration; $j++)
|
|
{
|
|
$intermediate_hash = $aes->encrypt ($intermediate_hash, $transf_random_seed);
|
|
|
|
$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)
|
|
{
|
|
$final_algorithm = "Crypt::Twofish";
|
|
}
|
|
else
|
|
{
|
|
$final_algorithm = "Crypt::Rijndael";
|
|
}
|
|
|
|
my $cipher = Crypt::CBC->new ({
|
|
key => $final_key,
|
|
cipher => $final_algorithm,
|
|
iv => $enc_iv,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32
|
|
});
|
|
|
|
if ($version == 1)
|
|
{
|
|
if (defined $additional_param)
|
|
{
|
|
# if we try to verify the crack, we need to decrypt the contents instead of only encrypting it:
|
|
|
|
$contents = $cipher->decrypt ($contents);
|
|
|
|
# and check the output
|
|
|
|
my $contents_hash_old = $contents_hash;
|
|
|
|
$contents_hash = sha256 ($contents);
|
|
|
|
if ($contents_hash_old ne $contents_hash)
|
|
{
|
|
# fake content
|
|
$contents = "\x00" x length ($contents);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$contents_hash = sha256 ($contents);
|
|
}
|
|
|
|
$contents = $cipher->encrypt ($contents);
|
|
|
|
$tmp_hash = sprintf ('$keepass$*%d*%d*%d*%s*%s*%s*%s*%d*%d*%s%s',
|
|
$version,
|
|
$iteration,
|
|
$algorithm,
|
|
unpack ("H*", $final_random_seed),
|
|
unpack ("H*", $transf_random_seed),
|
|
unpack ("H*", $enc_iv),
|
|
unpack ("H*", $contents_hash),
|
|
$inline_flag,
|
|
$contents_len,
|
|
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%s',
|
|
$version,
|
|
$iteration,
|
|
$algorithm,
|
|
unpack ("H*", $final_random_seed),
|
|
unpack ("H*", $transf_random_seed),
|
|
unpack ("H*", $enc_iv),
|
|
unpack ("H*", $expected_bytes),
|
|
unpack ("H*", $contents_hash),
|
|
$keyfile_attributes);
|
|
}
|
|
}
|
|
elsif ($mode == 13500)
|
|
{
|
|
$hash_buf = sha1_hex (pack ("H*", $salt_buf) . encode ("UTF-16LE", $word_buf));
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 13600)
|
|
{
|
|
my $iterations = 1000;
|
|
|
|
my $type = 0;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$type = $additional_param;
|
|
}
|
|
|
|
my $mode = 1 + int rand (3);
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$mode = $additional_param2;
|
|
}
|
|
|
|
my $magic = 0;
|
|
|
|
if (defined $additional_param3)
|
|
{
|
|
$magic = $additional_param3;
|
|
}
|
|
|
|
if (defined $additional_param4)
|
|
{
|
|
$salt_buf = $additional_param4;
|
|
}
|
|
|
|
$salt_buf = substr ($salt_buf, 0, 8 + ($mode * 8));
|
|
|
|
my $compress_length = 0;
|
|
|
|
if (defined $additional_param5)
|
|
{
|
|
$compress_length = $additional_param5;
|
|
}
|
|
|
|
my $data = "";
|
|
|
|
if (defined $additional_param6)
|
|
{
|
|
$data = $additional_param6;
|
|
}
|
|
|
|
my $key_len = (8 * ($mode & 3) + 8) * 2;
|
|
|
|
my $out_len = $key_len + 2;
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1');
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
output_len => $out_len
|
|
);
|
|
|
|
my $key = $pbkdf2->PBKDF2_hex ($salt_buf_bin, $word_buf);
|
|
|
|
my $verify_bytes = substr ($key, -4); $verify_bytes =~ s/^0+//; #lol
|
|
|
|
$key = substr ($key, $key_len, $key_len);
|
|
|
|
my $key_bin = pack ("H*", $key);
|
|
|
|
my $auth = hmac_hex ($data, $key_bin, \&sha1, 64);
|
|
|
|
$tmp_hash = sprintf ('$zip2$*%u*%u*%u*%s*%s*%u*%s*%s*$/zip2$', $type, $mode, $magic, $salt_buf, $verify_bytes, $compress_length, $data, substr ($auth, 0, 20));
|
|
}
|
|
elsif ($mode == 13800)
|
|
{
|
|
my $word_buf_utf16le = encode ("UTF-16LE", $word_buf);
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
$hash_buf = sha256_hex ($word_buf_utf16le . $salt_buf_bin);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 14000)
|
|
{
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $cipher = new Crypt::DES $word_buf;
|
|
|
|
my $hash_buf = $cipher->encrypt ($salt_buf_bin);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", unpack ("H*", $hash_buf), $salt_buf);
|
|
}
|
|
elsif ($mode == 14100)
|
|
{
|
|
my $word_buf1 = substr ($word_buf, 0, 8);
|
|
my $word_buf2 = substr ($word_buf, 8, 8);
|
|
my $word_buf3 = substr ($word_buf, 16, 8);
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $cipher1 = new Crypt::DES $word_buf1;
|
|
|
|
my $hash_buf1 = $cipher1->encrypt ($salt_buf_bin);
|
|
|
|
my $cipher2 = new Crypt::DES $word_buf2;
|
|
|
|
my $hash_buf2 = $cipher2->decrypt ($hash_buf1);
|
|
|
|
my $cipher3 = new Crypt::DES $word_buf3;
|
|
|
|
my $hash_buf3 = $cipher3->encrypt ($hash_buf2);
|
|
|
|
$tmp_hash = sprintf ("%s:%s", unpack ("H*", $hash_buf3), $salt_buf);
|
|
}
|
|
elsif ($mode == 14400)
|
|
{
|
|
my $begin = "--" . $salt_buf . "--";
|
|
my $end = "--" . $word_buf . "----";
|
|
|
|
my $hash_buf = sha1_hex ($begin . $end);
|
|
|
|
for (my $round = 1; $round < 10; $round++)
|
|
{
|
|
$hash_buf = sha1_hex ($begin . $hash_buf . $end);
|
|
}
|
|
|
|
$tmp_hash = sprintf ("%s:%s", $hash_buf, $salt_buf);
|
|
}
|
|
elsif ($mode == 14700)
|
|
{
|
|
my $iterations = 10000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1'),
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
$salt_buf = pack ("H*", $salt_buf);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt_buf, $word_buf);
|
|
|
|
my $ITUNES_BACKUP_KEY = 12008468691120727718;
|
|
|
|
my $WPKY = "\x00" x 40;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
my ($A, $R) = itunes_aes_unwrap ($key, $additional_param);
|
|
|
|
if ($A == $ITUNES_BACKUP_KEY)
|
|
{
|
|
$WPKY = itunes_aes_wrap ($key, $A, $R);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $max_number = 18446744073709551615; # 0xffffffffffffffff
|
|
|
|
my @R;
|
|
|
|
for (my $i = 0; $i < 4; $i++)
|
|
{
|
|
$R[$i] = get_random_num (0, $max_number);
|
|
}
|
|
|
|
$WPKY = itunes_aes_wrap ($key, $ITUNES_BACKUP_KEY, \@R);
|
|
}
|
|
|
|
$tmp_hash = sprintf ("\$itunes_backup\$*9*%s*%i*%s**", unpack ("H*", $WPKY), $iterations, unpack ("H*", $salt_buf));
|
|
}
|
|
elsif ($mode == 14800)
|
|
{
|
|
my $iterations = 10000;
|
|
|
|
if (length ($iter))
|
|
{
|
|
$iterations = int ($iter);
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1'),
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
$salt_buf = pack ("H*", $salt_buf);
|
|
|
|
my $ITUNES_BACKUP_KEY = 12008468691120727718;
|
|
|
|
my $DPIC;
|
|
my $DPSL;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$DPIC = $additional_param2;
|
|
$DPSL = $additional_param3;
|
|
}
|
|
else
|
|
{
|
|
#$DPIC = 10000000; it's too much for the tests
|
|
$DPIC = 1000;
|
|
$DPSL = randbytes (20);
|
|
}
|
|
|
|
my $WPKY = "\x00" x 40;
|
|
|
|
my $pbkdf2x = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2'),
|
|
iterations => $DPIC,
|
|
output_len => 32
|
|
);
|
|
|
|
my $key_dpsl = $pbkdf2x->PBKDF2 ($DPSL, $word_buf);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt_buf, $key_dpsl);
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
my ($A, $R) = itunes_aes_unwrap ($key, $additional_param);
|
|
|
|
if ($A == $ITUNES_BACKUP_KEY)
|
|
{
|
|
$WPKY = itunes_aes_wrap ($key, $A, $R);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $max_number = 18446744073709551615; # 0xffffffffffffffff
|
|
|
|
my @R;
|
|
|
|
for (my $i = 0; $i < 4; $i++)
|
|
{
|
|
$R[$i] = get_random_num (0, $max_number);
|
|
}
|
|
|
|
$WPKY = itunes_aes_wrap ($key, $ITUNES_BACKUP_KEY, \@R);
|
|
}
|
|
|
|
$tmp_hash = sprintf ("\$itunes_backup\$*10*%s*%i*%s*%i*%s", unpack ("H*", $WPKY), $iterations, unpack ("H*", $salt_buf), $DPIC, unpack ("H*", $DPSL));
|
|
}
|
|
elsif ($mode == 14900)
|
|
{
|
|
my $salt_bin = pack ("H*", $salt_buf);
|
|
|
|
my $skip32 = Crypt::Skip32->new ($word_buf);
|
|
|
|
my $hash = $skip32->encrypt ($salt_bin);
|
|
|
|
$tmp_hash = sprintf ("%08x:%s", unpack ("N*", $hash), $salt_buf);
|
|
}
|
|
elsif ($mode == 15100)
|
|
{
|
|
my $iterations = 20000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
my $pbkdf1_salt_buf = sprintf ('%s$sha1$%u', $salt_buf, $iterations);
|
|
|
|
my $tmp = hmac ($pbkdf1_salt_buf, $word_buf, \&sha1, 64);
|
|
|
|
for (my $r = 1; $r < $iterations; $r++)
|
|
{
|
|
$tmp = hmac ($tmp, $word_buf, \&sha1, 64);
|
|
}
|
|
|
|
my $hash_buf = "";
|
|
|
|
$hash_buf .= to64 ((int (ord (substr ($tmp, 0, 1))) << 16) | (int (ord (substr ($tmp, 1, 1))) << 8) | (int (ord (substr ($tmp, 2, 1)))), 4);
|
|
$hash_buf .= to64 ((int (ord (substr ($tmp, 3, 1))) << 16) | (int (ord (substr ($tmp, 4, 1))) << 8) | (int (ord (substr ($tmp, 5, 1)))), 4);
|
|
$hash_buf .= to64 ((int (ord (substr ($tmp, 6, 1))) << 16) | (int (ord (substr ($tmp, 7, 1))) << 8) | (int (ord (substr ($tmp, 8, 1)))), 4);
|
|
$hash_buf .= to64 ((int (ord (substr ($tmp, 9, 1))) << 16) | (int (ord (substr ($tmp, 10, 1))) << 8) | (int (ord (substr ($tmp, 11, 1)))), 4);
|
|
$hash_buf .= to64 ((int (ord (substr ($tmp, 12, 1))) << 16) | (int (ord (substr ($tmp, 13, 1))) << 8) | (int (ord (substr ($tmp, 14, 1)))), 4);
|
|
$hash_buf .= to64 ((int (ord (substr ($tmp, 15, 1))) << 16) | (int (ord (substr ($tmp, 16, 1))) << 8) | (int (ord (substr ($tmp, 17, 1)))), 4);
|
|
$hash_buf .= to64 ((int (ord (substr ($tmp, 18, 1))) << 16) | (int (ord (substr ($tmp, 19, 1))) << 8) | 0 , 4);
|
|
|
|
## super hackish, but we have no other choice, as this byte is kind of a random byte added to the digest when the hash was created
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$hash_buf = substr ($hash_buf, 0, 24) . substr ($additional_param, 24, 4);
|
|
}
|
|
|
|
$tmp_hash = sprintf ("\$sha1\$%d\$%s\$%s", $iterations, $salt_buf, $hash_buf);
|
|
}
|
|
elsif ($mode == 15200)
|
|
{
|
|
my $iterations = 5000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
my $data = qq|{
|
|
"guid" : "00000000-0000-0000-0000-000000000000",
|
|
"sharedKey" : "00000000-0000-0000-0000-000000000000",
|
|
"options" : {"pbkdf2_iterations":$iterations,"fee_policy":0,"html5_notifications":false,"logout_time":600000,"tx_display":0,"always_keep_local_backup":false}|;
|
|
|
|
my $salt_buf_bin = pack ("H*", $salt_buf);
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1');
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($salt_buf_bin, $word_buf);
|
|
|
|
my $cipher = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $salt_buf_bin,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32
|
|
});
|
|
|
|
my $encrypted = unpack ("H*", $cipher->encrypt ($data));
|
|
|
|
$tmp_hash = sprintf ("\$blockchain\$v2\$%d\$%s\$%s", $iterations, length ($salt_buf . $encrypted) / 2, $salt_buf . $encrypted);
|
|
}
|
|
elsif ($mode == 15300 || $mode == 15900)
|
|
{
|
|
my @salt_arr = split ('\*', $salt_buf);
|
|
|
|
my $version = $salt_arr[0];
|
|
|
|
my $context = $salt_arr[1];
|
|
|
|
my $SID = $salt_arr[2];
|
|
|
|
my $cipher_algorithm = $salt_arr[3];
|
|
|
|
my $hash_algorithm = $salt_arr[4];
|
|
|
|
my $iterations = $salt_arr[5];
|
|
|
|
my $salt = pack ("H*", $salt_arr[6]);
|
|
|
|
my $cipher_len = $salt_arr[7];
|
|
|
|
my $cipher;
|
|
|
|
# intermediate values
|
|
|
|
my $user_hash;
|
|
my $user_derivationKey;
|
|
my $encKey;
|
|
my $expected_hmac;
|
|
my $cleartext;
|
|
|
|
if ($context == 1)
|
|
{
|
|
$user_hash = sha1 (encode ("UTF-16LE", $word_buf));
|
|
}
|
|
elsif ($context == 2)
|
|
{
|
|
$user_hash = md4 (encode ("UTF-16LE", $word_buf));
|
|
}
|
|
|
|
$user_derivationKey = hmac_sha1 (encode ("UTF-16LE", $SID . "\x00"), $user_hash);
|
|
|
|
my $hmacSalt = randbytes (16);
|
|
my $last_key = randbytes (64);
|
|
|
|
if ($version == 1)
|
|
{
|
|
$encKey = hmac_sha1 ($hmacSalt, $user_derivationKey);
|
|
$expected_hmac = hmac_sha1 ($last_key, $encKey);
|
|
|
|
# need padding because keyLen is 24 and hashLen 20
|
|
$expected_hmac = $expected_hmac . randbytes (4);
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
$encKey = hmac_sha512 ($hmacSalt, $user_derivationKey);
|
|
$expected_hmac = hmac_sha512 ($last_key, $encKey);
|
|
}
|
|
|
|
$cleartext = $hmacSalt . $expected_hmac . $last_key;
|
|
|
|
my $derived_key;
|
|
my $key;
|
|
my $iv;
|
|
|
|
my $pbkdf2;
|
|
|
|
if ($version == 1)
|
|
{
|
|
$derived_key = dpapi_pbkdf2 ($user_derivationKey, $salt, $iterations, 32, \&hmac_sha1);
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
$derived_key = dpapi_pbkdf2 ($user_derivationKey, $salt, $iterations, 48, \&hmac_sha512);
|
|
}
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$cipher = pack ("H*", $additional_param);
|
|
my $computed_hmac = "";
|
|
|
|
if ($version == 1)
|
|
{
|
|
$key = substr ($derived_key, 0, 24);
|
|
$iv = substr ($derived_key, 24, 8);
|
|
|
|
my $p1 = Crypt::ECB->new ({
|
|
key => substr ($key, 0, 8),
|
|
cipher => "DES",
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 8,
|
|
padding => "null",
|
|
});
|
|
|
|
my $p2 = Crypt::ECB->new ({
|
|
key => substr ($key, 8, 8),
|
|
cipher => "DES",
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 8,
|
|
padding => "null",
|
|
});
|
|
|
|
my $p3 = Crypt::ECB->new ({
|
|
key => substr ($key, 16, 8),
|
|
cipher => "DES",
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 8,
|
|
padding => "null",
|
|
});
|
|
|
|
# let's compute a 3DES-EDE-CBC decryption
|
|
|
|
my $out1;
|
|
my $out2;
|
|
my $out3;
|
|
my $expected_cleartext = "";
|
|
|
|
# size of cipherlen is 104 bytes
|
|
for (my $k = 0; $k < 13; $k++)
|
|
{
|
|
$out1 = $p3->decrypt (substr ($cipher, $k * 8, 8));
|
|
$out2 = $p2->encrypt ($out1);
|
|
$out3 = $p1->decrypt ($out2);
|
|
|
|
$expected_cleartext .= substr ($out3, 0, 8) ^ $iv;
|
|
|
|
$iv = substr ($cipher, $k * 8, 8);
|
|
}
|
|
|
|
$last_key = substr ($expected_cleartext, length ($expected_cleartext) - 64, 64);
|
|
$hmacSalt = substr ($expected_cleartext, 0, 16);
|
|
$expected_hmac = substr ($expected_cleartext, 16, 20);
|
|
|
|
$encKey = hmac_sha1 ($hmacSalt, $user_derivationKey);
|
|
$computed_hmac = hmac_sha1 ($last_key, $encKey);
|
|
|
|
$cleartext = $expected_cleartext;
|
|
|
|
if (unpack ("H*", $expected_hmac) ne unpack ("H*", $computed_hmac))
|
|
{
|
|
$cleartext = "0" x 104;
|
|
}
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
$key = substr ($derived_key, 0, 32);
|
|
$iv = substr ($derived_key, 32, 16);
|
|
|
|
my $aes = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $iv,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32,
|
|
padding => "null",
|
|
});
|
|
|
|
my $expected_cleartext = $aes->decrypt ($cipher);
|
|
|
|
$last_key = substr ($expected_cleartext, length ($expected_cleartext) - 64, 64);
|
|
$hmacSalt = substr ($expected_cleartext, 0, 16);
|
|
$expected_hmac = substr ($expected_cleartext, 16, 64);
|
|
|
|
$encKey = hmac_sha512 ($hmacSalt, $user_derivationKey);
|
|
$computed_hmac = hmac_sha512 ($last_key, $encKey);
|
|
|
|
$cleartext = $expected_cleartext;
|
|
|
|
if (unpack ("H*", $expected_hmac) ne unpack ("H*", $computed_hmac))
|
|
{
|
|
$cleartext = "0" x 144;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($version == 1)
|
|
{
|
|
$key = substr ($derived_key, 0, 24);
|
|
$iv = substr ($derived_key, 24, 8);
|
|
|
|
my $p1 = Crypt::ECB->new ({
|
|
key => substr ($key, 0, 8),
|
|
cipher => "DES",
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 8,
|
|
padding => "null",
|
|
});
|
|
|
|
my $p2 = Crypt::ECB->new ({
|
|
key => substr ($key, 8, 8),
|
|
cipher => "DES",
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 8,
|
|
padding => "null",
|
|
});
|
|
|
|
my $p3 = Crypt::ECB->new ({
|
|
key => substr ($key, 16, 8),
|
|
cipher => "DES",
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 8,
|
|
padding => "null",
|
|
});
|
|
|
|
# let's compute a 3DES-EDE-CBC encryption
|
|
|
|
# compute first block
|
|
my $out1 = $p1->encrypt (substr ($cleartext, 0, 8) ^ $iv);
|
|
my $out2 = $p2->decrypt ($out1);
|
|
my $out3 = $p3->encrypt ($out2);
|
|
|
|
$cipher = substr ($out3, 0, 8);
|
|
|
|
# size of cipherlen is 104 bytes
|
|
for (my $k = 1; $k < 13; $k++)
|
|
{
|
|
$iv = $out3;
|
|
|
|
$out1 = $p1->encrypt (substr ($cleartext, $k * 8, 8) ^ $iv);
|
|
$out2 = $p2->decrypt ($out1);
|
|
$out3 = $p3->encrypt ($out2);
|
|
|
|
$cipher .= substr ($out3, 0, 8);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$key = substr ($derived_key, 0, 32);
|
|
$iv = substr ($derived_key, 32, 16);
|
|
|
|
my $aes = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $iv,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32,
|
|
padding => "null",
|
|
});
|
|
|
|
$cipher = $aes->encrypt ($cleartext);
|
|
}
|
|
|
|
$tmp_hash = sprintf ('$DPAPImk$%d*%d*%s*%s*%s*%d*%s*%d*%s',
|
|
$version,
|
|
$context,
|
|
$SID,
|
|
$cipher_algorithm,
|
|
$hash_algorithm,
|
|
$iterations,
|
|
unpack ("H*", $salt),
|
|
$cipher_len,
|
|
unpack ("H*", $cipher));
|
|
}
|
|
elsif ($mode == 15400)
|
|
{
|
|
my $counter;
|
|
my $offset;
|
|
my $iv;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$counter = $additional_param;
|
|
$offset = $additional_param2;
|
|
$iv = $additional_param3;
|
|
}
|
|
else
|
|
{
|
|
$counter = "0400000000000003";
|
|
$offset = int (rand (63));
|
|
$iv = "0200000000000001";
|
|
}
|
|
|
|
my $plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz0a2b4c6d8e";
|
|
my $eight_byte_iv = pack ("H*", $iv);
|
|
my $eight_byte_counter = pack ("H*", $counter);
|
|
my $pad_len = 32 - length ($word_buf);
|
|
my $key = $word_buf . "\0" x $pad_len;
|
|
|
|
my $cipher = Crypt::OpenSSH::ChachaPoly->new ($key);
|
|
|
|
$cipher->ivsetup ($eight_byte_iv, $eight_byte_counter);
|
|
|
|
my $enc = $cipher->encrypt ($plaintext);
|
|
|
|
my $enc_offset = substr ($enc, $offset, 8);
|
|
|
|
$hash_buf = $enc_offset;
|
|
|
|
$tmp_hash = sprintf ("\$chacha20\$\*%s\*%d\*%s\*%s\*%s", $counter, $offset, $iv, unpack ("H*", substr ($plaintext, $offset, 8)), unpack ("H*", $enc_offset));
|
|
}
|
|
elsif ($mode == 15500)
|
|
{
|
|
my $iv = pack ("H*", $salt_buf);
|
|
|
|
if (length $additional_param)
|
|
{
|
|
$iv = pack ("H*", $additional_param);
|
|
}
|
|
|
|
my $enc_key = randbytes (get_random_num (1, 1500));
|
|
|
|
if (length $additional_param2)
|
|
{
|
|
$enc_key = pack ("H*", $additional_param2);
|
|
}
|
|
|
|
my $alias = "test";
|
|
|
|
if (length $additional_param3)
|
|
{
|
|
$alias = $additional_param3;
|
|
}
|
|
|
|
my $word_buf_utf16be = encode ("UTF-16BE", $word_buf);
|
|
|
|
my $hash_buf = sha1 ($word_buf_utf16be . $iv);
|
|
|
|
my $DER1 = substr ($hash_buf, 0, 1);
|
|
my $DER2 = substr ($hash_buf, 6, 14);
|
|
|
|
my @enc_key_data = split "", $enc_key;
|
|
|
|
my $enc_key_data_length = scalar @enc_key_data;
|
|
|
|
my @key_data = ();
|
|
|
|
for (my $i = 0; $i < scalar $enc_key_data_length; $i += 20)
|
|
{
|
|
my @hash_buf_data = split "", $hash_buf;
|
|
|
|
for (my $j = 0; $j < 20; $j++)
|
|
{
|
|
last if (($i + $j) >= $enc_key_data_length);
|
|
|
|
$key_data[$i + $j] = $enc_key_data[$i + $j] ^ $hash_buf_data[$j];
|
|
}
|
|
|
|
$hash_buf = sha1 ($word_buf_utf16be . $hash_buf);
|
|
}
|
|
|
|
my $key = join "", @key_data;
|
|
|
|
$hash_buf = sha1 ($word_buf_utf16be . $key);
|
|
|
|
$tmp_hash = sprintf ("\$jksprivk\$*%s*%s*%s*%s*%s*%s", uc unpack ("H*", $hash_buf), uc unpack ("H*", $iv), uc unpack ("H*", $enc_key), uc unpack ("H*", $DER1), uc unpack ("H*", $DER2), $alias);
|
|
}
|
|
elsif ($mode == 15600)
|
|
{
|
|
my $iterations;
|
|
my $ciphertext;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$iterations = $iter;
|
|
$ciphertext = $additional_param;
|
|
}
|
|
else
|
|
{
|
|
$iterations = 1024; # 262144 originally
|
|
$ciphertext = randbytes (32);
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations,
|
|
out_len => 32
|
|
);
|
|
|
|
my $derived_key = $pbkdf2->PBKDF2 ($salt_buf, $word_buf);
|
|
|
|
my $derived_key_cropped = substr ($derived_key, 16, 16);
|
|
|
|
$hash_buf = keccak_256_hex ($derived_key_cropped . $ciphertext);
|
|
|
|
$tmp_hash = sprintf ("\$ethereum\$p*%i*%s*%s*%s", $iterations, unpack ("H*", $salt_buf), unpack ("H*", $ciphertext), $hash_buf);
|
|
}
|
|
elsif ($mode == 15700)
|
|
{
|
|
my $scrypt_N;
|
|
my $scrypt_r;
|
|
my $scrypt_p;
|
|
|
|
my $ciphertext;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$scrypt_N = $additional_param;
|
|
$scrypt_r = $additional_param2;
|
|
$scrypt_p = $additional_param3;
|
|
$ciphertext = $additional_param4;
|
|
}
|
|
else
|
|
{
|
|
$scrypt_N = 1024; # 262144 originally
|
|
$scrypt_r = 1; # 8 originally
|
|
$scrypt_p = 1;
|
|
$ciphertext = randbytes (32);
|
|
}
|
|
|
|
my $derived_key = scrypt_raw ($word_buf, $salt_buf, $scrypt_N, $scrypt_r, $scrypt_p, 32);
|
|
|
|
my $derived_key_cropped = substr ($derived_key, 16, 16);
|
|
|
|
$hash_buf = keccak_256_hex ($derived_key_cropped . $ciphertext);
|
|
|
|
$tmp_hash = sprintf ("\$ethereum\$s*%i*%i*%i*%s*%s*%s", $scrypt_N, $scrypt_r, $scrypt_p, unpack ("H*", $salt_buf), unpack ("H*", $ciphertext), $hash_buf);
|
|
}
|
|
elsif ($mode == 16000)
|
|
{
|
|
my $converter = Text::Iconv->new ("utf-8", "shift-jis");
|
|
|
|
$word_buf = $converter->convert ($word_buf);
|
|
|
|
$salt_buf = substr ($word_buf . '..', 1, 2);
|
|
|
|
$salt_buf =~ s/[^\.-z]/\./go;
|
|
|
|
$salt_buf =~ tr/:;<=>?@[\\]^_`/A-Ga-f/;
|
|
|
|
$hash_buf = crypt ($word_buf, $salt_buf);
|
|
|
|
$hash_buf = substr ($hash_buf, -10);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 16100)
|
|
{
|
|
my $session_id;
|
|
my $encrypted_data;
|
|
my $sequence;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$session_id = pack ("H*", $additional_param);
|
|
}
|
|
else
|
|
{
|
|
$session_id = pack ("H*", randbytes (8));
|
|
}
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$encrypted_data = pack ("H*", $additional_param2);
|
|
}
|
|
|
|
if (defined $additional_param3)
|
|
{
|
|
$sequence = pack ("H*", $additional_param3);
|
|
}
|
|
else
|
|
{
|
|
$sequence = pack ("H*", "c006");
|
|
}
|
|
|
|
my $key = md5 ($session_id . $word_buf . $sequence);
|
|
|
|
if (defined $encrypted_data)
|
|
{
|
|
## verify case
|
|
|
|
my $encrypted_data_len = length $encrypted_data;
|
|
|
|
my $plain_data = substr ($encrypted_data, 0, 6) ^ substr ($key, 0, 6);
|
|
|
|
my ($status, $flags, $server_msg_len, $data_len) = unpack ("CCnn", $plain_data);
|
|
|
|
if ((($status >= 0x01 && $status <= 0x07) || $status == 0x21)
|
|
&& ($flags == 0x01 || $flags == 0x00)
|
|
&& (6 + $server_msg_len + $data_len == $encrypted_data_len))
|
|
{
|
|
## ok
|
|
}
|
|
else
|
|
{
|
|
$encrypted_data = ""; # some invalid data
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $plain_data = "\x01\x00\x00\x00\x00\x00";
|
|
|
|
my $plain_data_len = length $plain_data;
|
|
|
|
my $shortest = ($plain_data_len > 16) ? 16 : $plain_data_len;
|
|
|
|
$encrypted_data = substr ($plain_data, 0, $shortest) ^ substr ($key, 0, $shortest);
|
|
}
|
|
|
|
$tmp_hash = sprintf ('$tacacs-plus$0$%s$%s$%s', unpack ("H*", $session_id), unpack ("H*", $encrypted_data), unpack ("H*", $sequence));
|
|
}
|
|
elsif ($mode == 16200)
|
|
{
|
|
my $salt_bin = pack ("H*", $salt_buf);
|
|
|
|
my $iterations = 20000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
my $Z_PK = 1;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$Z_PK = $additional_param;
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations,
|
|
output_len => 16,
|
|
);
|
|
|
|
my $KEK = $pbkdf2->PBKDF2 ($salt_bin, $word_buf);
|
|
|
|
my $aes = Crypt::Mode::ECB->new ('AES', 0);
|
|
|
|
my $blob_bin;
|
|
|
|
my $A;
|
|
my $B;
|
|
my $P1;
|
|
my $P2;
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$blob_bin = pack ("H*", $additional_param2);
|
|
|
|
$A = substr ($blob_bin, 0, 8);
|
|
$P1 = substr ($blob_bin, 8, 8);
|
|
$P2 = substr ($blob_bin, 16, 8);
|
|
|
|
for (my $j = 5; $j >= 0; $j--)
|
|
{
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B ^= pack ("Q>", (2 * $j + 2));
|
|
$B .= $P2;
|
|
$B = $aes->decrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$P2 = substr ($B, 8, 8);
|
|
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B ^= pack ("Q>", (2 * $j + 1));
|
|
$B .= $P1;
|
|
$B = $aes->decrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$P1 = substr ($B, 8, 8);
|
|
}
|
|
|
|
if ($A eq "\xa6" x 8)
|
|
{
|
|
for (my $j = 0; $j <= 5; $j++)
|
|
{
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B .= $P1;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (2 * $j + 1));
|
|
$P1 = substr ($B, 8, 8);
|
|
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B .= $P2;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (2 * $j + 2));
|
|
$P2 = substr ($B, 8, 8);
|
|
}
|
|
|
|
$blob_bin = $A . $P1 . $P2;
|
|
}
|
|
else
|
|
{
|
|
$blob_bin = "\xff" x 24;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$A = "\xa6" x 8;
|
|
$P1 = "\xff" x 8;
|
|
$P2 = "\xff" x 8;
|
|
|
|
for (my $j = 0; $j <= 5; $j++)
|
|
{
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B .= $P1;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (2 * $j + 1));
|
|
$P1 = substr ($B, 8, 8);
|
|
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B .= $P2;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (2 * $j + 2));
|
|
$P2 = substr ($B, 8, 8);
|
|
}
|
|
|
|
$blob_bin = $A . $P1 . $P2;
|
|
}
|
|
|
|
$tmp_hash = sprintf ('$ASN$*%d*%d*%s*%s', $Z_PK, $iterations, unpack ("H*", $salt_bin), unpack ("H*", $blob_bin));
|
|
}
|
|
elsif ($mode == 16300)
|
|
{
|
|
my $ethaddr = $salt_buf;
|
|
|
|
my $iv = "";
|
|
my $seed = "";
|
|
my $encseed = "";
|
|
|
|
# setup pbkdf2 params:
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => 2000,
|
|
output_len => 16
|
|
);
|
|
|
|
my $key = $pbkdf2->PBKDF2 ($word_buf, $word_buf);
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$iv = substr ($additional_param, 0, 16);
|
|
$encseed = substr ($additional_param, 16);
|
|
|
|
# AES-128-CBC decrypt:
|
|
|
|
my $aes_cbc = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $iv,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 16
|
|
});
|
|
|
|
$seed = $aes_cbc->decrypt ($encseed);
|
|
}
|
|
else
|
|
{
|
|
$iv = randbytes (16);
|
|
$seed = randbytes (592);
|
|
|
|
# AES-128-CBC encrypt:
|
|
|
|
my $aes_cbc = Crypt::CBC->new ({
|
|
key => $key,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $iv,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 16
|
|
});
|
|
|
|
$encseed = $aes_cbc->encrypt ($seed);
|
|
}
|
|
|
|
$hash_buf = keccak_256_hex ($seed . "\x02");
|
|
|
|
$tmp_hash = sprintf ("\$ethereum\$w*%s*%s*%s", unpack ("H*", $iv . $encseed), $ethaddr, substr ($hash_buf, 0, 32));
|
|
}
|
|
elsif ($mode == 16400)
|
|
{
|
|
my $md5 = Digest::Perl::MD5->new;
|
|
my $length = length($word_buf);
|
|
|
|
$md5->{_data} = $word_buf ^ ("\x5c" x $length);
|
|
$md5->{_data} .= "\x5c" x (64 - $length);
|
|
$md5->add();
|
|
|
|
$hash_buf = unpack("H*", pack('V4', @{$md5->{_state}}));
|
|
$tmp_hash = sprintf ("{CRAM-MD5}%s00000000000000000000000000000000", $hash_buf);
|
|
}
|
|
elsif ($mode == 16500)
|
|
{
|
|
my ($header_base64) = split (/\./, $salt_buf);
|
|
|
|
my $header_jwt = decode_base64url ($header_base64);
|
|
|
|
my $header = decode_json ($header_jwt);
|
|
|
|
my $alg = $header->{"alg"};
|
|
|
|
if ($alg eq "HS256")
|
|
{
|
|
$hash_buf = hmac ($salt_buf, $word_buf, \&sha256, 64);
|
|
}
|
|
elsif ($alg eq "HS384")
|
|
{
|
|
$hash_buf = hmac ($salt_buf, $word_buf, \&sha384, 128);
|
|
}
|
|
elsif ($alg eq "HS512")
|
|
{
|
|
$hash_buf = hmac ($salt_buf, $word_buf, \&sha512, 128);
|
|
}
|
|
else
|
|
{
|
|
die "not supported hash\n";
|
|
}
|
|
|
|
$tmp_hash = sprintf ("%s.%s", $salt_buf, encode_base64url ($hash_buf, ""));
|
|
}
|
|
elsif ($mode == 16600)
|
|
{
|
|
my $key_bin = sha256 (sha256 ($word_buf));
|
|
|
|
my $salt_type;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$salt_type = $additional_param;
|
|
|
|
if ($salt_type ne "1") { die "currently only salt_type 1 supported\n"; }
|
|
}
|
|
else
|
|
{
|
|
$salt_type = 1;
|
|
}
|
|
|
|
my $iv;
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$iv = $additional_param2;
|
|
}
|
|
else
|
|
{
|
|
$iv = substr ($salt_buf, 0, 32);
|
|
}
|
|
|
|
my $iv_bin = pack ("H*", $iv);
|
|
|
|
my $cipher = Crypt::CBC->new ({
|
|
key => $key_bin,
|
|
cipher => "Crypt::Rijndael",
|
|
iv => $iv_bin,
|
|
literal_key => 1,
|
|
header => "none",
|
|
keysize => 32,
|
|
padding => "null",
|
|
});
|
|
|
|
my $plain_bin;
|
|
|
|
if (defined $additional_param3)
|
|
{
|
|
my $encrypted_bin = pack ("H*", $additional_param3);
|
|
|
|
my $test = $cipher->decrypt ($encrypted_bin);
|
|
|
|
if ($test =~ /^[0-9a-f]+$/)
|
|
{
|
|
$plain_bin = $test;
|
|
}
|
|
else
|
|
{
|
|
$plain_bin = "\xff" x 16;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
my $plain = "30313233343536373839616263646566";
|
|
|
|
$plain_bin = pack ("H*", $plain);
|
|
}
|
|
|
|
my $encrypted_bin = $cipher->encrypt ($plain_bin);
|
|
|
|
my $encrypted = unpack ("H*", $encrypted_bin);
|
|
|
|
$tmp_hash = sprintf ("\$electrum\$%d*%s*%s", $salt_type, $iv, $encrypted);
|
|
}
|
|
elsif ($mode == 16700)
|
|
{
|
|
my $salt_bin = pack ("H*", $salt_buf);
|
|
|
|
my $iterations = 20000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
my $Z_PK = 1;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$Z_PK = $additional_param;
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations,
|
|
output_len => 16,
|
|
);
|
|
|
|
my $KEK = $pbkdf2->PBKDF2 ($salt_bin, $word_buf);
|
|
|
|
my $aes = Crypt::Mode::ECB->new ('AES', 0);
|
|
|
|
my $blob_bin;
|
|
|
|
my $A;
|
|
my $B;
|
|
my $P1;
|
|
my $P2;
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$blob_bin = pack ("H*", $additional_param2);
|
|
|
|
$A = substr ($blob_bin, 0, 8);
|
|
$P1 = substr ($blob_bin, 8, 8);
|
|
$P2 = substr ($blob_bin, 16, 8);
|
|
|
|
for (my $j = 5; $j >= 0; $j--)
|
|
{
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B ^= pack ("Q>", (2 * $j + 2));
|
|
$B .= $P2;
|
|
$B = $aes->decrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$P2 = substr ($B, 8, 8);
|
|
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B ^= pack ("Q>", (2 * $j + 1));
|
|
$B .= $P1;
|
|
$B = $aes->decrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$P1 = substr ($B, 8, 8);
|
|
}
|
|
|
|
if ($A eq "\xa6" x 8)
|
|
{
|
|
for (my $j = 0; $j <= 5; $j++)
|
|
{
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B .= $P1;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (2 * $j + 1));
|
|
$P1 = substr ($B, 8, 8);
|
|
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B .= $P2;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (2 * $j + 2));
|
|
$P2 = substr ($B, 8, 8);
|
|
}
|
|
|
|
$blob_bin = $A . $P1 . $P2;
|
|
}
|
|
else
|
|
{
|
|
$blob_bin = "\xff" x 24;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$A = "\xa6" x 8;
|
|
$P1 = "\xff" x 8;
|
|
$P2 = "\xff" x 8;
|
|
|
|
for (my $j = 0; $j <= 5; $j++)
|
|
{
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B .= $P1;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (2 * $j + 1));
|
|
$P1 = substr ($B, 8, 8);
|
|
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B .= $P2;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (2 * $j + 2));
|
|
$P2 = substr ($B, 8, 8);
|
|
}
|
|
|
|
$blob_bin = $A . $P1 . $P2;
|
|
}
|
|
|
|
$tmp_hash = sprintf ('$fvde$%d$%d$%s$%d$%s', $Z_PK, length ($salt_bin), unpack ("H*", $salt_bin), $iterations, unpack ("H*", $blob_bin));
|
|
}
|
|
elsif ($mode == 16800)
|
|
{
|
|
my $macap;
|
|
my $macsta;
|
|
my $essid;
|
|
|
|
if (!defined ($additional_param))
|
|
{
|
|
$macap = unpack ("H*", randbytes (6));
|
|
}
|
|
else
|
|
{
|
|
$macap = $additional_param;
|
|
}
|
|
|
|
if (!defined ($additional_param2))
|
|
{
|
|
$macsta = unpack ("H*", randbytes (6));
|
|
}
|
|
else
|
|
{
|
|
$macsta = $additional_param2;
|
|
}
|
|
|
|
if (!defined ($additional_param3))
|
|
{
|
|
$essid = unpack ("H*", randbytes (get_random_num (8, 32) & 0x1e));
|
|
}
|
|
else
|
|
{
|
|
$essid = $additional_param3;
|
|
}
|
|
|
|
# generate the Pairwise Master Key (PMK)
|
|
|
|
my $iterations = 4096;
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hash_class => 'HMACSHA1',
|
|
iterations => $iterations,
|
|
output_len => 32,
|
|
);
|
|
|
|
my $essid_bin = pack ("H*", $essid);
|
|
|
|
my $pmk = $pbkdf2->PBKDF2 ($essid_bin, $word_buf);
|
|
|
|
my $macap_bin = pack ("H*", $macap);
|
|
my $macsta_bin = pack ("H*", $macsta);
|
|
|
|
my $data = "PMK Name" . $macap_bin . $macsta_bin;
|
|
|
|
my $pmkid = hmac_hex ($data, $pmk, \&sha1);
|
|
|
|
$tmp_hash = sprintf ("%s*%s*%s*%s", substr ($pmkid, 0, 32), $macap, $macsta, $essid);
|
|
}
|
|
elsif ($mode == 17300)
|
|
{
|
|
$hash_buf = sha3_224_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 17400)
|
|
{
|
|
$hash_buf = sha3_256_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 17500)
|
|
{
|
|
$hash_buf = sha3_384_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 17600)
|
|
{
|
|
$hash_buf = sha3_512_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 17700)
|
|
{
|
|
$hash_buf = keccak_224_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 17800)
|
|
{
|
|
$hash_buf = keccak_256_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 17900)
|
|
{
|
|
$hash_buf = keccak_384_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 18000)
|
|
{
|
|
$hash_buf = keccak_512_hex ($word_buf);
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 18100)
|
|
{
|
|
my $paddedTime = sprintf ("%016x", int (int ($salt_buf) / 30));
|
|
my $data = pack ('H*', $paddedTime);
|
|
my $key = $word_buf;
|
|
|
|
$hash_buf = hmac_hex ($data, $key, \&sha1, 64);
|
|
|
|
my $offset = hex (substr ($hash_buf, -8)) & 0xf;
|
|
$offset *= 2;
|
|
my $token = hex (substr ($hash_buf, $offset, 8));
|
|
$token &= 0x7fffffff;
|
|
$token %= 1000000;
|
|
|
|
## token must be leading zero padded, and salt leading zero stripped
|
|
$tmp_hash = sprintf ("%06d:%d", $token, int ($salt_buf));
|
|
}
|
|
elsif ($mode == 18200)
|
|
{
|
|
my @salt_arr = split (':', $salt_buf);
|
|
|
|
my $user_principal_name = $salt_arr[0];
|
|
|
|
my $k = md4 (encode ("UTF-16LE", $word_buf));
|
|
|
|
my $k1 = hmac_md5 ("\x08\x00\x00\x00", $k);
|
|
|
|
my $cleartext_ticket = '7981df3081dca01b3019a003020117a112041071e026814da2' .
|
|
'3f129f0e67a01b73f79aa11c301a3018a003020100a111180f32303138313033303039353' .
|
|
'831365aa206020460fdc6caa311180f32303337303931343032343830355aa40703050050' .
|
|
'c10000a511180f32303138313033303039353831365aa611180f323031383130333030393' .
|
|
'53831365aa711180f32303138313033303139353831365aa811180f323031383130333131' .
|
|
'30303433385aa90d1b0b545952454c4c2e434f5250aa20301ea003020101a11730151b066' .
|
|
'b72627467741b0b545952454c4c2e434f5250';
|
|
my $checksum = "";
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$checksum = pack ("H*", $additional_param);
|
|
}
|
|
else
|
|
{
|
|
my $nonce = $salt_arr[1];
|
|
|
|
$cleartext_ticket = $nonce . $cleartext_ticket;
|
|
|
|
$checksum = hmac_md5 (pack ("H*", $cleartext_ticket), $k1);
|
|
}
|
|
|
|
my $k3 = hmac_md5 ($checksum, $k1);
|
|
|
|
my $edata2 = "";
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$edata2 = $additional_param2;
|
|
|
|
my $cipher_decrypt = Crypt::RC4->new ($k3);
|
|
|
|
my $ticket_decrypt = unpack ("H*", $cipher_decrypt->RC4 (pack ("H*", $edata2)));
|
|
|
|
my $check_correct = ((substr ($ticket_decrypt, 16, 4) eq "7981" && substr ($ticket_decrypt, 22, 2) eq "30")) ||
|
|
((substr ($ticket_decrypt, 16, 2) eq "79") && (substr ($ticket_decrypt, 20, 2) eq "30")) ||
|
|
((substr ($ticket_decrypt, 16, 4) eq "7982") && (substr ($ticket_decrypt, 24, 2) eq "30"));
|
|
|
|
if ($check_correct == 1)
|
|
{
|
|
$cleartext_ticket = $ticket_decrypt;
|
|
}
|
|
else # validation failed
|
|
{
|
|
# fake/wrong ticket (otherwise if we just decrypt/encrypt we end up with false positives all the time)
|
|
$cleartext_ticket = "0" x (length ($cleartext_ticket) + 16);
|
|
}
|
|
}
|
|
|
|
my $cipher = Crypt::RC4->new ($k3);
|
|
|
|
$edata2 = $cipher->RC4 (pack ("H*", $cleartext_ticket));
|
|
|
|
$tmp_hash = sprintf ('$krb5asrep$23$%s:%s$%s', $user_principal_name, unpack ("H*", $checksum), unpack ("H*", $edata2));
|
|
}
|
|
elsif ($mode == 18300)
|
|
{
|
|
my $salt_bin = pack ("H*", $salt_buf);
|
|
|
|
my $iterations = 20000;
|
|
|
|
if (defined ($iter))
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
my $Z_PK = 2;
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$Z_PK = $additional_param;
|
|
}
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new
|
|
(
|
|
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
|
iterations => $iterations,
|
|
output_len => 32,
|
|
);
|
|
|
|
my $KEK = $pbkdf2->PBKDF2 ($salt_bin, $word_buf);
|
|
|
|
my $aes = Crypt::Mode::ECB->new ('AES', 0);
|
|
|
|
my $blob_bin;
|
|
|
|
my $A;
|
|
my $B;
|
|
my $P1;
|
|
my $P2;
|
|
my $P3;
|
|
my $P4;
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$blob_bin = pack ("H*", $additional_param2);
|
|
|
|
$A = substr ($blob_bin, 0, 8);
|
|
$P1 = substr ($blob_bin, 8, 8);
|
|
$P2 = substr ($blob_bin, 16, 8);
|
|
$P3 = substr ($blob_bin, 24, 8);
|
|
$P4 = substr ($blob_bin, 32, 8);
|
|
|
|
for (my $j = 5; $j >= 0; $j--)
|
|
{
|
|
# N = 4
|
|
|
|
$B = $A;
|
|
$B ^= pack ("Q>", (4 * $j + 4));
|
|
$B .= $P4;
|
|
$B = $aes->decrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$P4 = substr ($B, 8, 8);
|
|
|
|
# N = 3
|
|
|
|
$B = $A;
|
|
$B ^= pack ("Q>", (4 * $j + 3));
|
|
$B .= $P3;
|
|
$B = $aes->decrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$P3 = substr ($B, 8, 8);
|
|
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B ^= pack ("Q>", (4 * $j + 2));
|
|
$B .= $P2;
|
|
$B = $aes->decrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$P2 = substr ($B, 8, 8);
|
|
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B ^= pack ("Q>", (4 * $j + 1));
|
|
$B .= $P1;
|
|
$B = $aes->decrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$P1 = substr ($B, 8, 8);
|
|
}
|
|
|
|
if ($A eq "\xa6" x 8)
|
|
{
|
|
for (my $j = 0; $j <= 5; $j++)
|
|
{
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B .= $P1;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (4 * $j + 1));
|
|
$P1 = substr ($B, 8, 8);
|
|
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B .= $P2;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (4 * $j + 2));
|
|
$P2 = substr ($B, 8, 8);
|
|
|
|
# N = 3
|
|
|
|
$B = $A;
|
|
$B .= $P3;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (4 * $j + 3));
|
|
$P3 = substr ($B, 8, 8);
|
|
|
|
# N = 4
|
|
|
|
$B = $A;
|
|
$B .= $P4;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (4 * $j + 4));
|
|
$P4 = substr ($B, 8, 8);
|
|
}
|
|
|
|
$blob_bin = $A . $P1 . $P2 . $P3 . $P4;
|
|
}
|
|
else
|
|
{
|
|
$blob_bin = "\xff" x 40;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$A = "\xa6" x 8;
|
|
$P1 = "\xff" x 8;
|
|
$P2 = "\xff" x 8;
|
|
$P3 = "\xff" x 8;
|
|
$P4 = "\xff" x 8;
|
|
|
|
for (my $j = 0; $j <= 5; $j++)
|
|
{
|
|
# N = 1
|
|
|
|
$B = $A;
|
|
$B .= $P1;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (4 * $j + 1));
|
|
$P1 = substr ($B, 8, 8);
|
|
|
|
# N = 2
|
|
|
|
$B = $A;
|
|
$B .= $P2;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (4 * $j + 2));
|
|
$P2 = substr ($B, 8, 8);
|
|
|
|
# N = 3
|
|
|
|
$B = $A;
|
|
$B .= $P3;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (4 * $j + 3));
|
|
$P3 = substr ($B, 8, 8);
|
|
|
|
# N = 4
|
|
|
|
$B = $A;
|
|
$B .= $P4;
|
|
$B = $aes->encrypt ($B, $KEK);
|
|
$A = substr ($B, 0, 8);
|
|
$A ^= pack ("Q>", (4 * $j + 4));
|
|
$P4 = substr ($B, 8, 8);
|
|
}
|
|
|
|
$blob_bin = $A . $P1 . $P2 . $P3 . $P4;
|
|
}
|
|
|
|
$tmp_hash = sprintf ('$fvde$%d$%d$%s$%d$%s', $Z_PK, length ($salt_bin), unpack ("H*", $salt_bin), $iterations, unpack ("H*", $blob_bin));
|
|
}
|
|
elsif ($mode == 18400)
|
|
{
|
|
# defaults for single mode
|
|
my $iterations = 100000;
|
|
my $iv = "aa" x 16;
|
|
my $plaintext = "bb" x 1024;
|
|
|
|
# parameters for verify mode
|
|
if (defined $iter)
|
|
{
|
|
$iterations = $iter;
|
|
}
|
|
|
|
if (defined $additional_param)
|
|
{
|
|
$iv = $additional_param;
|
|
}
|
|
|
|
if (defined $additional_param2)
|
|
{
|
|
$plaintext = $additional_param2;
|
|
}
|
|
|
|
# binary buffers
|
|
my $b_iv = pack ("H*", $iv);
|
|
my $b_salt = pack ("H*", $salt_buf);
|
|
my $b_plaintext = pack ("H*", $plaintext);
|
|
|
|
my $kdf = Crypt::PBKDF2->new
|
|
(
|
|
hash_class => 'HMACSHA1',
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
my $checksum = sha256_hex ($b_plaintext);
|
|
|
|
my $pass_hash = sha256 ($word_buf);
|
|
my $derived_key = $kdf->PBKDF2 ($b_salt, $pass_hash);
|
|
my $cbc = Crypt::Mode::CBC->new ('AES', 0);
|
|
my $b_ciphertext = $cbc->encrypt ($b_plaintext, $derived_key, $b_iv);
|
|
|
|
my $ciphertext = unpack ("H*", $b_ciphertext);
|
|
|
|
$tmp_hash = '$odf$'."*1*1*$iterations*32*$checksum*16*$iv*16*$salt_buf*0*$ciphertext";
|
|
}
|
|
elsif ($mode == 18500)
|
|
{
|
|
$hash_buf = sha1_hex (md5_hex (md5_hex ($word_buf)));
|
|
|
|
$tmp_hash = sprintf ("%s", $hash_buf);
|
|
}
|
|
elsif ($mode == 99999)
|
|
{
|
|
$tmp_hash = sprintf ("%s", $word_buf);
|
|
}
|
|
|
|
return ($tmp_hash);
|
|
}
|
|
|
|
#Thanks to Jochen Hoenicke <hoenicke@gmail.com>
|
|
# (one of the authors of Palm Keyring)
|
|
# for these next two subs.
|
|
sub dpapi_pbkdf2
|
|
{
|
|
my ($password, $salt, $iter, $keylen, $prf) = @_;
|
|
my ($k, $t, $u, $ui, $i);
|
|
$t = "";
|
|
for ($k = 1; length ($t) < $keylen; $k++)
|
|
{
|
|
$u = $ui = &$prf ($salt.pack ('N', $k), $password);
|
|
for ($i = 1; $i < $iter; $i++)
|
|
{
|
|
# modification to fit Microsoft
|
|
# weird pbkdf2 implementation...
|
|
$ui = &$prf ($u, $password);
|
|
$u ^= $ui;
|
|
}
|
|
$t .= $u;
|
|
}
|
|
return substr ($t, 0, $keylen);
|
|
}
|
|
|
|
## STEP 4: Add custom traits here (optional).
|
|
sub rnd
|
|
{
|
|
my $mode = shift;
|
|
|
|
my $word_len = shift;
|
|
|
|
my $salt_len = shift;
|
|
|
|
my $max = $MAX_LEN;
|
|
|
|
if ($mode == 2410)
|
|
{
|
|
$salt_len = min ($salt_len, 4);
|
|
}
|
|
|
|
if (is_in_array ($mode, $IS_UTF16LE))
|
|
{
|
|
if (is_in_array ($mode, $ALLOW_LONG_SALT))
|
|
{
|
|
$word_len = min ($word_len, int ($max / 2));
|
|
}
|
|
else
|
|
{
|
|
$word_len = min ($word_len, int ($max / 2) - $salt_len);
|
|
}
|
|
}
|
|
elsif (is_in_array ($mode, $LESS_FIFTEEN))
|
|
{
|
|
$word_len = min ($word_len, 15);
|
|
}
|
|
else
|
|
{
|
|
if (! is_in_array ($mode, $ALLOW_LONG_SALT))
|
|
{
|
|
$word_len = min ($word_len, $max - $salt_len);
|
|
}
|
|
}
|
|
|
|
if ($word_len < 1)
|
|
{
|
|
$word_len = 1;
|
|
}
|
|
|
|
##
|
|
## gen salt
|
|
##
|
|
|
|
my $salt_buf;
|
|
|
|
if ($mode == 4800)
|
|
{
|
|
my @salt_arr;
|
|
|
|
for (my $i = 0; $i < $salt_len; $i++)
|
|
{
|
|
my $c = get_random_chr (0x30, 0x39);
|
|
|
|
push (@salt_arr, $c);
|
|
}
|
|
|
|
$salt_buf = join ("", @salt_arr);
|
|
|
|
$salt_buf = get_random_md5chap_salt ($salt_buf);
|
|
}
|
|
elsif ($mode == 5300 || $mode == 5400)
|
|
{
|
|
$salt_buf = get_random_ike_salt ();
|
|
}
|
|
elsif ($mode == 5500)
|
|
{
|
|
$salt_buf = get_random_netntlmv1_salt ($salt_len, $salt_len);
|
|
}
|
|
elsif ($mode == 5600)
|
|
{
|
|
$salt_buf = get_random_netntlmv2_salt ($salt_len, $salt_len);
|
|
}
|
|
elsif ($mode == 6600)
|
|
{
|
|
$salt_buf = get_random_agilekeychain_salt ();
|
|
}
|
|
elsif ($mode == 8200)
|
|
{
|
|
$salt_buf = get_random_cloudkeychain_salt ();
|
|
}
|
|
elsif ($mode == 8300)
|
|
{
|
|
$salt_buf = get_random_dnssec_salt ();
|
|
}
|
|
elsif ($mode == 13100)
|
|
{
|
|
$salt_buf = get_random_kerberos5_tgs_salt ();
|
|
}
|
|
elsif ($mode == 13200)
|
|
{
|
|
$salt_buf = get_random_axcrypt_salt ();
|
|
}
|
|
elsif ($mode == 13400)
|
|
{
|
|
$salt_buf = get_random_keepass_salt ();
|
|
}
|
|
elsif ($mode == 13500)
|
|
{
|
|
$salt_buf = get_pstoken_salt ();
|
|
}
|
|
elsif ($mode == 15300 || $mode == 15900)
|
|
{
|
|
my $version = 2;
|
|
|
|
if ($mode == 15300)
|
|
{
|
|
$version = 1;
|
|
}
|
|
|
|
$salt_buf = get_random_dpapimk_salt ($version);
|
|
}
|
|
elsif ($mode == 16500)
|
|
{
|
|
$salt_buf = get_random_jwt_salt ();
|
|
}
|
|
elsif ($mode == 18200)
|
|
{
|
|
$salt_buf = get_random_kerberos5_as_rep_salt ();
|
|
}
|
|
else
|
|
{
|
|
my @salt_arr;
|
|
|
|
for (my $i = 0; $i < $salt_len; $i++)
|
|
{
|
|
my $c = get_random_chr (0x30, 0x39);
|
|
|
|
push (@salt_arr, $c);
|
|
}
|
|
|
|
$salt_buf = join ("", @salt_arr);
|
|
|
|
if ($mode == 7500)
|
|
{
|
|
$salt_buf = get_random_kerberos5_salt ($salt_buf);
|
|
}
|
|
}
|
|
|
|
##
|
|
## gen plain
|
|
##
|
|
|
|
my @word_arr;
|
|
|
|
for (my $i = 0; $i < $word_len; $i++)
|
|
{
|
|
my $c = get_random_chr (0x30, 0x39);
|
|
|
|
if (($mode == 14000) || ($mode == 14100))
|
|
{
|
|
$c &= 0xfe;
|
|
}
|
|
|
|
push (@word_arr, $c);
|
|
}
|
|
|
|
my $word_buf = join ("", @word_arr);
|
|
|
|
##
|
|
## gen hash
|
|
##
|
|
|
|
my $tmp_hash = gen_hash ($mode, $word_buf, $salt_buf);
|
|
|
|
##
|
|
## run
|
|
##
|
|
|
|
my @cmd =
|
|
(
|
|
$hashcat,
|
|
"-a 0 -m", $mode,
|
|
$tmp_hash
|
|
);
|
|
|
|
print sprintf ("echo -n %-20s | %s \${OPTS} %s %4d '%s'\n", $word_buf, @cmd);
|
|
}
|
|
|
|
##
|
|
## subs
|
|
##
|
|
|
|
sub min
|
|
{
|
|
$_[$_[0] > $_[1]];
|
|
}
|
|
|
|
sub get_random_string
|
|
{
|
|
my $len = shift;
|
|
|
|
my @arr;
|
|
|
|
for (my $i = 0; $i < $len; $i++)
|
|
{
|
|
my $c = get_random_chr (0x30, 0x39);
|
|
|
|
push (@arr, $c);
|
|
}
|
|
|
|
my $buf = join ("", @arr);
|
|
|
|
return $buf;
|
|
}
|
|
|
|
sub get_random_num
|
|
{
|
|
my $min = shift;
|
|
my $max = shift;
|
|
|
|
return int ((rand ($max - $min)) + $min);
|
|
}
|
|
|
|
sub get_random_chr
|
|
{
|
|
return chr get_random_num (@_);
|
|
}
|
|
|
|
sub domino_decode
|
|
{
|
|
my $str = shift;
|
|
|
|
my $decoded = "";
|
|
|
|
for (my $i = 0; $i < length ($str); $i += 4)
|
|
{
|
|
my $num = domino_base64_decode (substr ($str, $i, 4), 4);
|
|
|
|
$decoded .= chr (($num >> 16) & 0xff) . chr (($num >> 8) & 0xff) . chr ($num & 0xff);
|
|
}
|
|
|
|
my $salt;
|
|
my $digest;
|
|
my $char;
|
|
|
|
$salt = substr ($decoded, 0, 5);
|
|
|
|
my $byte10 = (ord (substr ($salt, 3, 1)) - 4);
|
|
|
|
if ($byte10 < 0)
|
|
{
|
|
$byte10 = 256 + $byte10;
|
|
}
|
|
|
|
substr ($salt, 3, 1) = chr ($byte10);
|
|
|
|
$digest = substr ($decoded, 5, 9);
|
|
$char = substr ($str, 18, 1);
|
|
|
|
return ($digest, $salt, $char);
|
|
}
|
|
|
|
sub domino_85x_decode
|
|
{
|
|
my $str = shift;
|
|
|
|
my $decoded = "";
|
|
|
|
for (my $i = 0; $i < length ($str); $i += 4)
|
|
{
|
|
my $num = domino_base64_decode (substr ($str, $i, 4), 4);
|
|
|
|
$decoded .= chr (($num >> 16) & 0xff) . chr (($num >> 8) & 0xff) . chr ($num & 0xff);
|
|
}
|
|
|
|
my $digest;
|
|
my $salt;
|
|
my $iterations = -1;
|
|
my $chars;
|
|
|
|
$salt = substr ($decoded, 0, 16); # longer than -m 8700 (5 vs 16 <- new)
|
|
|
|
my $byte10 = (ord (substr ($salt, 3, 1)) - 4);
|
|
|
|
if ($byte10 < 0)
|
|
{
|
|
$byte10 = 256 + $byte10;
|
|
}
|
|
|
|
substr ($salt, 3, 1) = chr ($byte10);
|
|
|
|
$iterations = substr ($decoded, 16, 10);
|
|
|
|
if ($iterations =~ /^?d*$/)
|
|
{
|
|
# continue
|
|
|
|
$iterations = $iterations + 0; # hack: make sure it is an int now (atoi ())
|
|
$chars = substr ($decoded, 26, 2); # in my example it is "02"
|
|
$digest = substr ($decoded, 28, 8); # only of length of 8 vs 20 SHA1 bytes
|
|
}
|
|
|
|
return ($digest, $salt, $iterations, $chars);
|
|
}
|
|
|
|
sub domino_base64_decode
|
|
{
|
|
my $v = shift;
|
|
my $n = shift;
|
|
|
|
my $itoa64 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
|
|
|
|
my $ret = 0;
|
|
|
|
my $i = 1;
|
|
|
|
while ($i <= $n)
|
|
{
|
|
my $idx = (index ($itoa64, substr ($v, $n - $i, 1))) & 0x3f;
|
|
|
|
$ret += ($idx << (6 * ($i - 1)));
|
|
|
|
$i = $i + 1;
|
|
}
|
|
|
|
return $ret
|
|
}
|
|
|
|
sub domino_encode
|
|
{
|
|
my $final = shift;
|
|
my $char = shift;
|
|
|
|
my $byte10 = (ord (substr ($final, 3, 1)) + 4);
|
|
|
|
if ($byte10 > 255)
|
|
{
|
|
$byte10 = $byte10 - 256;
|
|
}
|
|
|
|
substr ($final, 3, 1) = chr ($byte10);
|
|
|
|
my $passwd = "";
|
|
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 0, 1))) << 16) | (int (ord (substr ($final, 1, 1))) << 8) | (int (ord (substr ($final, 2, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 3, 1))) << 16) | (int (ord (substr ($final, 4, 1))) << 8) | (int (ord (substr ($final, 5, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 6, 1))) << 16) | (int (ord (substr ($final, 7, 1))) << 8) | (int (ord (substr ($final, 8, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 9, 1))) << 16) | (int (ord (substr ($final, 10, 1))) << 8) | (int (ord (substr ($final, 11, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 12, 1))) << 16) | (int (ord (substr ($final, 13, 1))) << 8) | (int (ord (substr ($final, 14, 1)))), 4);
|
|
|
|
if (defined ($char))
|
|
{
|
|
substr ($passwd, 18, 1) = $char;
|
|
}
|
|
substr ($passwd, 19, 1) = "";
|
|
|
|
return $passwd;
|
|
}
|
|
|
|
sub domino_85x_encode
|
|
{
|
|
my $final = shift;
|
|
my $char = shift;
|
|
|
|
my $byte10 = (ord (substr ($final, 3, 1)) + 4);
|
|
|
|
if ($byte10 > 255)
|
|
{
|
|
$byte10 = $byte10 - 256;
|
|
}
|
|
|
|
substr ($final, 3, 1) = chr ($byte10);
|
|
|
|
my $passwd = "";
|
|
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 0, 1))) << 16) | (int (ord (substr ($final, 1, 1))) << 8) | (int (ord (substr ($final, 2, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 3, 1))) << 16) | (int (ord (substr ($final, 4, 1))) << 8) | (int (ord (substr ($final, 5, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 6, 1))) << 16) | (int (ord (substr ($final, 7, 1))) << 8) | (int (ord (substr ($final, 8, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 9, 1))) << 16) | (int (ord (substr ($final, 10, 1))) << 8) | (int (ord (substr ($final, 11, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 12, 1))) << 16) | (int (ord (substr ($final, 13, 1))) << 8) | (int (ord (substr ($final, 14, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 15, 1))) << 16) | (int (ord (substr ($final, 16, 1))) << 8) | (int (ord (substr ($final, 17, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 18, 1))) << 16) | (int (ord (substr ($final, 19, 1))) << 8) | (int (ord (substr ($final, 20, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 21, 1))) << 16) | (int (ord (substr ($final, 22, 1))) << 8) | (int (ord (substr ($final, 23, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 24, 1))) << 16) | (int (ord (substr ($final, 25, 1))) << 8) | (int (ord (substr ($final, 26, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 27, 1))) << 16) | (int (ord (substr ($final, 28, 1))) << 8) | (int (ord (substr ($final, 29, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 30, 1))) << 16) | (int (ord (substr ($final, 31, 1))) << 8) | (int (ord (substr ($final, 32, 1)))), 4);
|
|
$passwd .= domino_base64_encode ((int (ord (substr ($final, 33, 1))) << 16) | (int (ord (substr ($final, 34, 1))) << 8) | (int (ord (substr ($final, 35, 1)))), 4);
|
|
|
|
if (defined ($char))
|
|
{
|
|
substr ($passwd, 18, 1) = $char;
|
|
}
|
|
|
|
return $passwd;
|
|
}
|
|
|
|
sub domino_base64_encode
|
|
{
|
|
my $v = shift;
|
|
my $n = shift;
|
|
|
|
my $itoa64 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
|
|
|
|
my $ret = "";
|
|
|
|
while (($n - 1) >= 0)
|
|
{
|
|
$n = $n - 1;
|
|
|
|
$ret = substr ($itoa64, $v & 0x3f, 1) . $ret;
|
|
|
|
$v = $v >> 6;
|
|
}
|
|
|
|
return $ret
|
|
}
|
|
|
|
sub pseudo_base64
|
|
{
|
|
my $itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
my $md5 = shift;
|
|
my $s64 = "";
|
|
for my $i (0..3) {
|
|
my $v = unpack "V", substr ($md5, $i*4, 4);
|
|
for (1..4) {
|
|
$s64 .= substr ($itoa64, $v & 0x3f, 1);
|
|
$v >>= 6;
|
|
}
|
|
}
|
|
return $s64;
|
|
}
|
|
|
|
sub racf_hash
|
|
{
|
|
my ($username, $password) = @_;
|
|
|
|
$username = substr ($username . " " x 8, 0, 8);
|
|
$password = substr ($password . " " x 8, 0, 8);
|
|
|
|
my $username_ebc = ascii2ebcdic ($username);
|
|
my $password_ebc = ascii2ebcdic ($password);
|
|
|
|
my @pw = split ("", $password_ebc);
|
|
|
|
for (my $i = 0; $i < 8; $i++)
|
|
{
|
|
$pw[$i] = unpack ("C", $pw[$i]);
|
|
$pw[$i] ^= 0x55;
|
|
$pw[$i] <<= 1;
|
|
$pw[$i] = pack ("C", $pw[$i] & 0xff);
|
|
}
|
|
|
|
my $key = join ("", @pw);
|
|
|
|
my $cipher = new Crypt::DES $key;
|
|
|
|
my $ciphertext = $cipher->encrypt ($username_ebc);
|
|
|
|
my $ct = unpack ("H16", $ciphertext);
|
|
|
|
return $ct;
|
|
}
|
|
|
|
sub oracle_hash
|
|
{
|
|
my ($username, $password) = @_;
|
|
|
|
my $userpass = pack ('n*', unpack ('C*', uc ($username.$password)));
|
|
$userpass .= pack ('C', 0) while (length ($userpass) % 8);
|
|
|
|
my $key = pack ('H*', "0123456789ABCDEF");
|
|
my $iv = pack ('H*', "0000000000000000");
|
|
|
|
my $c = new Crypt::CBC (
|
|
-literal_key => 1,
|
|
-cipher => "DES",
|
|
-key => $key,
|
|
-iv => $iv,
|
|
-header => "none"
|
|
);
|
|
my $key2 = substr ($c->encrypt ($userpass), length ($userpass)-8, 8);
|
|
|
|
my $c2 = new Crypt::CBC (
|
|
-literal_key => 1,
|
|
-cipher => "DES",
|
|
-key => $key2,
|
|
-iv => $iv,
|
|
-header => "none"
|
|
);
|
|
my $hash = substr ($c2->encrypt ($userpass), length ($userpass)-8, 8);
|
|
|
|
return uc (unpack ('H*', $hash));
|
|
}
|
|
|
|
sub androidpin_hash
|
|
{
|
|
my $word_buf = shift;
|
|
|
|
my $salt_buf = shift;
|
|
|
|
my $w = sprintf ("%d%s%s", 0, $word_buf, $salt_buf);
|
|
|
|
my $digest = sha1 ($w);
|
|
|
|
for (my $i = 1; $i < 1024; $i++)
|
|
{
|
|
$w = $digest . sprintf ("%d%s%s", $i, $word_buf, $salt_buf);
|
|
|
|
$digest = sha1 ($w);
|
|
}
|
|
|
|
my ($A, $B, $C, $D, $E) = unpack ("N5", $digest);
|
|
|
|
return sprintf ("%08x%08x%08x%08x%08x", $A, $B, $C, $D, $E);
|
|
}
|
|
|
|
sub to64
|
|
{
|
|
my $v = shift;
|
|
my $n = shift;
|
|
|
|
my $itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
my $ret = "";
|
|
|
|
while (($n - 1) >= 0)
|
|
{
|
|
$n = $n - 1;
|
|
|
|
$ret .= substr ($itoa64, $v & 0x3f, 1);
|
|
|
|
$v = $v >> 6;
|
|
}
|
|
|
|
return $ret
|
|
}
|
|
|
|
sub md5_crypt
|
|
{
|
|
my $magic = shift;
|
|
|
|
my $iter = shift;
|
|
my $pass = shift;
|
|
my $salt = shift;
|
|
|
|
my $hash = ""; # hash to be returned by this function
|
|
|
|
my $final = md5 ($pass . $salt . $pass);
|
|
|
|
$salt = substr ($salt, 0, 8);
|
|
|
|
my $tmp = $pass . $magic . $salt;
|
|
|
|
my $pass_len = length ($pass);
|
|
|
|
my $i;
|
|
|
|
for ($i = $pass_len; $i > 0; $i -= 16)
|
|
{
|
|
my $len = 16;
|
|
|
|
if ($i < $len)
|
|
{
|
|
$len = $i;
|
|
}
|
|
|
|
$tmp .= substr ($final, 0, $len);
|
|
}
|
|
|
|
$i = $pass_len;
|
|
|
|
while ($i > 0)
|
|
{
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= chr (0);
|
|
}
|
|
else
|
|
{
|
|
$tmp .= substr ($pass, 0, 1);
|
|
}
|
|
|
|
$i >>= 1;
|
|
}
|
|
|
|
$final = md5 ($tmp);
|
|
|
|
for ($i = 0; $i < $iter; $i++)
|
|
{
|
|
$tmp = "";
|
|
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= $pass;
|
|
}
|
|
else
|
|
{
|
|
$tmp .= $final;
|
|
}
|
|
|
|
if ($i % 3)
|
|
{
|
|
$tmp .= $salt;
|
|
}
|
|
|
|
if ($i % 7)
|
|
{
|
|
$tmp .= $pass;
|
|
}
|
|
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= $final;
|
|
}
|
|
else
|
|
{
|
|
$tmp .= $pass;
|
|
}
|
|
|
|
$final = md5 ($tmp);
|
|
}
|
|
|
|
# done
|
|
# now format the output sting ("hash")
|
|
|
|
my $hash_buf;
|
|
|
|
$hash = to64 ((ord (substr ($final, 0, 1)) << 16) | (ord (substr ($final, 6, 1)) << 8) | (ord (substr ($final, 12, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 1, 1)) << 16) | (ord (substr ($final, 7, 1)) << 8) | (ord (substr ($final, 13, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 2, 1)) << 16) | (ord (substr ($final, 8, 1)) << 8) | (ord (substr ($final, 14, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 3, 1)) << 16) | (ord (substr ($final, 9, 1)) << 8) | (ord (substr ($final, 15, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 4, 1)) << 16) | (ord (substr ($final, 10, 1)) << 8) | (ord (substr ($final, 5, 1))), 4);
|
|
$hash .= to64 (ord (substr ($final, 11, 1)), 2);
|
|
|
|
if ($iter == 1000) # default
|
|
{
|
|
$hash_buf = sprintf ("%s%s\$%s", $magic , $salt , $hash);
|
|
}
|
|
else
|
|
{
|
|
$hash_buf = sprintf ("%srounds=%i\$%s\$%s", $magic, $iter, $salt , $hash);
|
|
}
|
|
|
|
return $hash_buf;
|
|
}
|
|
|
|
sub sha512_crypt
|
|
{
|
|
my $iter = shift;
|
|
my $pass = shift;
|
|
my $salt = shift;
|
|
|
|
my $hash = ""; # hash to be returned by this function
|
|
|
|
my $final = sha512 ($pass . $salt . $pass);
|
|
|
|
$salt = substr ($salt, 0, 16);
|
|
|
|
my $tmp = $pass . $salt;
|
|
|
|
my $pass_len = length ($pass);
|
|
my $salt_len = length ($salt);
|
|
|
|
my $i;
|
|
|
|
for ($i = $pass_len; $i > 0; $i -= 16)
|
|
{
|
|
my $len = 16;
|
|
|
|
if ($i < $len)
|
|
{
|
|
$len = $i;
|
|
}
|
|
|
|
$tmp .= substr ($final, 0, $len);
|
|
}
|
|
|
|
$i = $pass_len;
|
|
|
|
while ($i > 0)
|
|
{
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= $final;
|
|
}
|
|
else
|
|
{
|
|
$tmp .= $pass;
|
|
}
|
|
|
|
$i >>= 1;
|
|
}
|
|
|
|
$final = sha512 ($tmp);
|
|
|
|
# p_bytes
|
|
|
|
my $p_bytes = "";
|
|
|
|
for ($i = 0; $i < $pass_len; $i++)
|
|
{
|
|
$p_bytes .= $pass;
|
|
}
|
|
|
|
$p_bytes = sha512 ($p_bytes);
|
|
$p_bytes = substr ($p_bytes, 0, $pass_len);
|
|
|
|
# s_bytes
|
|
|
|
my $final_first_byte = ord (substr ($final, 0, 1));
|
|
|
|
my $s_bytes = "";
|
|
|
|
for ($i = 0; $i < (16 + $final_first_byte); $i++)
|
|
{
|
|
$s_bytes .= $salt;
|
|
}
|
|
|
|
$s_bytes = sha512 ($s_bytes);
|
|
$s_bytes = substr ($s_bytes, 0, $salt_len);
|
|
|
|
for ($i = 0; $i < $iter; $i++)
|
|
{
|
|
$tmp = "";
|
|
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= $p_bytes;
|
|
}
|
|
else
|
|
{
|
|
$tmp .= $final;
|
|
}
|
|
|
|
if ($i % 3)
|
|
{
|
|
$tmp .= $s_bytes;
|
|
}
|
|
|
|
if ($i % 7)
|
|
{
|
|
$tmp .= $p_bytes;
|
|
}
|
|
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= $final;
|
|
}
|
|
else
|
|
{
|
|
$tmp .= $p_bytes;
|
|
}
|
|
|
|
$final = sha512 ($tmp);
|
|
}
|
|
|
|
# done
|
|
# now format the output string ("hash")
|
|
|
|
my $hash_buf;
|
|
|
|
$hash .= to64 ((ord (substr ($final, 0, 1)) << 16) | (ord (substr ($final, 21, 1)) << 8) | (ord (substr ($final, 42, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 22, 1)) << 16) | (ord (substr ($final, 43, 1)) << 8) | (ord (substr ($final, 1, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 44, 1)) << 16) | (ord (substr ($final, 2, 1)) << 8) | (ord (substr ($final, 23, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 3, 1)) << 16) | (ord (substr ($final, 24, 1)) << 8) | (ord (substr ($final, 45, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 25, 1)) << 16) | (ord (substr ($final, 46, 1)) << 8) | (ord (substr ($final, 4, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 47, 1)) << 16) | (ord (substr ($final, 5, 1)) << 8) | (ord (substr ($final, 26, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 6, 1)) << 16) | (ord (substr ($final, 27, 1)) << 8) | (ord (substr ($final, 48, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 28, 1)) << 16) | (ord (substr ($final, 49, 1)) << 8) | (ord (substr ($final, 7, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 50, 1)) << 16) | (ord (substr ($final, 8, 1)) << 8) | (ord (substr ($final, 29, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 9, 1)) << 16) | (ord (substr ($final, 30, 1)) << 8) | (ord (substr ($final, 51, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 31, 1)) << 16) | (ord (substr ($final, 52, 1)) << 8) | (ord (substr ($final, 10, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 53, 1)) << 16) | (ord (substr ($final, 11, 1)) << 8) | (ord (substr ($final, 32, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 12, 1)) << 16) | (ord (substr ($final, 33, 1)) << 8) | (ord (substr ($final, 54, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 34, 1)) << 16) | (ord (substr ($final, 55, 1)) << 8) | (ord (substr ($final, 13, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 56, 1)) << 16) | (ord (substr ($final, 14, 1)) << 8) | (ord (substr ($final, 35, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 15, 1)) << 16) | (ord (substr ($final, 36, 1)) << 8) | (ord (substr ($final, 57, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 37, 1)) << 16) | (ord (substr ($final, 58, 1)) << 8) | (ord (substr ($final, 16, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 59, 1)) << 16) | (ord (substr ($final, 17, 1)) << 8) | (ord (substr ($final, 38, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 18, 1)) << 16) | (ord (substr ($final, 39, 1)) << 8) | (ord (substr ($final, 60, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 40, 1)) << 16) | (ord (substr ($final, 61, 1)) << 8) | (ord (substr ($final, 19, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 62, 1)) << 16) | (ord (substr ($final, 20, 1)) << 8) | (ord (substr ($final, 41, 1))), 4);
|
|
$hash .= to64 (ord (substr ($final, 63, 1)), 2);
|
|
|
|
my $magic = '$6$';
|
|
|
|
if ($iter == 5000) # default
|
|
{
|
|
$hash_buf = sprintf ("%s%s\$%s", $magic, $salt , $hash);
|
|
}
|
|
else
|
|
{
|
|
$hash_buf = sprintf ("%srounds=%i\$%s\$%s", $magic, $iter, $salt , $hash);
|
|
}
|
|
|
|
return $hash_buf;
|
|
}
|
|
|
|
sub sha256_crypt
|
|
{
|
|
my $iter = shift;
|
|
my $pass = shift;
|
|
my $salt = shift;
|
|
|
|
my $hash = ""; # hash to be returned by this function
|
|
|
|
my $final = sha256 ($pass . $salt . $pass);
|
|
|
|
$salt = substr ($salt, 0, 16);
|
|
|
|
my $tmp = $pass . $salt;
|
|
|
|
my $pass_len = length ($pass);
|
|
my $salt_len = length ($salt);
|
|
|
|
my $i;
|
|
|
|
for ($i = $pass_len; $i > 0; $i -= 16)
|
|
{
|
|
my $len = 16;
|
|
|
|
if ($i < $len)
|
|
{
|
|
$len = $i;
|
|
}
|
|
|
|
$tmp .= substr ($final, 0, $len);
|
|
}
|
|
|
|
$i = $pass_len;
|
|
|
|
while ($i > 0)
|
|
{
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= $final;
|
|
}
|
|
else
|
|
{
|
|
$tmp .= $pass;
|
|
}
|
|
|
|
$i >>= 1;
|
|
}
|
|
|
|
$final = sha256 ($tmp);
|
|
|
|
# p_bytes
|
|
|
|
my $p_bytes = "";
|
|
|
|
for ($i = 0; $i < $pass_len; $i++)
|
|
{
|
|
$p_bytes .= $pass;
|
|
}
|
|
|
|
$p_bytes = sha256 ($p_bytes);
|
|
$p_bytes = substr ($p_bytes, 0, $pass_len);
|
|
|
|
# s_bytes
|
|
|
|
my $final_first_byte = ord (substr ($final, 0, 1));
|
|
|
|
my $s_bytes = "";
|
|
|
|
for ($i = 0; $i < (16 + $final_first_byte); $i++)
|
|
{
|
|
$s_bytes .= $salt;
|
|
}
|
|
|
|
$s_bytes = sha256 ($s_bytes);
|
|
$s_bytes = substr ($s_bytes, 0, $salt_len);
|
|
|
|
for ($i = 0; $i < $iter; $i++)
|
|
{
|
|
$tmp = "";
|
|
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= $p_bytes;
|
|
}
|
|
else
|
|
{
|
|
$tmp .= $final;
|
|
}
|
|
|
|
if ($i % 3)
|
|
{
|
|
$tmp .= $s_bytes;
|
|
}
|
|
|
|
if ($i % 7)
|
|
{
|
|
$tmp .= $p_bytes;
|
|
}
|
|
|
|
if ($i & 1)
|
|
{
|
|
$tmp .= $final;
|
|
}
|
|
else
|
|
{
|
|
$tmp .= $p_bytes;
|
|
}
|
|
|
|
$final = sha256 ($tmp);
|
|
}
|
|
|
|
# done
|
|
# now format the output string ("hash")
|
|
|
|
my $hash_buf;
|
|
|
|
$hash .= to64 ((ord (substr ($final, 0, 1)) << 16) | (ord (substr ($final, 10, 1)) << 8) | (ord (substr ($final, 20, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 21, 1)) << 16) | (ord (substr ($final, 1, 1)) << 8) | (ord (substr ($final, 11, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 12, 1)) << 16) | (ord (substr ($final, 22, 1)) << 8) | (ord (substr ($final, 2, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 3, 1)) << 16) | (ord (substr ($final, 13, 1)) << 8) | (ord (substr ($final, 23, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 24, 1)) << 16) | (ord (substr ($final, 4, 1)) << 8) | (ord (substr ($final, 14, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 15, 1)) << 16) | (ord (substr ($final, 25, 1)) << 8) | (ord (substr ($final, 5, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 6, 1)) << 16) | (ord (substr ($final, 16, 1)) << 8) | (ord (substr ($final, 26, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 27, 1)) << 16) | (ord (substr ($final, 7, 1)) << 8) | (ord (substr ($final, 17, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 18, 1)) << 16) | (ord (substr ($final, 28, 1)) << 8) | (ord (substr ($final, 8, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 9, 1)) << 16) | (ord (substr ($final, 19, 1)) << 8) | (ord (substr ($final, 29, 1))), 4);
|
|
$hash .= to64 ((ord (substr ($final, 31, 1)) << 8) | (ord (substr ($final, 30, 1))), 3);
|
|
|
|
my $magic = '$5$';
|
|
|
|
if ($iter == 5000) # default
|
|
{
|
|
$hash_buf = sprintf ("%s%s\$%s", $magic, $salt , $hash);
|
|
}
|
|
else
|
|
{
|
|
$hash_buf = sprintf ("%srounds=%i\$%s\$%s", $magic, $iter, $salt , $hash);
|
|
}
|
|
|
|
return $hash_buf;
|
|
}
|
|
|
|
sub aix_ssha256_pbkdf2
|
|
{
|
|
my $word_buf = shift;
|
|
my $salt_buf = shift;
|
|
my $iterations = shift;
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256);
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
output_len => 32
|
|
);
|
|
|
|
my $hash_buf = $pbkdf2->PBKDF2 ($salt_buf, $word_buf);
|
|
|
|
my $tmp_hash = "";
|
|
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 0, 1))) << 16) | (int (ord (substr ($hash_buf, 1, 1))) << 8) | (int (ord (substr ($hash_buf, 2, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 3, 1))) << 16) | (int (ord (substr ($hash_buf, 4, 1))) << 8) | (int (ord (substr ($hash_buf, 5, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 6, 1))) << 16) | (int (ord (substr ($hash_buf, 7, 1))) << 8) | (int (ord (substr ($hash_buf, 8, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 9, 1))) << 16) | (int (ord (substr ($hash_buf, 10, 1))) << 8) | (int (ord (substr ($hash_buf, 11, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 12, 1))) << 16) | (int (ord (substr ($hash_buf, 13, 1))) << 8) | (int (ord (substr ($hash_buf, 14, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 15, 1))) << 16) | (int (ord (substr ($hash_buf, 16, 1))) << 8) | (int (ord (substr ($hash_buf, 17, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 18, 1))) << 16) | (int (ord (substr ($hash_buf, 19, 1))) << 8) | (int (ord (substr ($hash_buf, 20, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 21, 1))) << 16) | (int (ord (substr ($hash_buf, 22, 1))) << 8) | (int (ord (substr ($hash_buf, 23, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 24, 1))) << 16) | (int (ord (substr ($hash_buf, 25, 1))) << 8) | (int (ord (substr ($hash_buf, 26, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 27, 1))) << 16) | (int (ord (substr ($hash_buf, 28, 1))) << 8) | (int (ord (substr ($hash_buf, 29, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 30, 1))) << 16) | (int (ord (substr ($hash_buf, 31, 1))) << 8) , 3);
|
|
|
|
return $tmp_hash;
|
|
}
|
|
|
|
sub aix_ssha512_pbkdf2
|
|
{
|
|
my $word_buf = shift;
|
|
my $salt_buf = shift;
|
|
my $iterations = shift;
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 512);
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
);
|
|
|
|
my $hash_buf = $pbkdf2->PBKDF2 ($salt_buf, $word_buf);
|
|
|
|
my $tmp_hash = "";
|
|
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 0, 1))) << 16) | (int (ord (substr ($hash_buf, 1, 1))) << 8) | (int (ord (substr ($hash_buf, 2, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 3, 1))) << 16) | (int (ord (substr ($hash_buf, 4, 1))) << 8) | (int (ord (substr ($hash_buf, 5, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 6, 1))) << 16) | (int (ord (substr ($hash_buf, 7, 1))) << 8) | (int (ord (substr ($hash_buf, 8, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 9, 1))) << 16) | (int (ord (substr ($hash_buf, 10, 1))) << 8) | (int (ord (substr ($hash_buf, 11, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 12, 1))) << 16) | (int (ord (substr ($hash_buf, 13, 1))) << 8) | (int (ord (substr ($hash_buf, 14, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 15, 1))) << 16) | (int (ord (substr ($hash_buf, 16, 1))) << 8) | (int (ord (substr ($hash_buf, 17, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 18, 1))) << 16) | (int (ord (substr ($hash_buf, 19, 1))) << 8) | (int (ord (substr ($hash_buf, 20, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 21, 1))) << 16) | (int (ord (substr ($hash_buf, 22, 1))) << 8) | (int (ord (substr ($hash_buf, 23, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 24, 1))) << 16) | (int (ord (substr ($hash_buf, 25, 1))) << 8) | (int (ord (substr ($hash_buf, 26, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 27, 1))) << 16) | (int (ord (substr ($hash_buf, 28, 1))) << 8) | (int (ord (substr ($hash_buf, 29, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 30, 1))) << 16) | (int (ord (substr ($hash_buf, 31, 1))) << 8) | (int (ord (substr ($hash_buf, 32, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 33, 1))) << 16) | (int (ord (substr ($hash_buf, 34, 1))) << 8) | (int (ord (substr ($hash_buf, 35, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 36, 1))) << 16) | (int (ord (substr ($hash_buf, 37, 1))) << 8) | (int (ord (substr ($hash_buf, 38, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 39, 1))) << 16) | (int (ord (substr ($hash_buf, 40, 1))) << 8) | (int (ord (substr ($hash_buf, 41, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 42, 1))) << 16) | (int (ord (substr ($hash_buf, 43, 1))) << 8) | (int (ord (substr ($hash_buf, 44, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 45, 1))) << 16) | (int (ord (substr ($hash_buf, 46, 1))) << 8) | (int (ord (substr ($hash_buf, 47, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 48, 1))) << 16) | (int (ord (substr ($hash_buf, 49, 1))) << 8) | (int (ord (substr ($hash_buf, 50, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 51, 1))) << 16) | (int (ord (substr ($hash_buf, 52, 1))) << 8) | (int (ord (substr ($hash_buf, 53, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 54, 1))) << 16) | (int (ord (substr ($hash_buf, 55, 1))) << 8) | (int (ord (substr ($hash_buf, 56, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 57, 1))) << 16) | (int (ord (substr ($hash_buf, 58, 1))) << 8) | (int (ord (substr ($hash_buf, 59, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 60, 1))) << 16) | (int (ord (substr ($hash_buf, 61, 1))) << 8) | (int (ord (substr ($hash_buf, 62, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 63, 1))) << 16) , 2);
|
|
|
|
return $tmp_hash;
|
|
}
|
|
|
|
sub aix_ssha1_pbkdf2
|
|
{
|
|
my $word_buf = shift;
|
|
my $salt_buf = shift;
|
|
my $iterations = shift;
|
|
|
|
my $hasher = Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1');
|
|
|
|
my $pbkdf2 = Crypt::PBKDF2->new (
|
|
hasher => $hasher,
|
|
iterations => $iterations,
|
|
);
|
|
|
|
my $hash_buf = $pbkdf2->PBKDF2 ($salt_buf, $word_buf);
|
|
|
|
my $tmp_hash = "";
|
|
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 0, 1))) << 16) | (int (ord (substr ($hash_buf, 1, 1))) << 8) | (int (ord (substr ($hash_buf, 2, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 3, 1))) << 16) | (int (ord (substr ($hash_buf, 4, 1))) << 8) | (int (ord (substr ($hash_buf, 5, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 6, 1))) << 16) | (int (ord (substr ($hash_buf, 7, 1))) << 8) | (int (ord (substr ($hash_buf, 8, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 9, 1))) << 16) | (int (ord (substr ($hash_buf, 10, 1))) << 8) | (int (ord (substr ($hash_buf, 11, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 12, 1))) << 16) | (int (ord (substr ($hash_buf, 13, 1))) << 8) | (int (ord (substr ($hash_buf, 14, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 15, 1))) << 16) | (int (ord (substr ($hash_buf, 16, 1))) << 8) | (int (ord (substr ($hash_buf, 17, 1)))), 4);
|
|
$tmp_hash .= to64 ((int (ord (substr ($hash_buf, 18, 1))) << 16) | (int (ord (substr ($hash_buf, 19, 1))) << 8) , 3);
|
|
|
|
return $tmp_hash;
|
|
}
|
|
|
|
sub sapb_transcode
|
|
{
|
|
my $data_s = shift;
|
|
|
|
my @data = split "", $data_s;
|
|
|
|
my $transTable_s =
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\x3f\x40\x41\x50\x43\x44\x45\x4b\x47\x48\x4d\x4e\x54\x51\x53\x46" .
|
|
"\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x56\x55\x5c\x49\x5d\x4a" .
|
|
"\x42\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" .
|
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x58\x5b\x59\xff\x52" .
|
|
"\x4c\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" .
|
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x57\x5e\x5a\x4f\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" .
|
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
|
|
|
|
my @transTable = unpack ("C256", $transTable_s);
|
|
|
|
my @out;
|
|
|
|
for (my $i = 0; $i < scalar @data; $i++)
|
|
{
|
|
$out[$i] = $transTable[int (ord ($data[$i]))];
|
|
}
|
|
|
|
return pack ("C*", @out);
|
|
}
|
|
|
|
sub sapb_waldorf
|
|
{
|
|
my $digest_s = shift;
|
|
|
|
my $w_s = shift;
|
|
my $s_s = shift;
|
|
|
|
my @w = unpack "C*", $w_s;
|
|
my @s = unpack "C*", $s_s;
|
|
|
|
my $bcodeTable_s =
|
|
"\x14\x77\xf3\xd4\xbb\x71\x23\xd0\x03\xff\x47\x93\x55\xaa\x66\x91" .
|
|
"\xf2\x88\x6b\x99\xbf\xcb\x32\x1a\x19\xd9\xa7\x82\x22\x49\xa2\x51" .
|
|
"\xe2\xb7\x33\x71\x8b\x9f\x5d\x01\x44\x70\xae\x11\xef\x28\xf0\x0d";
|
|
|
|
my @bcodeTable = unpack ("C48", $bcodeTable_s);
|
|
|
|
my @abcd = unpack ("C16", $digest_s);
|
|
|
|
my $sum20 = ($abcd[0] & 3)
|
|
+ ($abcd[1] & 3)
|
|
+ ($abcd[2] & 3)
|
|
+ ($abcd[3] & 3)
|
|
+ ($abcd[5] & 3);
|
|
|
|
$sum20 |= 0x20;
|
|
|
|
my @out;
|
|
|
|
for (my $i2 = 0; $i2 < $sum20; $i2++)
|
|
{
|
|
$out[$i2] = 0;
|
|
}
|
|
|
|
for (my $i1 = 0, my $i2 = 0, my $i3 = 0; $i2 < $sum20; $i2++, $i2++)
|
|
{
|
|
if ($i1 < length $w_s)
|
|
{
|
|
if ($abcd[15 - $i1] & 1)
|
|
{
|
|
$out[$i2] = $bcodeTable[48 - 1 - $i1];
|
|
|
|
$i2++;
|
|
}
|
|
|
|
$out[$i2] = $w[$i1];
|
|
|
|
$i1++;
|
|
$i2++;
|
|
}
|
|
|
|
if ($i3 < length $s_s)
|
|
{
|
|
$out[$i2] = $s[$i3];
|
|
|
|
$i2++;
|
|
$i3++;
|
|
}
|
|
|
|
$out[$i2] = $bcodeTable[$i2 - $i1 - $i3];
|
|
}
|
|
|
|
return substr (pack ("C*", @out), 0, $sum20);
|
|
}
|
|
|
|
sub setup_des_key
|
|
{
|
|
my @key_56 = split (//, shift);
|
|
|
|
my $key = "";
|
|
|
|
$key = $key_56[0];
|
|
|
|
$key .= chr (((ord ($key_56[0]) << 7) | (ord ($key_56[1]) >> 1)) & 255);
|
|
$key .= chr (((ord ($key_56[1]) << 6) | (ord ($key_56[2]) >> 2)) & 255);
|
|
$key .= chr (((ord ($key_56[2]) << 5) | (ord ($key_56[3]) >> 3)) & 255);
|
|
$key .= chr (((ord ($key_56[3]) << 4) | (ord ($key_56[4]) >> 4)) & 255);
|
|
$key .= chr (((ord ($key_56[4]) << 3) | (ord ($key_56[5]) >> 5)) & 255);
|
|
$key .= chr (((ord ($key_56[5]) << 2) | (ord ($key_56[6]) >> 6)) & 255);
|
|
$key .= chr (( ord ($key_56[6]) << 1) & 255);
|
|
|
|
return $key;
|
|
}
|
|
|
|
sub randbytes
|
|
{
|
|
my $len = shift;
|
|
|
|
my @arr;
|
|
|
|
for (my $i = 0; $i < $len; $i++)
|
|
{
|
|
my $c = get_random_chr (0, 255);
|
|
|
|
push (@arr, $c);
|
|
}
|
|
|
|
return join ("", @arr);
|
|
}
|
|
|
|
sub get_random_netntlmv1_salt
|
|
{
|
|
my $len_user = shift;
|
|
my $len_domain = shift;
|
|
|
|
my $char;
|
|
my $type;
|
|
my $user = "";
|
|
|
|
for (my $i = 0; $i < $len_user; $i++)
|
|
{
|
|
$type = get_random_num (1, 3);
|
|
|
|
if ($type == 1)
|
|
{
|
|
$char = get_random_chr (0x30, 0x39);
|
|
}
|
|
elsif ($type == 2)
|
|
{
|
|
$char = get_random_chr (0x41, 0x5A);
|
|
}
|
|
else
|
|
{
|
|
$char = get_random_chr (0x61, 0x7A);
|
|
}
|
|
|
|
$user .= $char;
|
|
}
|
|
|
|
my $domain = "";
|
|
|
|
for (my $i = 0; $i < $len_domain; $i++)
|
|
{
|
|
$type = get_random_num (1, 3);
|
|
|
|
if ($type == 1)
|
|
{
|
|
$char = get_random_chr (0x30, 0x39);
|
|
}
|
|
elsif ($type == 2)
|
|
{
|
|
$char = get_random_chr (0x41, 0x5A);
|
|
}
|
|
else
|
|
{
|
|
$char = get_random_chr (0x61, 0x7A);
|
|
}
|
|
|
|
$domain .= $char;
|
|
}
|
|
|
|
my $c_challenge = randbytes (8);
|
|
my $s_challenge = randbytes (8);
|
|
|
|
my $salt_buf = $user . "::" . $domain . ":" . unpack ("H*", $c_challenge) . unpack ("H*", $s_challenge);
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_netntlmv2_salt
|
|
{
|
|
my $len_user = shift;
|
|
my $len_domain = shift;
|
|
|
|
my $char;
|
|
my $type;
|
|
my $user = "";
|
|
|
|
if ($len_user + $len_domain > 27)
|
|
{
|
|
if ($len_user > $len_domain)
|
|
{
|
|
$len_user = 27 - $len_domain;
|
|
}
|
|
else
|
|
{
|
|
$len_domain = 27 - $len_user;
|
|
}
|
|
}
|
|
|
|
for (my $i = 0; $i < $len_user; $i++)
|
|
{
|
|
$type = get_random_num (1, 3);
|
|
|
|
if ($type == 1)
|
|
{
|
|
$char = get_random_chr (0x30, 0x39);
|
|
}
|
|
elsif ($type == 2)
|
|
{
|
|
$char = get_random_chr (0x41, 0x5A);
|
|
}
|
|
else
|
|
{
|
|
$char = get_random_chr (0x61, 0x7A);
|
|
}
|
|
|
|
$user .= $char;
|
|
}
|
|
|
|
my $domain = "";
|
|
|
|
for (my $i = 0; $i < $len_domain; $i++)
|
|
{
|
|
$type = get_random_num (1, 3);
|
|
|
|
if ($type == 1)
|
|
{
|
|
$char = get_random_chr (0x30, 0x39);
|
|
}
|
|
elsif ($type == 2)
|
|
{
|
|
$char = get_random_chr (0x41, 0x5A);
|
|
}
|
|
else
|
|
{
|
|
$char = get_random_chr (0x61, 0x7A);
|
|
}
|
|
|
|
$domain .= $char;
|
|
}
|
|
|
|
my $c_challenge = randbytes (8);
|
|
my $s_challenge = randbytes (8);
|
|
|
|
my $temp = "\x01\x01" .
|
|
"\x00" x 6 .
|
|
randbytes (8) .
|
|
$c_challenge .
|
|
"\x00" x 4 .
|
|
randbytes (20 * rand () + 1) .
|
|
"\x00";
|
|
|
|
my $salt_buf = $user . "::" . $domain . ":" . unpack ("H*", $s_challenge) . unpack ("H*", $temp);
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_ike_salt
|
|
{
|
|
my $nr_buf = "";
|
|
|
|
for (my $i = 0; $i < 40; $i++)
|
|
{
|
|
$nr_buf .= get_random_chr (0, 0xff);
|
|
}
|
|
|
|
my $msg_buf = "";
|
|
|
|
for (my $i = 0; $i < 440; $i++)
|
|
{
|
|
$msg_buf .= get_random_chr (0, 0xff);
|
|
}
|
|
|
|
my $nr_buf_hex = unpack ("H*", $nr_buf);
|
|
my $msg_buf_hex = unpack ("H*", $msg_buf);
|
|
|
|
my $salt_buf = sprintf ("%s:%s:%s:%s:%s:%s:%s:%s", substr ($msg_buf_hex, 0, 256), substr ($msg_buf_hex, 256, 256), substr ($msg_buf_hex, 512, 16), substr ($msg_buf_hex, 528, 16), substr ($msg_buf_hex, 544, 320), substr ($msg_buf_hex, 864, 16), substr ($nr_buf_hex, 0, 40), substr ($nr_buf_hex, 40, 40));
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_agilekeychain_salt
|
|
{
|
|
my $salt_buf = "";
|
|
|
|
for (my $i = 0; $i < 8; $i++)
|
|
{
|
|
$salt_buf .= get_random_chr (0x0, 0xff);
|
|
}
|
|
|
|
my $iv = "";
|
|
|
|
for (my $i = 0; $i < 16; $i++)
|
|
{
|
|
$iv .= get_random_chr (0x0, 0xff);
|
|
}
|
|
|
|
my $prefix = "\x00" x 1008;
|
|
|
|
my $ret = unpack ("H*", $salt_buf . $prefix . $iv);
|
|
|
|
return $ret;
|
|
}
|
|
|
|
sub get_random_cloudkeychain_salt
|
|
{
|
|
my $salt_buf = "";
|
|
|
|
for (my $i = 0; $i < 16; $i++)
|
|
{
|
|
$salt_buf .= get_random_chr (0x0, 0xff);
|
|
}
|
|
|
|
for (my $i = 0; $i < 304; $i++)
|
|
{
|
|
$salt_buf .= get_random_chr (0x0, 0xff);
|
|
}
|
|
|
|
my $ret = unpack ("H*", $salt_buf);
|
|
|
|
return $ret;
|
|
}
|
|
|
|
sub get_random_kerberos5_salt
|
|
{
|
|
my $custom_salt = shift;
|
|
|
|
my $clear_data = randbytes (14) .
|
|
strftime ("%Y%m%d%H%M%S", localtime) .
|
|
randbytes (8);
|
|
|
|
my $user = "user";
|
|
my $realm = "realm";
|
|
my $salt = "salt";
|
|
|
|
my $salt_buf = $user . "\$" . $realm . "\$" . $salt . "\$" . unpack ("H*", $custom_salt) . "\$" . unpack ("H*", $clear_data) . "\$";
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_kerberos5_tgs_salt
|
|
{
|
|
my $nonce = randbytes (8);
|
|
|
|
my $user = "user";
|
|
my $realm = "realm";
|
|
my $spn = "test/spn";
|
|
|
|
my $salt_buf = $user . "\$" . $realm . "\$" . $spn . "\$" . unpack ("H*", $nonce);
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_kerberos5_as_rep_salt
|
|
{
|
|
my $nonce = randbytes (8);
|
|
|
|
my $user_principal_name = "user\@domain.com";
|
|
my $salt_buf = $user_principal_name . ":" . unpack ("H*", $nonce);
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_axcrypt_salt
|
|
{
|
|
my $mysalt = randbytes (16);
|
|
|
|
$mysalt = unpack ("H*", $mysalt);
|
|
|
|
my $iteration = get_random_num (6, 100000);
|
|
|
|
my $salt_buf = $iteration . '*' . $mysalt;
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_keepass_salt
|
|
{
|
|
my $version = get_random_num (1, 3);
|
|
|
|
my $algorithm;
|
|
|
|
my $iteration;
|
|
|
|
my $final_random_seed;
|
|
|
|
if ($version == 1)
|
|
{
|
|
$algorithm = get_random_num (0, 2);
|
|
|
|
$iteration = get_random_num (50000, 100000);
|
|
|
|
$final_random_seed = randbytes (16);
|
|
$final_random_seed = unpack ("H*", $final_random_seed);
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
$algorithm = 0;
|
|
|
|
$iteration = get_random_num (6000, 100000);
|
|
|
|
$final_random_seed = randbytes (32);
|
|
$final_random_seed = unpack ("H*", $final_random_seed);
|
|
}
|
|
|
|
my $transf_random_seed = randbytes (32);
|
|
$transf_random_seed = unpack ("H*", $transf_random_seed);
|
|
|
|
my $enc_iv = randbytes (16);
|
|
$enc_iv = unpack ("H*", $enc_iv);
|
|
|
|
my $contents_hash = randbytes (32);
|
|
$contents_hash = unpack ("H*", $contents_hash);
|
|
|
|
my $inline_flag = 1;
|
|
|
|
my $contents_len = get_random_num (128, 500);
|
|
|
|
my $contents = randbytes ($contents_len);
|
|
|
|
$contents_len += 16 - $contents_len % 16;
|
|
|
|
$contents = unpack ("H*", $contents);
|
|
|
|
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 . '*' .
|
|
$iteration . '*' .
|
|
$algorithm . '*' .
|
|
$final_random_seed . '*' .
|
|
$transf_random_seed . '*' .
|
|
$enc_iv . '*' .
|
|
$contents_hash . '*' .
|
|
$inline_flag . '*' .
|
|
$contents_len . '*' .
|
|
$contents . '*' .
|
|
$keyfile_attributes;
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
$contents = randbytes (32);
|
|
$contents = unpack ("H*", $contents);
|
|
|
|
$salt_buf = $version . '*' .
|
|
$iteration . '*' .
|
|
$algorithm . '*' .
|
|
$final_random_seed . '*' .
|
|
$transf_random_seed . '*' .
|
|
$enc_iv . '*' .
|
|
$contents_hash . '*' .
|
|
$contents . '*' .
|
|
$keyfile_attributes;
|
|
}
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_pstoken_salt
|
|
{
|
|
my $pstoken_length = get_random_num (16, 256);
|
|
|
|
## not a valid pstoken but a better test
|
|
## because of random length
|
|
|
|
my $pstoken_const = randbytes ($pstoken_length);
|
|
|
|
return unpack ("H*", $pstoken_const);
|
|
}
|
|
|
|
sub get_random_md5chap_salt
|
|
{
|
|
my $salt_buf = shift;
|
|
|
|
my $salt = unpack ("H*", $salt_buf);
|
|
|
|
$salt .= ":";
|
|
|
|
$salt .= unpack ("H*", randbytes (1));
|
|
|
|
return $salt;
|
|
}
|
|
|
|
sub get_random_dnssec_salt
|
|
{
|
|
my $salt_buf = "";
|
|
|
|
$salt_buf .= ".";
|
|
|
|
for (my $i = 0; $i < 8; $i++)
|
|
{
|
|
$salt_buf .= get_random_chr (0x61, 0x7a);
|
|
}
|
|
|
|
$salt_buf .= ".net";
|
|
|
|
$salt_buf .= ":";
|
|
|
|
for (my $i = 0; $i < 8; $i++)
|
|
{
|
|
$salt_buf .= get_random_chr (0x30, 0x39);
|
|
}
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_dpapimk_salt
|
|
{
|
|
my $salt_buf = "";
|
|
|
|
my $version = shift;
|
|
|
|
my $context = get_random_num (1, 3);
|
|
|
|
my $cipher_algo = "";
|
|
|
|
my $hash_algo = "";
|
|
|
|
my $iterations;
|
|
|
|
my $SID = sprintf ('S-15-21-%d-%d-%d-%d',
|
|
get_random_num (400000000,490000000),
|
|
get_random_num (400000000,490000000),
|
|
get_random_num (400000000,490000000),
|
|
get_random_num (1000,1999));
|
|
|
|
my $cipher_len = 0;
|
|
|
|
if ($version == 1)
|
|
{
|
|
$iterations = get_random_num (4000, 24000);
|
|
|
|
$cipher_algo = "des3";
|
|
|
|
$hash_algo = "sha1";
|
|
|
|
$cipher_len = 208;
|
|
}
|
|
elsif ($version == 2)
|
|
{
|
|
$iterations = get_random_num (8000, 17000);
|
|
|
|
$cipher_algo = "aes256";
|
|
|
|
$hash_algo = "sha512";
|
|
|
|
$cipher_len = 288;
|
|
}
|
|
|
|
my $iv = randbytes (16);
|
|
$iv = unpack ("H*", $iv);
|
|
|
|
$salt_buf = $version . '*' .
|
|
$context . '*' .
|
|
$SID . '*' .
|
|
$cipher_algo . '*' .
|
|
$hash_algo . '*' .
|
|
$iterations . '*' .
|
|
$iv . '*' .
|
|
$cipher_len . '*';
|
|
|
|
return $salt_buf;
|
|
}
|
|
|
|
sub get_random_jwt_salt
|
|
{
|
|
my @hashes =
|
|
(
|
|
"HS256",
|
|
#"HS384", #this is support in hashcat, but commented out here to prevent mixed hash output files in single mode
|
|
#"HS512", #this is support in hashcat, but commented out here to prevent mixed hash output files in single mode
|
|
#"RS256", #not supported by hashcat
|
|
#"RS384",
|
|
#"RS512",
|
|
#"PS256",
|
|
#"PS384",
|
|
#"PS512",
|
|
#"ES256",
|
|
#"ES384",
|
|
#"ES512",
|
|
);
|
|
|
|
my $rnd = get_random_num (0, scalar @hashes);
|
|
|
|
my $hash = $hashes[$rnd];
|
|
|
|
my $header =
|
|
{
|
|
"alg" => $hash
|
|
};
|
|
|
|
my $random_key = get_random_num (1, 100000000);
|
|
my $random_val = get_random_num (1, 100000000);
|
|
|
|
my $payload =
|
|
{
|
|
$random_key => $random_val
|
|
};
|
|
|
|
my $header_json = encode_json ($header);
|
|
my $payload_json = encode_json ($payload);
|
|
|
|
my $header_base64 = encode_base64url ($header_json, "");
|
|
my $payload_base64 = encode_base64url ($payload_json, "");
|
|
|
|
return $header_base64 . "." . $payload_base64;
|
|
}
|
|
|
|
sub md5bit
|
|
{
|
|
my $digest = shift;
|
|
my $bit = shift;
|
|
|
|
$bit %= 128;
|
|
|
|
my $byte_off = int ($bit / 8);
|
|
my $bit_off = int ($bit % 8);
|
|
|
|
my $char = substr ($digest, $byte_off, 1);
|
|
my $num = ord ($char);
|
|
|
|
return (($num & (1 << $bit_off)) ? 1 : 0);
|
|
}
|
|
|
|
sub sun_md5
|
|
{
|
|
my $pw = shift;
|
|
my $salt = shift;
|
|
my $iter = shift;
|
|
|
|
my $constant_phrase =
|
|
"To be, or not to be,--that is the question:--\n" .
|
|
"Whether 'tis nobler in the mind to suffer\n" .
|
|
"The slings and arrows of outrageous fortune\n" .
|
|
"Or to take arms against a sea of troubles,\n" .
|
|
"And by opposing end them?--To die,--to sleep,--\n" .
|
|
"No more; and by a sleep to say we end\n" .
|
|
"The heartache, and the thousand natural shocks\n" .
|
|
"That flesh is heir to,--'tis a consummation\n" .
|
|
"Devoutly to be wish'd. To die,--to sleep;--\n" .
|
|
"To sleep! perchance to dream:--ay, there's the rub;\n" .
|
|
"For in that sleep of death what dreams may come,\n" .
|
|
"When we have shuffled off this mortal coil,\n" .
|
|
"Must give us pause: there's the respect\n" .
|
|
"That makes calamity of so long life;\n" .
|
|
"For who would bear the whips and scorns of time,\n" .
|
|
"The oppressor's wrong, the proud man's contumely,\n" .
|
|
"The pangs of despis'd love, the law's delay,\n" .
|
|
"The insolence of office, and the spurns\n" .
|
|
"That patient merit of the unworthy takes,\n" .
|
|
"When he himself might his quietus make\n" .
|
|
"With a bare bodkin? who would these fardels bear,\n" .
|
|
"To grunt and sweat under a weary life,\n" .
|
|
"But that the dread of something after death,--\n" .
|
|
"The undiscover'd country, from whose bourn\n" .
|
|
"No traveller returns,--puzzles the will,\n" .
|
|
"And makes us rather bear those ills we have\n" .
|
|
"Than fly to others that we know not of?\n" .
|
|
"Thus conscience does make cowards of us all;\n" .
|
|
"And thus the native hue of resolution\n" .
|
|
"Is sicklied o'er with the pale cast of thought;\n" .
|
|
"And enterprises of great pith and moment,\n" .
|
|
"With this regard, their currents turn awry,\n" .
|
|
"And lose the name of action.--Soft you now!\n" .
|
|
"The fair Ophelia!--Nymph, in thy orisons\n" .
|
|
"Be all my sins remember'd.\n\x00";
|
|
|
|
my $constant_len = length ($constant_phrase);
|
|
|
|
my $hash_buf = md5 ($pw . $salt);
|
|
|
|
my $W;
|
|
|
|
my $to_hash;
|
|
|
|
for (my $round = 0; $round < $iter; $round++)
|
|
{
|
|
my $shift_a = md5bit ($hash_buf, $round + 0);
|
|
my $shift_b = md5bit ($hash_buf, $round + 64);
|
|
|
|
my @shift_4;
|
|
my @shift_7;
|
|
|
|
for (my $k = 0; $k < 16; $k++)
|
|
{
|
|
my $s7shift = ord (substr ($hash_buf, $k, 1)) % 8;
|
|
|
|
my $l = ($k + 3) % 16;
|
|
|
|
my $num = ord (substr ($hash_buf, $l, 1));
|
|
|
|
$shift_4[$k] = $num % 5;
|
|
|
|
$shift_7[$k] = ($num >> $s7shift) & 1;
|
|
}
|
|
|
|
my @indirect_4;
|
|
|
|
for (my $k = 0; $k < 16; $k++)
|
|
{
|
|
$indirect_4[$k] = (ord (substr ($hash_buf, $k, 1)) >> $shift_4[$k]) & 0xf;
|
|
}
|
|
|
|
my @indirect_7;
|
|
|
|
for (my $k = 0; $k < 16; $k++)
|
|
{
|
|
$indirect_7[$k] = (ord (substr ($hash_buf, $indirect_4[$k], 1)) >> $shift_7[$k]) & 0x7f;
|
|
}
|
|
|
|
my $indirect_a = 0;
|
|
my $indirect_b = 0;
|
|
|
|
for (my $k = 0; $k < 8; $k++)
|
|
{
|
|
$indirect_a |= md5bit ($hash_buf, $indirect_7[$k + 0]) << $k;
|
|
|
|
$indirect_b |= md5bit ($hash_buf, $indirect_7[$k + 8]) << $k;
|
|
}
|
|
|
|
$indirect_a = ($indirect_a >> $shift_a) & 0x7f;
|
|
$indirect_b = ($indirect_b >> $shift_b) & 0x7f;
|
|
|
|
my $bit_a = md5bit ($hash_buf, $indirect_a);
|
|
my $bit_b = md5bit ($hash_buf, $indirect_b);
|
|
|
|
$W = $hash_buf;
|
|
|
|
my $pos = 16;
|
|
|
|
my $total = $pos;
|
|
|
|
$to_hash = "";
|
|
|
|
if ($bit_a ^ $bit_b)
|
|
{
|
|
substr ($W, 16, 48) = substr ($constant_phrase, 0, 48);
|
|
|
|
$total += 48;
|
|
|
|
$to_hash .= substr ($W, 0, 64);
|
|
|
|
my $constant_off;
|
|
|
|
for ($constant_off = 48; $constant_off < $constant_len - 64; $constant_off += 64)
|
|
{
|
|
substr ($W, 0, 64) = substr ($constant_phrase, $constant_off, 64);
|
|
|
|
$total += 64;
|
|
|
|
$to_hash .= substr ($W, 0, 64);
|
|
}
|
|
|
|
$pos = $constant_len - $constant_off;
|
|
|
|
$total += $pos;
|
|
|
|
substr ($W, 0, $pos) = substr ($constant_phrase, $constant_off, $pos);
|
|
}
|
|
|
|
my $a_len = 0;
|
|
|
|
my @a_buf;
|
|
$a_buf[0] = 0;
|
|
$a_buf[1] = 0;
|
|
$a_buf[2] = 0;
|
|
$a_buf[3] = 0;
|
|
|
|
my $tmp = $round;
|
|
|
|
do
|
|
{
|
|
my $round_div = int ($tmp / 10);
|
|
my $round_mod = int ($tmp % 10);
|
|
|
|
$tmp = $round_div;
|
|
|
|
$a_buf[int ($a_len / 4)] = (($round_mod + 0x30) | ($a_buf[int ($a_len / 4)] << 8));
|
|
|
|
$a_len++;
|
|
|
|
} while ($tmp);
|
|
|
|
my $tmp_str = "";
|
|
|
|
my $g;
|
|
|
|
for ($g = 0; $g < $a_len; $g++)
|
|
{
|
|
my $remainder = $a_buf[$g];
|
|
my $factor = 7;
|
|
my $started = 1;
|
|
|
|
my $sub;
|
|
|
|
while ($remainder > 0)
|
|
{
|
|
$sub = $remainder >> (8 * $factor);
|
|
|
|
if ($started != 1 || $sub > 0)
|
|
{
|
|
$started = 0;
|
|
|
|
$tmp_str = chr ($sub) . $tmp_str;
|
|
|
|
$remainder -= ($sub << (8 * $factor));
|
|
}
|
|
|
|
$factor--;
|
|
}
|
|
|
|
}
|
|
|
|
substr ($W, $pos, $a_len) = $tmp_str;
|
|
|
|
$pos += $a_len;
|
|
|
|
$total += $a_len;
|
|
|
|
$to_hash .= substr ($W, 0, $pos);
|
|
|
|
$to_hash = substr ($to_hash, 0, $total);
|
|
|
|
$hash_buf = md5 ($to_hash);
|
|
}
|
|
|
|
my $passwd = "";
|
|
|
|
$passwd .= to64 ((int (ord (substr ($hash_buf, 0, 1))) << 16) | (int (ord (substr ($hash_buf, 6, 1))) << 8) | (int (ord (substr ($hash_buf, 12, 1)))), 4);
|
|
$passwd .= to64 ((int (ord (substr ($hash_buf, 1, 1))) << 16) | (int (ord (substr ($hash_buf, 7, 1))) << 8) | (int (ord (substr ($hash_buf, 13, 1)))), 4);
|
|
$passwd .= to64 ((int (ord (substr ($hash_buf, 2, 1))) << 16) | (int (ord (substr ($hash_buf, 8, 1))) << 8) | (int (ord (substr ($hash_buf, 14, 1)))), 4);
|
|
$passwd .= to64 ((int (ord (substr ($hash_buf, 3, 1))) << 16) | (int (ord (substr ($hash_buf, 9, 1))) << 8) | (int (ord (substr ($hash_buf, 15, 1)))), 4);
|
|
$passwd .= to64 ((int (ord (substr ($hash_buf, 4, 1))) << 16) | (int (ord (substr ($hash_buf, 10, 1))) << 8) | (int (ord (substr ($hash_buf, 5, 1)))), 4);
|
|
$passwd .= to64 ((int (ord (substr ($hash_buf, 11, 1)))), 2);
|
|
|
|
return $passwd;
|
|
}
|
|
|
|
sub usage_die
|
|
{
|
|
die ("usage: $0 single|passthrough| [mode] [len]\n" .
|
|
" or\n" .
|
|
" $0 verify [mode] [hashfile] [cracks] [outfile]\n");
|
|
}
|
|
|
|
sub pad16
|
|
{
|
|
my $block_ref = shift;
|
|
|
|
my $offset = shift;
|
|
|
|
my $value = 16 - $offset;
|
|
|
|
for (my $i = $offset; $i < 16; $i++)
|
|
{
|
|
push @{$block_ref}, $value;
|
|
}
|
|
}
|
|
|
|
sub lotus_mix
|
|
{
|
|
my $in_ref = shift;
|
|
|
|
my $p = 0;
|
|
|
|
for (my $i = 0; $i < 18; $i++)
|
|
{
|
|
for (my $j = 0; $j < 48; $j++)
|
|
{
|
|
$p = ($p + 48 - $j) & 0xff;
|
|
|
|
my $c = $LOTUS_MAGIC_TABLE->[$p];
|
|
|
|
$p = $in_ref->[$j] ^ $c;
|
|
|
|
$in_ref->[$j] = $p;
|
|
}
|
|
}
|
|
}
|
|
|
|
sub lotus_transform_password
|
|
{
|
|
my $in_ref = shift;
|
|
my $out_ref = shift;
|
|
|
|
my $t = $out_ref->[15];
|
|
|
|
for (my $i = 0; $i < 16; $i++)
|
|
{
|
|
$t ^= $in_ref->[$i];
|
|
|
|
my $c = $LOTUS_MAGIC_TABLE->[$t];
|
|
|
|
$out_ref->[$i] ^= $c;
|
|
|
|
$t = $out_ref->[$i];
|
|
}
|
|
}
|
|
|
|
sub mdtransform_norecalc
|
|
{
|
|
my $state_ref = shift;
|
|
my $block_ref = shift;
|
|
|
|
my @x;
|
|
|
|
push (@x, @{$state_ref});
|
|
push (@x, @{$block_ref});
|
|
|
|
for (my $i = 0; $i < 16; $i++)
|
|
{
|
|
push (@x, $x[0 + $i] ^ $x[16 + $i]);
|
|
}
|
|
|
|
lotus_mix (\@x);
|
|
|
|
for (my $i = 0; $i < 16; $i++)
|
|
{
|
|
$state_ref->[$i] = $x[$i];
|
|
}
|
|
}
|
|
|
|
sub mdtransform
|
|
{
|
|
my $state_ref = shift;
|
|
my $checksum_ref = shift;
|
|
my $block_ref = shift;
|
|
|
|
mdtransform_norecalc ($state_ref, $block_ref);
|
|
|
|
lotus_transform_password ($block_ref, $checksum_ref);
|
|
}
|
|
|
|
sub domino_big_md
|
|
{
|
|
my $saved_key_ref = shift;
|
|
|
|
my $size = shift;
|
|
|
|
@{$saved_key_ref} = splice (@{$saved_key_ref}, 0, $size);
|
|
|
|
my @state = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
|
|
my @checksum;
|
|
|
|
my $curpos;
|
|
|
|
for ($curpos = 0; $curpos + 16 < $size; $curpos += 16)
|
|
{
|
|
my @block = splice (@{$saved_key_ref}, 0, 16);
|
|
|
|
mdtransform (\@state, \@checksum, \@block);
|
|
}
|
|
|
|
my $left = $size - $curpos;
|
|
|
|
my @block = splice (@{$saved_key_ref}, 0, 16);
|
|
|
|
pad16 (\@block, $left);
|
|
|
|
mdtransform (\@state, \@checksum, \@block);
|
|
|
|
mdtransform_norecalc (\@state, \@checksum);
|
|
|
|
return @state;
|
|
}
|
|
|
|
sub pdf_compute_encryption_key
|
|
{
|
|
my $word_buf = shift;
|
|
my $padding = shift;
|
|
my $id = shift;
|
|
my $u = shift;
|
|
my $o = shift;
|
|
my $P = shift;
|
|
my $V = shift;
|
|
my $R = shift;
|
|
my $enc = shift;
|
|
|
|
## start
|
|
|
|
my $data;
|
|
|
|
$data .= $word_buf;
|
|
|
|
$data .= substr ($padding, 0, 32 - length $word_buf);
|
|
|
|
$data .= pack ("H*", $o);
|
|
|
|
$data .= pack ("I", $P);
|
|
|
|
$data .= pack ("H*", $id);
|
|
|
|
if ($R >= 4)
|
|
{
|
|
if (!$enc)
|
|
{
|
|
$data .= pack ("I", -1);
|
|
}
|
|
}
|
|
|
|
my $res = md5 ($data);
|
|
|
|
if ($R >= 3)
|
|
{
|
|
for (my $i = 0; $i < 50; $i++)
|
|
{
|
|
$res = md5 ($res);
|
|
}
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
sub gen_random_wpa_eapol
|
|
{
|
|
my $keyver = shift;
|
|
my $snonce = shift;
|
|
|
|
my $ret = "";
|
|
|
|
# version
|
|
|
|
my $version = 1; # 802.1X-2001
|
|
|
|
$ret .= pack ("C*", $version);
|
|
|
|
my $type = 3; # means that this EAPOL frame is used to transfer key information
|
|
|
|
$ret .= pack ("C*", $type);
|
|
|
|
my $length; # length of remaining data
|
|
|
|
if ($keyver == 1)
|
|
{
|
|
$length = 119;
|
|
}
|
|
else
|
|
{
|
|
$length = 117;
|
|
}
|
|
|
|
$ret .= pack ("n*", $length);
|
|
|
|
my $descriptor_type;
|
|
|
|
if ($keyver == 1)
|
|
{
|
|
$descriptor_type = 254; # EAPOL WPA key
|
|
}
|
|
else
|
|
{
|
|
$descriptor_type = 1; # EAPOL RSN key
|
|
}
|
|
|
|
$ret .= pack ("C*", $descriptor_type);
|
|
|
|
# key_info is a bit vector:
|
|
# generated from these 13 bits: encrypted key data, request, error, secure, key mic, key ack, install, key index (2), key type, key descriptor (3)
|
|
|
|
my $key_info = 0;
|
|
|
|
$key_info |= 1 << 8; # set key MIC
|
|
$key_info |= 1 << 3; # set if it is a pairwise key
|
|
|
|
if ($keyver == 1)
|
|
{
|
|
$key_info |= 1 << 0; # RC4 Cipher, HMAC-MD5 MIC
|
|
}
|
|
else
|
|
{
|
|
$key_info |= 1 << 1; # AES Cipher, HMAC-SHA1 MIC
|
|
}
|
|
|
|
$ret .= pack ("n*", $key_info);
|
|
|
|
my $key_length;
|
|
|
|
if ($keyver == 1)
|
|
{
|
|
$key_length = 32;
|
|
}
|
|
else
|
|
{
|
|
$key_length = 0;
|
|
}
|
|
|
|
$ret .= pack ("n*", $key_length);
|
|
|
|
my $replay_counter = 1;
|
|
|
|
$ret .= pack ("Q>*", $replay_counter);
|
|
|
|
$ret .= $snonce;
|
|
|
|
my $key_iv = "\x00" x 16;
|
|
|
|
$ret .= $key_iv;
|
|
|
|
my $key_rsc = "\x00" x 8;
|
|
|
|
$ret .= $key_rsc;
|
|
|
|
my $key_id = "\x00" x 8;
|
|
|
|
$ret .= $key_id;
|
|
|
|
my $key_mic = "\x00" x 16;
|
|
|
|
$ret .= $key_mic;
|
|
|
|
my $key_data_len;
|
|
|
|
if ($keyver == 1)
|
|
{
|
|
$key_data_len = 24; # length of the key_data (== WPA info)
|
|
}
|
|
else
|
|
{
|
|
$key_data_len = 22; # length of the key_data (== RSN info)
|
|
}
|
|
|
|
$ret .= pack ("n*", $key_data_len);
|
|
|
|
my $key_data = "";
|
|
|
|
if ($keyver == 1)
|
|
{
|
|
# wpa info
|
|
|
|
my $wpa_info = "";
|
|
|
|
my $vendor_specific_data = "";
|
|
|
|
my $tag_number = 221; # means it is a vendor specific tag
|
|
|
|
$vendor_specific_data .= pack ("C*", $tag_number);
|
|
|
|
my $tag_len = 22; # length of the remaining "tag data"
|
|
|
|
$vendor_specific_data .= pack ("C*", $tag_len);
|
|
|
|
my $vendor_specific_oui = pack ("H*", "0050f2"); # microsoft
|
|
|
|
$vendor_specific_data .= $vendor_specific_oui;
|
|
|
|
my $vendor_specific_oui_type = 1; # WPA Information Element
|
|
|
|
$vendor_specific_data .= pack ("C*", $vendor_specific_oui_type);
|
|
|
|
my $vendor_specific_wpa_version = 1;
|
|
|
|
$vendor_specific_data .= pack ("v*", $vendor_specific_wpa_version);
|
|
|
|
# multicast
|
|
|
|
my $vendor_specific_multicast_oui = pack ("H*", "0050f2");
|
|
|
|
$vendor_specific_data .= $vendor_specific_multicast_oui;
|
|
|
|
my $vendor_specific_multicast_type = 2; # TKIP
|
|
|
|
$vendor_specific_data .= pack ("C*", $vendor_specific_multicast_type);
|
|
|
|
# unicast
|
|
|
|
my $vendor_specific_unicast_count = 1;
|
|
|
|
$vendor_specific_data .= pack ("v*", $vendor_specific_unicast_count);
|
|
|
|
my $vendor_specific_unicast_oui = pack ("H*", "0050f2");
|
|
|
|
$vendor_specific_data .= $vendor_specific_unicast_oui;
|
|
|
|
my $vendor_specific_unicast_type = 2; # TKIP
|
|
|
|
$vendor_specific_data .= pack ("C*", $vendor_specific_unicast_type);
|
|
|
|
# Auth Key Management (AKM)
|
|
|
|
my $auth_key_management_count = 1;
|
|
|
|
$vendor_specific_data .= pack ("v*", $auth_key_management_count);
|
|
|
|
my $auth_key_management_oui = pack ("H*", "0050f2");
|
|
|
|
$vendor_specific_data .= $auth_key_management_oui;
|
|
|
|
my $auth_key_management_type = 2; # Pre-Shared Key (PSK)
|
|
|
|
$vendor_specific_data .= pack ("C*", $auth_key_management_type);
|
|
|
|
$wpa_info = $vendor_specific_data;
|
|
|
|
$key_data = $wpa_info;
|
|
}
|
|
else
|
|
{
|
|
# rsn info
|
|
|
|
my $rsn_info = "";
|
|
|
|
my $tag_number = 48; # RSN info
|
|
|
|
$rsn_info .= pack ("C*", $tag_number);
|
|
|
|
my $tag_len = 20; # length of the remaining "tag_data"
|
|
|
|
$rsn_info .= pack ("C*", $tag_len);
|
|
|
|
my $rsn_version = 1;
|
|
|
|
$rsn_info .= pack ("v*", $rsn_version);
|
|
|
|
# group cipher suite
|
|
|
|
my $group_cipher_suite_oui = pack ("H*", "000fac"); # Ieee8021
|
|
|
|
$rsn_info .= $group_cipher_suite_oui;
|
|
|
|
my $group_cipher_suite_type = 4; # AES (CCM)
|
|
|
|
$rsn_info .= pack ("C*", $group_cipher_suite_type);
|
|
|
|
# pairwise cipher suite
|
|
|
|
my $pairwise_cipher_suite_count = 1;
|
|
|
|
$rsn_info .= pack ("v*", $pairwise_cipher_suite_count);
|
|
|
|
my $pairwise_cipher_suite_oui = pack ("H*", "000fac"); # Ieee8021
|
|
|
|
$rsn_info .= $pairwise_cipher_suite_oui;
|
|
|
|
my $pairwise_cipher_suite_type = 4; # AES (CCM)
|
|
|
|
$rsn_info .= pack ("C*", $pairwise_cipher_suite_type);
|
|
|
|
# Auth Key Management (AKM)
|
|
|
|
my $auth_key_management_count = 1;
|
|
|
|
$rsn_info .= pack ("v*", $auth_key_management_count);
|
|
|
|
my $auth_key_management_oui = pack ("H*", "000fac"); # Ieee8021
|
|
|
|
$rsn_info .= $auth_key_management_oui;
|
|
|
|
my $auth_key_management_type = 2; # Pre-Shared Key (PSK)
|
|
|
|
$rsn_info .= pack ("C*", $auth_key_management_type);
|
|
|
|
# RSN Capabilities
|
|
|
|
# bit vector of these 9 bits: peerkey enabled, management frame protection (MFP) capable, MFP required,
|
|
# RSN GTKSA Capabilities (2), RSN PTKSA Capabilities (2), no pairwise Capabilities, Pre-Auth Capabilities
|
|
|
|
my $rsn_capabilities = pack ("H*", "0000");
|
|
|
|
$rsn_info .= $rsn_capabilities;
|
|
|
|
$key_data = $rsn_info;
|
|
}
|
|
|
|
$ret .= $key_data;
|
|
|
|
return $ret;
|
|
}
|
|
|
|
sub wpa_prf_512
|
|
{
|
|
my $keyver = shift;
|
|
my $pmk = shift;
|
|
my $stmac = shift;
|
|
my $bssid = shift;
|
|
my $snonce = shift;
|
|
my $anonce = shift;
|
|
|
|
my $data = "Pairwise key expansion";
|
|
|
|
if (($keyver == 1) || ($keyver == 2))
|
|
{
|
|
$data .= "\x00";
|
|
}
|
|
|
|
#
|
|
# Min(AA, SPA) || Max(AA, SPA)
|
|
#
|
|
|
|
# compare if greater: Min()/Max() on the MACs (6 bytes)
|
|
|
|
if (memcmp ($stmac, $bssid, 6) < 0)
|
|
{
|
|
$data .= $stmac;
|
|
$data .= $bssid;
|
|
}
|
|
else
|
|
{
|
|
$data .= $bssid;
|
|
$data .= $stmac;
|
|
}
|
|
|
|
#
|
|
# Min(ANonce,SNonce) || Max(ANonce,SNonce)
|
|
#
|
|
|
|
# compare if greater: Min()/Max() on the nonces (32 bytes)
|
|
|
|
if (memcmp ($snonce, $anonce, 32) < 0)
|
|
{
|
|
$data .= $snonce;
|
|
$data .= $anonce;
|
|
}
|
|
else
|
|
{
|
|
$data .= $anonce;
|
|
$data .= $snonce;
|
|
}
|
|
|
|
my $prf_buf;
|
|
|
|
if (($keyver == 1) || ($keyver == 2))
|
|
{
|
|
$data .= "\x00";
|
|
|
|
$prf_buf = hmac ($data, $pmk, \&sha1);
|
|
}
|
|
else
|
|
{
|
|
my $data3 = "\x01\x00" . $data . "\x80\x01";
|
|
|
|
$prf_buf = hmac ($data3, $pmk, \&sha256);
|
|
}
|
|
|
|
$prf_buf = substr ($prf_buf, 0, 16);
|
|
|
|
return $prf_buf;
|
|
}
|
|
|
|
sub itunes_aes_wrap
|
|
{
|
|
my $key = shift;
|
|
my $A = shift;
|
|
my $R_l = shift;
|
|
|
|
my $k = scalar (@$R_l);
|
|
my $n = $k + 1;
|
|
|
|
my @R;
|
|
|
|
for (my $i = 0; $i < $n; $i++)
|
|
{
|
|
$R[$i] = @$R_l[$i];
|
|
}
|
|
|
|
# AES mode ECB
|
|
|
|
my $m = Crypt::Mode::ECB->new ('AES', 0);
|
|
|
|
# main wrap loop
|
|
|
|
my ($i, $j, $a);
|
|
|
|
for ($j = 0; $j <= 5; $j++)
|
|
{
|
|
for ($i = 1, $a = 0; $i <= $k; $i++, $a++)
|
|
{
|
|
my $input;
|
|
|
|
$input = pack ("Q>", $A);
|
|
$input .= pack ("Q>", $R[$a]);
|
|
|
|
my $t = $m->encrypt ($input, $key);
|
|
|
|
$A = unpack ("Q>", substr ($t, 0, 8));
|
|
$A ^= $k * $j + $i;
|
|
|
|
$R[$a] = unpack ("Q>", substr ($t, 8, 8));
|
|
}
|
|
}
|
|
|
|
my $WPKY = pack ("Q>", $A);
|
|
|
|
for (my $i = 0; $i < $k; $i++)
|
|
{
|
|
$WPKY .= pack ("Q>", $R[$i]);
|
|
}
|
|
|
|
return $WPKY;
|
|
}
|
|
|
|
sub itunes_aes_unwrap
|
|
{
|
|
my $key = shift;
|
|
my $WPKY = shift;
|
|
|
|
my @B;
|
|
|
|
for (my $i = 0; $i < length ($WPKY) / 8; $i++)
|
|
{
|
|
$B[$i] = unpack ("Q>", substr ($WPKY, $i * 8, 8));
|
|
}
|
|
|
|
my $n = scalar (@B);
|
|
my $k = $n - 1;
|
|
|
|
my @R;
|
|
|
|
for (my $i = 0; $i < $k; $i++)
|
|
{
|
|
$R[$i] = $B[$i + 1];
|
|
}
|
|
|
|
# AES mode ECB
|
|
|
|
my $m = Crypt::Mode::ECB->new ('AES', 0);
|
|
|
|
# main unwrap loop
|
|
|
|
my $A = $B[0];
|
|
|
|
my ($i, $j, $a);
|
|
|
|
for ($j = 5; $j >= 0; $j--)
|
|
{
|
|
for ($i = $k, $a = $k - 1; $i > 0; $i--, $a--)
|
|
{
|
|
my $input;
|
|
|
|
$input = pack ("Q>", $A ^ ($k * $j + $i));
|
|
$input .= pack ("Q>", $R[$a]);
|
|
|
|
my $t = $m->decrypt ($input, $key);
|
|
|
|
$A = unpack ("Q>", substr ($t, 0, 8));
|
|
$R[$a] = unpack ("Q>", substr ($t, 8, 8));
|
|
}
|
|
}
|
|
|
|
return ($A, \@R);
|
|
}
|
|
|
|
sub memcmp
|
|
{
|
|
my $str1 = shift;
|
|
my $str2 = shift;
|
|
my $len = shift;
|
|
|
|
my $len_str1 = length ($str1);
|
|
my $len_str2 = length ($str2);
|
|
|
|
if (($len > $len_str1) || ($len > $len_str2))
|
|
{
|
|
print "ERROR: memcmp () lengths wrong";
|
|
|
|
exit (1);
|
|
}
|
|
|
|
for (my $i = 0; $i < $len; $i++)
|
|
{
|
|
my $c_1 = ord (substr ($str1, $i, 1));
|
|
my $c_2 = ord (substr ($str2, $i, 1));
|
|
|
|
return -1 if ($c_1 < $c_2);
|
|
return 1 if ($c_1 > $c_2);
|
|
}
|
|
|
|
return 0;
|
|
}
|