diff --git a/tools/legacy_test.pl b/tools/legacy_test.pl new file mode 100755 index 000000000..ed03680b0 --- /dev/null +++ b/tools/legacy_test.pl @@ -0,0 +1,13462 @@ +#!/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::GCrypt; +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, 18600, + 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 = ) + { + $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 = ) + { + 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}))); + } + elsif ($mode == 18600) + { + ($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 '0'); + next unless ($cs_type eq '0'); + next unless ($cs_len eq '16'); + next unless ($iv_len eq '8'); + 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 => 16 + ); + + my $pass_hash = sha1 ($word); + my $derived_key = $kdf->PBKDF2 ($b_salt, $pass_hash); + + my $cfb = Crypt::GCrypt->new( + type => 'cipher', + algorithm => 'blowfish', + mode => 'cfb' + ); + + $cfb->start ('decrypting'); + $cfb->setkey ($derived_key); + $cfb->setiv ($b_iv); + + my $b_plaintext = $cfb->decrypt ($b_ciphertext); + + $cfb->finish (); + + 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 hash parser 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); + } + elsif ($mode == 18600) + { + $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)); + } + elsif ($mode == 18600) + { + $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); + } + } + } + elsif ($mode == 18600) + { + 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 == 18600) + { + # defaults for single mode + my $iterations = 1024; + my $iv = "aa" x 8; + 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 => 16 + ); + + my $checksum = sha1_hex ($b_plaintext); + my $pass_hash = sha1 ($word_buf); + my $derived_key = $kdf->PBKDF2 ($b_salt, $pass_hash); + + my $cfb = Crypt::GCrypt->new( + type => 'cipher', + algorithm => 'blowfish', + mode => 'cfb', + ); + + $cfb->start ('encrypting'); + $cfb->setkey ($derived_key); + $cfb->setiv ($b_iv); + + my $b_ciphertext = $cfb->encrypt ($b_plaintext); + + $cfb->finish (); + + my $ciphertext = unpack ("H*", $b_ciphertext); + + $tmp_hash = '$odf$'."*0*0*$iterations*16*$checksum*8*$iv*16*$salt_buf*0*$ciphertext"; + } + elsif ($mode == 99999) + { + $tmp_hash = sprintf ("%s", $word_buf); + } + + return ($tmp_hash); +} + +#Thanks to Jochen Hoenicke +# (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; +} diff --git a/tools/test.pl b/tools/test.pl index ed03680b0..548dde66e 100755 --- a/tools/test.pl +++ b/tools/test.pl @@ -5,13458 +5,207 @@ ## 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::GCrypt; -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; +use Data::Types qw (is_count is_whole); +use File::Basename; +use FindBin; -my $hashcat = "./hashcat"; +# allows require by filename +use lib "$FindBin::Bin/test_modules"; -my $MAX_LEN = 55; +my $TYPES = [ 'single', 'passthrough', 'verify' ]; -## STEP 1: Add your hash mode to this array. -# -# This array contains all supported hash modes. -# -## +my $TYPE = shift @ARGV; +my $MODE = shift @ARGV; -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, 18600, - 99999 -]; +is_in_array ($TYPE, $TYPES) or usage_exit (); -## 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. -# -## +is_whole ($MODE) or die "Mode must be a number\n"; -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 -]; +eval { require "m$MODE.pm" } or die "Could not load test module:\n$@"; -## 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 = +if ($TYPE eq 'single') { - '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 (); + single (@ARGV); } - -my $type; -my $mode; -my $len; - -$type = shift @ARGV; - -if ($type ne "verify") +elsif ($TYPE eq 'passthrough') { - if (scalar @ARGV > 1) - { - $mode = shift @ARGV; - $len = shift @ARGV; - } - elsif (scalar @ARGV == 1) - { - $mode = shift @ARGV; - $len = 0; - } - else - { - $len = 0; - } + passthrough (); +} +elsif ($TYPE eq "verify") +{ + usage_exit () if scalar @ARGV != 3; - if ($type eq "single") - { - single ($mode); - } - elsif ($type eq "passthrough") - { - passthrough ($mode); - } - else - { - usage_die (); - } + verify (@ARGV); } 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 = ) - { - $line =~ s/[\n\r]*$//; - - $db->{$line} = undef; - } - - close (IN); - - verify ($mode, $db, $in_file, $out_file); + usage_exit (); +} + +sub single +{ + exists &{module_generate_hash} or die "Module function not found\n"; + + my $len = shift; + + undef $len unless is_count ($len); + + my $format = "echo -n %-32s | ./hashcat \${OPTS} -a0 -m%d '%s'\n"; + + for (my $i = 1; $i <= 32; $i++) + { + my $cur_len = $len // $i; + + my $word = random_numeric_string ($cur_len); + my $hash = module_generate_hash ($word); + + next unless defined $hash; + + print sprintf ($format, $word, $MODE, $hash); + } +} + +sub passthrough +{ + exists &{module_generate_hash} or die "Module function not found\n"; + + while (<>) + { + chomp $_; + + next if length $_ > 256; + + my $hash = module_generate_hash ($_); + + print "$hash\n"; + } +} + +sub verify +{ + exists &{module_verify_hash} or die "Module function not found\n"; + + my $hashes_file = shift; + my $cracks_file = shift; + my $out_file = shift; + + open (IN, '<', $hashes_file) or die "$hashes_file: $!\n"; + + my $hashlist; + + while () + { + s/[\n\r]*$//; + + push (@{$hashlist}, $_); + } + + close IN; + + open (IN, '<', $cracks_file) or die "$cracks_file: $!\n"; + open (OUT, '>', $out_file ) or die "$out_file: $!\n"; + + while () + { + s/[\n\r]*$//; + + my $hash = module_verify_hash ($_); + + next unless defined $hash; + + next unless is_in_array ($hash, $hashlist); + + print OUT "$_\n"; + } + + close IN; + close OUT; } -# Array lookup sub is_in_array { my $value = shift; my $array = shift; + return unless defined $value; + return unless defined $array; + return grep { $_ eq $value } @{$array}; } -sub verify +sub pack_if_HEX_notation { - my $mode = shift; - my $db = shift; - my $in_file = shift; - my $out_file = shift; + my $string = 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; + return unless defined $string; - 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 = ) + if ($string =~ m/^\$HEX\[[0-9a-fA-F]*\]$/) { - 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}))); - } - elsif ($mode == 18600) - { - ($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 '0'); - next unless ($cs_type eq '0'); - next unless ($cs_len eq '16'); - next unless ($iv_len eq '8'); - 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 => 16 - ); - - my $pass_hash = sha1 ($word); - my $derived_key = $kdf->PBKDF2 ($b_salt, $pass_hash); - - my $cfb = Crypt::GCrypt->new( - type => 'cipher', - algorithm => 'blowfish', - mode => 'cfb' - ); - - $cfb->start ('decrypting'); - $cfb->setkey ($derived_key); - $cfb->setiv ($b_iv); - - my $b_plaintext = $cfb->decrypt ($b_ciphertext); - - $cfb->finish (); - - 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 hash parser 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); - } - elsif ($mode == 18600) - { - $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"; + return pack ("H*", substr ($string, 5, -1)); } - close (IN); - close (OUT); + return $string; } -sub passthrough +sub random_bytes { - my $mode = shift || 0; + my $count = shift; - 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)); - } - elsif ($mode == 18600) - { - $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"; - } + return pack ("H*", random_hex_string (2 * $count)); } -sub single +sub random_hex_string { - my $mode = shift; + my $count = shift; - if (defined $mode) - { - @{$MODES} = ($mode); - } + return if ! is_count ($count); - for (my $j = 0; $j < scalar @{$MODES}; $j++) - { - my $mode = $MODES->[$j]; + my $string; - 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); + $string .= sprintf("%x", rand 16) for (1 .. $count); - 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); - } - } - } - elsif ($mode == 18600) - { - 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 - } + return $string; } -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 +sub random_numeric_string { - my $mode = shift; + my $count = shift; - my $word_buf = shift; + return if ! is_count ($count); - my $salt_buf = shift; + my $string; - my $iter = shift; + $string .= sprintf("%d", rand 10) for (1 .. $count); - 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 == 18600) - { - # defaults for single mode - my $iterations = 1024; - my $iv = "aa" x 8; - 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 => 16 - ); - - my $checksum = sha1_hex ($b_plaintext); - my $pass_hash = sha1 ($word_buf); - my $derived_key = $kdf->PBKDF2 ($b_salt, $pass_hash); - - my $cfb = Crypt::GCrypt->new( - type => 'cipher', - algorithm => 'blowfish', - mode => 'cfb', - ); - - $cfb->start ('encrypting'); - $cfb->setkey ($derived_key); - $cfb->setiv ($b_iv); - - my $b_ciphertext = $cfb->encrypt ($b_plaintext); - - $cfb->finish (); - - my $ciphertext = unpack ("H*", $b_ciphertext); - - $tmp_hash = '$odf$'."*0*0*$iterations*16*$checksum*8*$iv*16*$salt_buf*0*$ciphertext"; - } - elsif ($mode == 99999) - { - $tmp_hash = sprintf ("%s", $word_buf); - } - - return ($tmp_hash); + return $string; } -#Thanks to Jochen Hoenicke -# (one of the authors of Palm Keyring) -# for these next two subs. -sub dpapi_pbkdf2 +sub usage_exit { - 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; + my $f = basename ($0); + + print "\n" + . "Usage:\n" + . " $f single [length]\n" + . " $f passthrough \n" + . " $f verify \n" + . "\n" + . "Single:\n" + . " Generates up to 32 hashes of random numbers of incrementing length, or up to 32\n" + . " hashes of random numbers of exact [length]. Writes shell commands to stdout that\n" + . " can be processed by the test.sh script.\n" + . "\n" + . "Passthrough:\n" + . " Generates hashes for strings entered via stdin and prints them to stdout.\n" + . "\n" + . "Verify:\n" + . " Reads a list of hashes from and a list of hash:password pairs from\n" + . " . Hashes every password and compares the hash to the corresponding\n" + . " entry in the . If the hashes match and the hash is present in the\n" + . " list from , it will be written to the .\n"; + + exit 1; } diff --git a/tools/test_modules/README.md b/tools/test_modules/README.md new file mode 100644 index 000000000..35a951d77 --- /dev/null +++ b/tools/test_modules/README.md @@ -0,0 +1,15 @@ +### Hashcat test modules ### + +Each module provides the two functions `module_generate_hash` and `module_verify_hash`. The first parameter to `module_generate_hash` is the password, which can be either in ASCII or binary (packed) form. The `module_verify_hash` function accepts a line from the cracks file, without the newline characters. + +During `single` and `passthrough` tests the `module_generate_hash` function must provide random values (e.g. salt) for hash generation if necessary. The test.pl script offers a few handy functions like `random_hex_string`, `random_numeric_string` and `random_bytes`. You can implement your own salt generation functions, if your mode has specific requirements. + +During `verify` tests the `module_verify_hash` function must parse the hash:password line and to calculate a hash by passing all necessary data to `module_generate_hash`. How you pass it is up to you, as long as the first parameter is the password. + +**Important**: You have to call `pack_if_HEX_notation` as soon as you have parsed the password, or your tests will fail on passwords in the `$HEX[...]` format. + +#### Examples #### + +* For the most basic test modules, see [m0.pm](m0.pm) and [m100.pm](m100.pm) +* For the basic salted hash tests, see [m110.pm](m110.pm) and [m120.pm](m120.pm) +* For some sligthly more complex modules with PBKDF2 and encryption, see [m18400.pm](m18400.pm) and [m18600.pm](m18600.pm) diff --git a/tools/test_modules/m0.pm b/tools/test_modules/m0.pm new file mode 100644 index 000000000..da25bf5c1 --- /dev/null +++ b/tools/test_modules/m0.pm @@ -0,0 +1,39 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; + +use Digest::MD5 qw (md5_hex); + +sub module_generate_hash +{ + my $word = shift; + + my $hash = md5_hex ($word); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split ":", $line; + + return unless defined $hash; + return unless defined $word; + + $word = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word); + + return unless $new_hash eq $hash; + + return $new_hash; +} + +1; diff --git a/tools/test_modules/m100.pm b/tools/test_modules/m100.pm new file mode 100644 index 000000000..7f87d334f --- /dev/null +++ b/tools/test_modules/m100.pm @@ -0,0 +1,39 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; + +use Digest::SHA qw (sha1_hex); + +sub module_generate_hash +{ + my $word = shift; + + my $hash = sha1_hex ($word); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split (":", $line); + + return unless defined $hash; + return unless defined $word; + + $word = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word); + + return unless $new_hash eq $hash; + + return $new_hash; +} + +1; diff --git a/tools/test_modules/m110.pm b/tools/test_modules/m110.pm new file mode 100644 index 000000000..a4883124c --- /dev/null +++ b/tools/test_modules/m110.pm @@ -0,0 +1,41 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; + +use Digest::SHA qw (sha1_hex); + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift // random_numeric_string (int (rand 16)); + + my $hash = sha1_hex ($word . $salt) . ":$salt"; + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $salt, $word) = split (":", $line); + + return unless defined $hash; + return unless defined $salt; + return unless defined $word; + + $word = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word, $salt); + + return unless $new_hash eq "$hash:$salt"; + + return $new_hash; +} + +1; diff --git a/tools/test_modules/m120.pm b/tools/test_modules/m120.pm new file mode 100644 index 000000000..765f959e6 --- /dev/null +++ b/tools/test_modules/m120.pm @@ -0,0 +1,41 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; + +use Digest::SHA qw (sha1_hex); + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift // random_numeric_string (int (rand 16)); + + my $hash = sha1_hex ($salt . $word) . ":$salt"; + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $salt, $word) = split (":", $line); + + return unless defined $hash; + return unless defined $salt; + return unless defined $word; + + $word = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word, $salt); + + return unless $new_hash eq "$hash:$salt"; + + return $new_hash; +} + +1; diff --git a/tools/test_modules/m18400.pm b/tools/test_modules/m18400.pm new file mode 100644 index 000000000..0c7ed42c8 --- /dev/null +++ b/tools/test_modules/m18400.pm @@ -0,0 +1,109 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; + +use Crypt::Mode::CBC; +use Crypt::PBKDF2; +use Digest::SHA qw (sha256 sha256_hex); + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift // random_hex_string (2*16); + my $iter = shift // 100000; + my $iv = shift // random_hex_string (2*16); + my $plain = shift // random_hex_string (2*1024); + + my $b_iv = pack ("H*", $iv); + my $b_salt = pack ("H*", $salt); + my $b_plain = pack ("H*", $plain); + + my $kdf = Crypt::PBKDF2->new + ( + hash_class => 'HMACSHA1', + iterations => $iter, + output_len => 32 + ); + + my $pass_hash = sha256 ($word); + my $key = $kdf->PBKDF2 ($b_salt, $pass_hash); + my $cbc = Crypt::Mode::CBC->new ('AES', 0); + my $b_cipher = $cbc->encrypt ($b_plain, $key, $b_iv); + my $cipher = unpack ("H*", $b_cipher); + my $checksum = sha256_hex ($b_plain); + + my $hash = '$odf$'."*1*1*$iter*32*$checksum*16*$iv*16*$salt*0*$cipher"; + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split (":", $line); + + return unless defined $hash; + return unless defined $word; + + $word = pack_if_HEX_notation ($word); + + # tokenize + my @data = split ('\*', $hash); + + next unless scalar @data == 12; + + my $signature = shift @data; + my $cipher_type = shift @data; + my $cs_type = shift @data; + my $iter = shift @data; + my $cs_len = shift @data; + my $cs = shift @data; + my $iv_len = shift @data; + my $iv = shift @data; + my $salt_len = shift @data; + my $salt = shift @data; + my $unused = shift @data; + my $cipher = shift @data; + + # validate + return unless $signature eq '$odf$'; + return unless $cipher_type eq '1'; + return unless $cs_type eq '1'; + return unless $cs_len eq '32'; + return unless $iv_len eq '16'; + return unless $salt_len eq '16'; + return unless $unused eq '0'; + return unless defined $cipher; + + # decrypt + my $b_iv = pack ("H*", $iv); + my $b_salt = pack ("H*", $salt); + my $b_cipher = pack ("H*", $cipher); + + my $kdf = Crypt::PBKDF2->new + ( + hash_class => 'HMACSHA1', + iterations => $iter, + output_len => 32 + ); + + my $pass_hash = sha256 ($word); + my $key = $kdf->PBKDF2 ($b_salt, $pass_hash); + my $cbc = Crypt::Mode::CBC->new ('AES', 0); + my $b_plain = $cbc->decrypt ($b_cipher, $key, $b_iv); + my $plain = unpack ("H*", $b_plain); + + my $new_hash = module_generate_hash ($word, $salt, $iter, $iv, $plain); + + return unless $new_hash eq $hash; + + return $new_hash; +} + +1; diff --git a/tools/test_modules/m18600.pm b/tools/test_modules/m18600.pm new file mode 100644 index 000000000..e18fb2bd5 --- /dev/null +++ b/tools/test_modules/m18600.pm @@ -0,0 +1,135 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; + +use Crypt::GCrypt; +use Crypt::PBKDF2; +use Digest::SHA qw (sha1 sha1_hex); + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift // random_hex_string (2*16); + my $iter = shift // 100000; + my $iv = shift // random_hex_string (2*8); + my $plain = shift // random_hex_string (2*1024); + + my $b_iv = pack ("H*", $iv); + my $b_salt = pack ("H*", $salt); + my $b_plain = pack ("H*", $plain); + + my $kdf = Crypt::PBKDF2->new + ( + hash_class => 'HMACSHA1', + iterations => $iter, + output_len => 16 + ); + + my $pass_hash = sha1 ($word); + my $key = $kdf->PBKDF2 ($b_salt, $pass_hash); + + my $cfb = Crypt::GCrypt->new( + type => 'cipher', + algorithm => 'blowfish', + mode => 'cfb' + ); + + $cfb->start ('encrypting'); + $cfb->setkey ($key); + $cfb->setiv ($b_iv); + + my $b_cipher = $cfb->encrypt ($b_plain); + + $cfb->finish (); + + my $cipher = unpack ("H*", $b_cipher); + my $checksum = sha1_hex ($b_plain); + + my $hash = '$odf$'."*0*0*$iter*16*$checksum*8*$iv*16*$salt*0*$cipher"; + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split (":", $line); + + return unless defined $hash; + return unless defined $word; + + $word = pack_if_HEX_notation ($word); + + # tokenize + my @data = split ('\*', $hash); + + next unless scalar @data == 12; + + my $signature = shift @data; + my $cipher_type = shift @data; + my $cs_type = shift @data; + my $iter = shift @data; + my $cs_len = shift @data; + my $cs = shift @data; + my $iv_len = shift @data; + my $iv = shift @data; + my $salt_len = shift @data; + my $salt = shift @data; + my $unused = shift @data; + my $cipher = shift @data; + + # validate + return unless $signature eq '$odf$'; + return unless $cipher_type eq '0'; + return unless $cs_type eq '0'; + return unless $cs_len eq '16'; + return unless $iv_len eq '8'; + return unless $salt_len eq '16'; + return unless $unused eq '0'; + return unless defined $cipher; + + # decrypt + my $b_iv = pack ("H*", $iv); + my $b_salt = pack ("H*", $salt); + my $b_cipher = pack ("H*", $cipher); + + my $kdf = Crypt::PBKDF2->new + ( + hash_class => 'HMACSHA1', + iterations => $iter, + output_len => 16 + ); + + my $pass_hash = sha1 ($word); + my $key = $kdf->PBKDF2 ($b_salt, $pass_hash); + + my $cfb = Crypt::GCrypt->new( + type => 'cipher', + algorithm => 'blowfish', + mode => 'cfb' + ); + + $cfb->start ('decrypting'); + $cfb->setkey ($key); + $cfb->setiv ($b_iv); + + my $b_plain = $cfb->decrypt ($b_cipher); + + $cfb->finish (); + + my $plain = unpack ("H*", $b_plain); + + my $new_hash = module_generate_hash ($word, $salt, $iter, $iv, $plain); + + return unless $new_hash eq $hash; + + return $new_hash; +} + +1;