Add unit tests for multiple modules

13800, 13900, 14400, 14700, 14800, 14900, 15000, 15100 & 15200
pull/1922/head
mhasbini 5 years ago
parent eb4f5d82d1
commit 825c977ca4

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;

@ -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;
Loading…
Cancel
Save