diff --git a/tools/test_modules/m13200.pm b/tools/test_modules/m13200.pm new file mode 100644 index 000000000..c659fed05 --- /dev/null +++ b/tools/test_modules/m13200.pm @@ -0,0 +1,170 @@ +#!/usr/bin/env perl + +## +## Author......: See docs/credits.txt +## License.....: MIT +## + +use strict; +use warnings; + +use Crypt::Mode::ECB; +use Digest::SHA qw (sha1); + +sub module_constraints { [[0, 255], [-1, -1], [-1, -1], [-1, -1], [-1, -1]] } + +sub get_random_axcrypt_salt +{ + my $mysalt = random_bytes (16); + + $mysalt = unpack ("H*", $mysalt); + + my $iteration = random_number (6, 99999); + + my $salt_buf = $iteration . '*' . $mysalt; + + return $salt_buf; +} + +sub module_generate_hash +{ + my $word = shift; + my $salt = shift; + my $param = shift; + + if (length $salt == 0) + { + $salt = get_random_axcrypt_salt (); + } + + my @salt_arr = split ('\*', $salt); + + my $iteration = $salt_arr[0]; + + my $mysalt = $salt_arr[1]; + + $mysalt = pack ("H*", $mysalt); + + my $iv = "a6a6a6a6a6a6a6a6"; + + my $KEK = sha1 ($word); + + $KEK = substr ($KEK ^ $mysalt, 0, 16); + + my $aes = Crypt::Mode::ECB->new ('AES'); + + my $B; + + my $A; + + my @R = (); + + if (defined $param) + { + $param = pack ("H*", $param); + + $A = substr ($param, 0, 8); + $B = 0x00 x 8; + + $R[1] = substr ($param, 8, 8); + $R[2] = substr ($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 = random_hex_string (32); + + @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); + + my $hash = sprintf ('$axcrypt$*1*%s*%s*%s', $iteration, $mysalt, $wrapped_key); + + return $hash; +} + +sub module_verify_hash +{ + my $line = shift; + + my ($hash_in, $word) = split ":", $line; + + return unless defined $hash_in; + return unless defined $word; + + my @data = split ('\*', $hash_in); + + return unless scalar @data == 5; + + my $signature = shift @data; + my $version = shift @data; + my $iteration = shift @data; + my $mysalt = shift @data; + my $digest = shift @data; + + return unless ($signature eq '$axcrypt$'); + return unless (length ($mysalt) == 32); + return unless (length ($digest) == 48); + + my $salt = $iteration . '*' . $mysalt; + my $param = $digest; + + return unless defined $salt; + return unless defined $param; + + $word = pack_if_HEX_notation ($word); + + my $new_hash = module_generate_hash ($word, $salt, $param); + + return ($new_hash, $word); +} + +1;