#!/usr/bin/env perl ## ## Author......: See docs/credits.txt ## License.....: MIT ## use strict; use warnings; use Encode; use Crypt::RC4; use Digest::HMAC_MD5 qw (hmac_md5); use Digest::MD4 qw (md4); use POSIX qw (strftime); sub get_random_kerberos5_salt { my $custom_salt = shift; my $clear_data = random_bytes (14) . strftime ("%Y%m%d%H%M%S", localtime) . random_bytes (8); my $user = "user"; my $realm = "realm"; my $salt = "salt"; my $salt_buf = $user . "\$" . $realm . "\$" . $salt . "\$" . unpack ("H*", $custom_salt) . "\$" . unpack ("H*", $clear_data) . "\$"; return $salt_buf; } sub module_constraints { [[0, 256], [16, 16], [0, 27], [16, 16], [-1, -1]] } sub module_generate_hash { my $word_buf = shift; my $salt_buf = shift; if ($salt_buf !~ /\$/) { $salt_buf = get_random_kerberos5_salt ($salt_buf); } my @salt_arr = split ("\\\$", $salt_buf); my $user = $salt_arr[0]; my $realm = $salt_arr[1]; my $salt = $salt_arr[2]; my $hmac_salt = $salt_arr[3]; my $hmac_salt_bin = pack ("H*", $hmac_salt); my $clear_data = $salt_arr[4]; my $k = md4 (encode ("UTF-16LE", $word_buf)); my $k1 = hmac_md5 ("\x01\x00\x00\x00", $k); my $k3 = hmac_md5 ($hmac_salt_bin, $k1); my $hash_buf; if (length ($clear_data) > 1) { my $clear_data_bin = pack ("H*", $clear_data); $hash_buf = RC4 ($k3, $clear_data_bin); } else { my $hash = $salt_arr[5]; my $hash_bin = pack ("H*", $hash); my $clear_data = RC4 ($k3, $hash_bin); my $timestamp = substr ($clear_data, 14, 14); my $is_numeric = 1; if ($timestamp !~ /^[[:digit:]]{14}$/) { $is_numeric = 0; } if (! $is_numeric) { $hash_buf = "\x00" x 36; if ($hash_buf eq $hash_bin) { $hash_buf = "\x01" x 36; } } else { $hash_buf = $hash_bin; } } my $tmp_hash = sprintf ("\$krb5pa\$23\$%s\$%s\$%s\$%s%s", $user, $realm, $salt, unpack ("H*", $hash_buf), $hmac_salt); return $tmp_hash; } sub module_verify_hash { my $line = shift; my $index1 = index ($line, "\$", 11); return if $index1 < 1; my $index2 = index ($line, "\$", $index1 + 1); return if $index2 < 1; my $index3 = index ($line, "\$", $index2 + 1); return if $index3 < 1; $index2 = index ($line, ":", $index3 + 1); return if $index2 < 1; my $hash_in = substr ($line, 0, $index2); my $word = substr ($line, $index2 + 1); my $salt; $salt = substr ($hash_in, 11, $index3 - 10); $salt .= substr ($hash_in, $index2 - 32) . "\$\$"; $salt .= substr ($hash_in, $index3 + 1, $index2 - $index3 - 32 - 1); my $word_packed = pack_if_HEX_notation ($word); my $new_hash = module_generate_hash ($word_packed, $salt); return ($new_hash, $word); } 1;