From 444d11a74b54efdb3c7ad75ec8860decbafb6662 Mon Sep 17 00:00:00 2001 From: "R. Yushaev" <44146334+Naufragous@users.noreply.github.com> Date: Thu, 20 Dec 2018 19:18:06 +0100 Subject: [PATCH] Add test modules Add tests for modes 0, 100, 110, 120, 18400, 18600. Update readme. --- tools/test_modules/README.md | 6 ++ tools/test_modules/m0.pm | 39 ++++++++++ tools/test_modules/m100.pm | 39 ++++++++++ tools/test_modules/m110.pm | 41 +++++++++++ tools/test_modules/m120.pm | 41 +++++++++++ tools/test_modules/m18400.pm | 109 ++++++++++++++++++++++++++++ tools/test_modules/m18600.pm | 135 +++++++++++++++++++++++++++++++++++ 7 files changed, 410 insertions(+) create mode 100644 tools/test_modules/m0.pm create mode 100644 tools/test_modules/m100.pm create mode 100644 tools/test_modules/m110.pm create mode 100644 tools/test_modules/m120.pm create mode 100644 tools/test_modules/m18400.pm create mode 100644 tools/test_modules/m18600.pm diff --git a/tools/test_modules/README.md b/tools/test_modules/README.md index 3732b42d6..35a951d77 100644 --- a/tools/test_modules/README.md +++ b/tools/test_modules/README.md @@ -7,3 +7,9 @@ During `single` and `passthrough` tests the `module_generate_hash` function must 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;