diff --git a/tools/test_modules/m13800.pm b/tools/test_modules/m13800.pm new file mode 100644 index 000000000..b23ab5301 --- /dev/null +++ b/tools/test_modules/m13800.pm @@ -0,0 +1,49 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Digest::SHA qw (sha256_hex); +use Encode; + +sub module_constraints { [[0, 255], [256, 256], [0, 27], [256, 256], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + + my $word_utf16le = encode ("UTF-16LE", $word); + + my $salt_bin = pack ("H*", $salt); + + my $digest = sha256_hex ($word_utf16le . $salt_bin); + + my $hash = sprintf ("%s:%s", $digest, $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; + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt); + + return ($new_hash, $word); +} + +1; diff --git a/tools/test_modules/m13900.pm b/tools/test_modules/m13900.pm new file mode 100644 index 000000000..5bca190c5 --- /dev/null +++ b/tools/test_modules/m13900.pm @@ -0,0 +1,45 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Digest::SHA qw (sha1_hex); +use Encode; + +sub module_constraints { [[0, 255], [9, 9], [0, 46], [9, 9], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + + my $digest = sha1_hex ($salt . sha1_hex ($salt . sha1_hex ($word))); + + my $hash = sprintf ("%s:%s", $digest, $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; + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt); + + return ($new_hash, $word); +} + +1; diff --git a/tools/test_modules/m14400.pm b/tools/test_modules/m14400.pm new file mode 100644 index 000000000..095d62e7f --- /dev/null +++ b/tools/test_modules/m14400.pm @@ -0,0 +1,52 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Digest::SHA qw (sha1_hex); + +sub module_constraints { [[0, 235], [20, 20], [0, 35], [20, 20], [0, 55]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + + my $begin = "--" . $salt . "--"; + my $end = "--" . $word . "----"; + + my $digest = sha1_hex ($begin . $end); + + for (my $round = 1; $round < 10; $round++) + { + $digest = sha1_hex ($begin . $digest . $end); + } + + my $hash = sprintf ("%s:%s", $digest, $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; + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt); + + return ($new_hash, $word); +} + +1; diff --git a/tools/test_modules/m14700.pm b/tools/test_modules/m14700.pm new file mode 100644 index 000000000..49293ee09 --- /dev/null +++ b/tools/test_modules/m14700.pm @@ -0,0 +1,195 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Crypt::PBKDF2; +use Crypt::Mode::ECB; + +sub module_constraints { [[0, 255], [40, 40], [0, 55], [40, 40], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + my $iterations = shift // 10000; + my $wpky_param = shift; + + my $pbkdf2 = Crypt::PBKDF2->new + ( + hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1'), + iterations => $iterations, + output_len => 32 + ); + + $salt = pack ("H*", $salt); + + my $key = $pbkdf2->PBKDF2 ($salt, $word); + + my $ITUNES_BACKUP_KEY = 12008468691120727718; + + my $WPKY = "\x00" x 40; + + if (defined $wpky_param) + { + my ($A, $R) = itunes_aes_unwrap ($key, $wpky_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] = random_number (0, $max_number); + } + + $WPKY = itunes_aes_wrap ($key, $ITUNES_BACKUP_KEY, \@R); + } + + my $hash = sprintf ("\$itunes_backup\$*9*%s*%i*%s**", unpack ("H*", $WPKY), $iterations, unpack ("H*", $salt)); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split (':', $line); + + return unless defined $hash; + return unless defined $word; + + my ($signature, $version, $wpky_encoded, $iterations, $salt, undef, undef) = split ('\*', $hash); + + return unless ($signature eq '$itunes_backup$'); + return unless ($version eq '9'); + return unless length ($wpky_encoded) == 80; + return unless defined $iterations; + return unless defined $salt; + + my $wpky = pack ("H*", $wpky_encoded); + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt, $iterations, $wpky); + + return ($new_hash, $word); +} + +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); +} + +1; diff --git a/tools/test_modules/m14800.pm b/tools/test_modules/m14800.pm new file mode 100644 index 000000000..51ac789ef --- /dev/null +++ b/tools/test_modules/m14800.pm @@ -0,0 +1,213 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Crypt::PBKDF2; +use Crypt::Mode::ECB; + +sub module_constraints { [[0, 255], [40, 40], [-1, -1], [-1, -1], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + my $iterations = shift // 10000; + my $wpky_param = shift; + my $DPIC = shift // 1000; + my $DPSL = shift // random_bytes (20); + + my $pbkdf2 = Crypt::PBKDF2->new + ( + hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1'), + iterations => $iterations, + output_len => 32 + ); + + $salt = pack ("H*", $salt); + + my $ITUNES_BACKUP_KEY = 12008468691120727718; + + 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); + + my $key = $pbkdf2->PBKDF2 ($salt, $key_dpsl); + + if (defined $wpky_param) + { + my ($A, $R) = itunes_aes_unwrap ($key, $wpky_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] = random_number (0, $max_number); + } + + $WPKY = itunes_aes_wrap ($key, $ITUNES_BACKUP_KEY, \@R); + } + + my $hash = sprintf ("\$itunes_backup\$*10*%s*%i*%s*%i*%s", unpack ("H*", $WPKY), $iterations, unpack ("H*", $salt), $DPIC, unpack ("H*", $DPSL)); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split (':', $line); + + return unless defined $hash; + return unless defined $word; + + my ($signature, $version, $wpky_encoded, $iterations, $salt, $dpic, $dpsl_encoded) = split ('\*', $hash); + + return unless ($signature eq '$itunes_backup$'); + return unless ($version eq '10'); + return unless length ($wpky_encoded) == 80; + return unless defined $iterations; + return unless defined $salt; + return unless defined $dpic; + return unless defined $dpsl_encoded; + + my $wpky = pack ("H*", $wpky_encoded); + my $dpsl = pack ("H*", $dpsl_encoded); + + $iterations = int ($iterations); + + $dpic = int ($dpic); + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt, $iterations, $wpky, $dpic, $dpsl); + + return ($new_hash, $word); +} + +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); +} + +1; diff --git a/tools/test_modules/m14900.pm b/tools/test_modules/m14900.pm new file mode 100644 index 000000000..c639d073a --- /dev/null +++ b/tools/test_modules/m14900.pm @@ -0,0 +1,48 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Crypt::Skip32; + +sub module_constraints { [[-1, -1], [-1, -1], [10, 10], [8, 8], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + + my $salt_bin = pack ("H*", $salt); + + my $skip32 = Crypt::Skip32->new ($word); + + my $digest = $skip32->encrypt ($salt_bin); + + my $hash = sprintf ("%08x:%s", unpack ("N*", $digest), $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; + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt); + + return ($new_hash, $word); +} + +1; diff --git a/tools/test_modules/m15000.pm b/tools/test_modules/m15000.pm new file mode 100644 index 000000000..1109bbbf9 --- /dev/null +++ b/tools/test_modules/m15000.pm @@ -0,0 +1,44 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Digest::SHA qw (sha512_hex); + +sub module_constraints { [[0, 255], [64, 64], [0, 55], [64, 64], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + + my $digest = sha512_hex ($word . $salt); + + my $hash = sprintf ("%s:%s", $digest, $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; + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt); + + return ($new_hash, $word); +} + +1; diff --git a/tools/test_modules/m15100.pm b/tools/test_modules/m15100.pm new file mode 100644 index 000000000..6642776dc --- /dev/null +++ b/tools/test_modules/m15100.pm @@ -0,0 +1,105 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Digest::SHA qw (sha1); +use Digest::HMAC qw (hmac); + +sub module_constraints { [[0, 255], [8, 8], [0, 55], [8, 8], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + my $iterations = shift // 20000; + my $additional_param = shift; + + my $pbkdf1_salt = sprintf ('%s$sha1$%u', $salt, $iterations); + + my $tmp = hmac ($pbkdf1_salt, $word, \&sha1, 64); + + for (my $r = 1; $r < $iterations; $r++) + { + $tmp = hmac ($tmp, $word, \&sha1, 64); + } + + my $digest = ""; + + $digest .= to64 ((int (ord (substr ($tmp, 0, 1))) << 16) | (int (ord (substr ($tmp, 1, 1))) << 8) | (int (ord (substr ($tmp, 2, 1)))), 4); + $digest .= to64 ((int (ord (substr ($tmp, 3, 1))) << 16) | (int (ord (substr ($tmp, 4, 1))) << 8) | (int (ord (substr ($tmp, 5, 1)))), 4); + $digest .= to64 ((int (ord (substr ($tmp, 6, 1))) << 16) | (int (ord (substr ($tmp, 7, 1))) << 8) | (int (ord (substr ($tmp, 8, 1)))), 4); + $digest .= to64 ((int (ord (substr ($tmp, 9, 1))) << 16) | (int (ord (substr ($tmp, 10, 1))) << 8) | (int (ord (substr ($tmp, 11, 1)))), 4); + $digest .= to64 ((int (ord (substr ($tmp, 12, 1))) << 16) | (int (ord (substr ($tmp, 13, 1))) << 8) | (int (ord (substr ($tmp, 14, 1)))), 4); + $digest .= to64 ((int (ord (substr ($tmp, 15, 1))) << 16) | (int (ord (substr ($tmp, 16, 1))) << 8) | (int (ord (substr ($tmp, 17, 1)))), 4); + $digest .= 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) + { + $digest = substr ($digest, 0, 24) . substr ($additional_param, 24, 4); + } + + my $hash = sprintf ("\$sha1\$%d\$%s\$%s", $iterations, $salt, $digest); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split (':', $line); + + return unless defined $hash; + return unless defined $word; + + my @data = split ('\$', $hash); + + return unless scalar @data == 5; + + shift @data; + + my $signature = shift @data; + + return unless ($signature eq 'sha1'); + + my $iterations = shift @data; + my $salt = shift @data; + my $additional_param = shift @data; + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt, $iterations, $additional_param); + + return ($new_hash, $word); +} + +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 +} + +1; diff --git a/tools/test_modules/m15200.pm b/tools/test_modules/m15200.pm new file mode 100644 index 000000000..37aa27fab --- /dev/null +++ b/tools/test_modules/m15200.pm @@ -0,0 +1,84 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Crypt::PBKDF2; +use Crypt::CBC; + +sub module_constraints { [[0, 255], [32, 32], [-1, -1], [-1, -1], [-1, -1]] } + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + my $iterations = shift // 5000; + my $encrypted = shift; + + my $salt_bin = pack ("H*", $salt); + + 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_bin, $word); + + my $cipher = Crypt::CBC->new ({ + key => $key, + cipher => "Crypt::Rijndael", + iv => $salt_bin, + literal_key => 1, + header => "none", + keysize => 32 + }); + + 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}|; + + unless (defined $encrypted) + { + $encrypted = unpack ("H*", $cipher->encrypt ($data)); + } + + my $hash = sprintf ("\$blockchain\$v2\$%d\$%s\$%s", $iterations, length ($salt . $encrypted) / 2, $salt . $encrypted); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash, $word) = split (':', $line); + + return unless defined $hash; + return unless defined $word; + + my (undef, $signature, $version, $iterations, $data_len, $data) = split '\$', $hash; + + return unless ($signature eq "blockchain"); + return unless ($version eq "v2"); + return unless (($data_len * 2) == length $data); + + my $salt = substr ($data, 0, 32); + my $encrypted = substr ($data, 32); + + my $word_packed = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word_packed, $salt, $iterations, $encrypted); + + return ($new_hash, $word); +} + +1;