diff --git a/tools/test_modules/m10900.pm b/tools/test_modules/m10900.pm
new file mode 100644
index 000000000..29e04cefb
--- /dev/null
+++ b/tools/test_modules/m10900.pm
@@ -0,0 +1,70 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Crypt::PBKDF2;
+use MIME::Base64 qw (encode_base64 decode_base64);
+
+sub module_constraints { [[0, 255], [1, 15], [0, 55], [1, 15], [-1, -1]] }
+
+sub module_generate_hash
+{
+  my $word       = shift;
+  my $salt       = shift;
+  my $iterations = shift // 1000;
+  my $out_len    = shift // 24;
+
+  my $pbkdf2 = Crypt::PBKDF2->new
+  (
+    hasher     => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
+    iterations => $iterations,
+    output_len => $out_len
+  );
+
+  my $digest = encode_base64 ($pbkdf2->PBKDF2 ($salt, $word), "");
+
+  my $base64_salt = encode_base64 ($salt, "");
+
+  my $hash = sprintf ("sha256:%i:%s:%s", $iterations, $base64_salt, $digest);
+
+  return $hash;
+}
+
+sub module_verify_hash
+{
+  my $line = shift;
+
+  my ($digest, $word) = split (/:([^:]+)$/, $line);
+
+  return unless defined $digest;
+  return unless defined $word;
+
+  my @data = split (':', $digest);
+
+  return unless scalar(@data) == 4;
+
+  my $signature = shift @data;
+
+  return unless ($signature eq 'sha256');
+
+  my $iterations = int (shift @data);
+
+  my $salt = decode_base64 (shift @data);
+  my $hash = decode_base64 (shift @data);
+
+  my $out_len = length ($hash);
+
+  my $word_packed = pack_if_HEX_notation ($word);
+
+  my $new_hash = module_generate_hash ($word_packed, $salt, $iterations, $out_len);
+
+  return ($new_hash, $word);
+}
+
+1;
diff --git a/tools/test_modules/m11000.pm b/tools/test_modules/m11000.pm
new file mode 100644
index 000000000..ef1c09b38
--- /dev/null
+++ b/tools/test_modules/m11000.pm
@@ -0,0 +1,44 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Digest::MD5 qw (md5_hex);
+
+sub module_constraints { [[0, 255], [56, 56], [0, 55], [56, 56], [-1, -1]] }
+
+sub module_generate_hash
+{
+  my $word = shift;
+  my $salt = shift;
+
+  my $digest = md5_hex ($salt . $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/m11100.pm b/tools/test_modules/m11100.pm
new file mode 100644
index 000000000..6d29f05c7
--- /dev/null
+++ b/tools/test_modules/m11100.pm
@@ -0,0 +1,50 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Digest::MD5 qw (md5_hex);
+
+sub module_constraints { [[0, 255], [8, 8], [0, 55], [8, 8], [-1, -1]] }
+
+sub module_generate_hash
+{
+  my $word = shift;
+  my $salt = shift;
+  my $user = shift // "postgres";
+
+  my $digest = md5_hex (md5_hex ($word . $user) . pack ("H*", $salt));
+
+  my $hash = sprintf ("\$postgres\$%s*%s*%s", $user, $salt, $digest);
+
+  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 (undef, $signature, $digest) = split ('\$', $hash_in);
+
+  return unless ($signature eq 'postgres');
+
+  my ($user, $salt, $hash) = split ('\*', $digest);
+
+  my $word_packed = pack_if_HEX_notation ($word);
+
+  my $new_hash = module_generate_hash ($word_packed, $salt, $user);
+
+  return ($new_hash, $word);
+}
+
+1;
diff --git a/tools/test_modules/m11200.pm b/tools/test_modules/m11200.pm
new file mode 100644
index 000000000..ad1813c2a
--- /dev/null
+++ b/tools/test_modules/m11200.pm
@@ -0,0 +1,68 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Digest::MD5 qw (md5_hex);
+use Digest::SHA qw (sha1);
+
+sub module_constraints { [[0, 255], [40, 40], [0, 55], [40, 40], [-1, -1]] }
+
+sub module_generate_hash
+{
+  my $word = shift;
+  my $salt = shift;
+
+  my $sha1_pass   = sha1 ($word);
+  my $double_sha1 = sha1 ($sha1_pass);
+
+  my $xor_part1 = $sha1_pass;
+  my $xor_part2 = sha1 (pack ("H*", $salt) . $double_sha1);
+
+  my $digest = "";
+
+  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;
+
+    $digest .= unpack ("H*", $xor_result);
+  }
+
+  my $hash = sprintf ("\$mysqlna\$%s*%s", $salt, $digest);
+
+  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 (undef, $signature, $digest) = split ('\$', $hash_in);
+
+  my ($salt, $hash) = split ('\*', $digest);
+
+  return unless ($signature eq 'mysqlna');
+  return unless defined $salt;
+  return unless defined $hash;
+
+  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/m11300.pm b/tools/test_modules/m11300.pm
new file mode 100644
index 000000000..e4e8d5724
--- /dev/null
+++ b/tools/test_modules/m11300.pm
@@ -0,0 +1,66 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Digest::SHA qw (sha512);
+use Crypt::CBC;
+
+sub module_constraints { [[0, 255], [16, 16], [0, 55], [16, 16], [-1, -1]] }
+
+sub module_generate_hash
+{
+  my $word       = shift;
+  my $salt       = shift;
+  my $ckey       = shift // random_hex_string (96);
+  my $public_key = shift // random_hex_string (66);
+  my $salt_iter  = shift // random_number (150000, 250000);
+
+  my $digest = sha512 ($word . pack ("H*", $salt));
+
+  for (my $i = 1; $i < $salt_iter; $i++)
+  {
+    $digest = sha512 ($digest);
+  }
+
+  my $data = random_hex_string (32);
+
+  my $aes = Crypt::CBC->new ({
+    key         => substr ($digest,  0, 32),
+    cipher      => "Crypt::Rijndael",
+    iv          => substr ($digest, 32, 16),
+    literal_key => 1,
+    header      => "none",
+    keysize     => 32,
+    padding     => "standard",
+  });
+
+  my $cry_master = (unpack ("H*", $aes->encrypt ($data)));
+
+  my $hash = sprintf ('$bitcoin$%d$%s$%d$%s$%d$%d$%s$%d$%s',
+    length ($cry_master),
+    $cry_master,
+    length ($salt),
+    $salt,
+    $salt_iter,
+    length ($ckey),
+    $ckey,
+    length ($public_key),
+    $public_key);
+
+  return $hash;
+}
+
+sub module_verify_hash
+{
+  print "ERROR: verify currently not supported for Bitcoin/Litecoin wallet.dat because of unknown crypt data\n";
+
+  exit (1);
+}
+
+1;
diff --git a/tools/test_modules/m11400.pm b/tools/test_modules/m11400.pm
new file mode 100644
index 000000000..a3dd73b98
--- /dev/null
+++ b/tools/test_modules/m11400.pm
@@ -0,0 +1,164 @@
+#!/usr/bin/env perl
+
+##
+## Author......: See docs/credits.txt
+## License.....: MIT
+##
+
+use strict;
+use warnings;
+
+use Digest::MD5 qw (md5_hex);
+
+sub module_constraints { [[0, 24], [1, 15], [0, 24], [1, 15], [-1, -1]] }
+
+sub module_generate_hash
+{
+  my $word         = shift;
+  my $nonce        = shift;
+  my $user         = shift // random_string (random_number (1, 12 + 1));
+  my $realm        = shift;
+  my $nonce_count  = shift;
+  my $nonce_client = shift;
+  my $qop          = shift;
+  my $method       = shift // random_string (random_number (1, 24 + 1));
+  my $URI_prefix   = shift // random_string (random_number (1, 10 + 1));
+  my $URI_resource = shift // random_string (random_number (1, 32 + 1));
+  my $URI_suffix   = shift // random_string (random_number (1, 32 + 1));
+  my $directive    = shift // "MD5";
+
+  # not needed information
+  my $URI_server = shift // random_string (random_number (1, 32 + 1));
+  my $URI_client = $URI_resource;
+
+  return unless ($directive eq "MD5"); # only MD5 directive currently supported
+
+  unless (defined $realm)
+  {
+    # special limit: (user_len + 1 + realm_len + 1 + word_len) < 56
+    my $realm_max_len = 55 - length ($user) - 1 - length ($word) - 1;
+
+    if ($realm_max_len < 1) # should never happen
+    {
+      $realm_max_len = 1;
+    }
+
+    $realm_max_len = min (20, $realm_max_len);
+
+    $realm = random_string (random_number (1, $realm_max_len + 1));
+  }
+
+  unless ((defined $nonce_count) && (defined $nonce_client) && (defined $qop))
+  {
+    if (random_number (0, 1 + 1) == 1)
+    {
+      $qop = "auth";
+
+      $nonce_count  = random_string (random_number (1, 10 + 1));
+      $nonce_client = random_string (random_number (1, 12 + 1));
+    }
+    else
+    {
+      $qop = "";
+
+      $nonce_count  = "";
+      $nonce_client = "";
+    }
+  }
+
+  # start
+
+  my $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);
+
+  my $tmp;
+
+  if (($qop eq "auth") || ($qop eq "auth-int"))
+  {
+    $tmp = $nonce . ":" . $nonce_count . ":" . $nonce_client . ":" . $qop;
+  }
+  else
+  {
+    $tmp = $nonce;
+  }
+
+  my $digest = md5_hex ($HA1 . ":" . $tmp . ":" . $HA2);
+
+  my $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, $digest);
+
+  return $hash;
+}
+
+sub module_verify_hash
+{
+
+  my $line = shift;
+
+  my ($digest, $word) = split (/:/, $line);
+
+  return unless defined $digest;
+  return unless defined $word;
+
+  my @data = split ('\*', $digest);
+
+  return unless scalar @data == 15;
+
+  my $signature    = shift @data;
+  my $URI_server   = shift @data;
+  my $URI_client   = shift @data;
+  my $user         = shift @data;
+  my $realm        = shift @data;
+  my $method       = shift @data;
+  my $URI_prefix   = shift @data;
+  my $URI_resource = shift @data;
+  my $URI_suffix   = shift @data;
+  my $nonce        = shift @data;
+  my $nonce_client = shift @data;
+  my $nonce_count  = shift @data;
+  my $qop          = shift @data;
+  my $directive    = shift @data;
+  my $hash         = shift @data;
+
+  return unless ($signature eq '$sip$');
+
+  my $word_packed = pack_if_HEX_notation ($word);
+
+  my $new_hash = module_generate_hash (
+    $word_packed,
+    $nonce,
+    $user,
+    $realm,
+    $nonce_count,
+    $nonce_client,
+    $qop,
+    $method,
+    $URI_prefix,
+    $URI_resource,
+    $URI_suffix,
+    $directive,
+    $URI_server);
+
+  return ($new_hash, $word);
+}
+
+sub min
+{
+  $_[$_[0] > $_[1]];
+}
+
+1;