Merge remote-tracking branch 'origin/master' into knx-ip-secure
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
##
|
||||
## Author......: See docs/credits.txt
|
||||
## License.....: MIT
|
||||
##
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use MIME::Base64 qw (decode_base64 encode_base64);
|
||||
use Digest::MD5 qw (md5_hex);
|
||||
use Digest::SHA1 qw (sha1);
|
||||
use Digest::HMAC qw (hmac);
|
||||
use Crypt::PBKDF2;
|
||||
|
||||
sub module_constraints { [[0, 256], [16, 16], [-1, -1], [-1, -1], [-1, -1]] }
|
||||
|
||||
my $ITERATIONS = 10000;
|
||||
my $MD5_SALT = ":mongo:";
|
||||
my $HMAC_SALT = "Server Key";
|
||||
|
||||
sub module_generate_hash
|
||||
{
|
||||
my $word = shift;
|
||||
my $salt = shift;
|
||||
my $iter = shift // $ITERATIONS;
|
||||
my $user = shift // random_string (random_number (0, 57));
|
||||
|
||||
my $pbkdf = Crypt::PBKDF2->new
|
||||
(
|
||||
hash_class => 'HMACSHA1',
|
||||
iterations => $iter,
|
||||
output_len => 20
|
||||
);
|
||||
|
||||
my $md5_dgst = md5_hex ($user . $MD5_SALT . $word);
|
||||
|
||||
my $pbkdf2_dgst = $pbkdf->PBKDF2 ($salt, $md5_dgst);
|
||||
|
||||
my $hash_buf = hmac ($HMAC_SALT, $pbkdf2_dgst, \&sha1);
|
||||
|
||||
my $hash = sprintf ('$mongodb-scram$*0*%s*%i*%s*%s', encode_base64 ($user, ""), $iter, encode_base64 ($salt, ""), encode_base64 ($hash_buf, ""));
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
sub module_verify_hash
|
||||
{
|
||||
my $line = shift;
|
||||
|
||||
my $idx = index ($line, ':');
|
||||
|
||||
return unless $idx >= 0;
|
||||
|
||||
my $hash = substr ($line, 0, $idx);
|
||||
my $word = substr ($line, $idx + 1);
|
||||
|
||||
return unless substr ($hash, 0, 17) eq '$mongodb-scram$*0';
|
||||
|
||||
my (undef, undef, $user, $iter, $salt) = split ('\*', $hash);
|
||||
|
||||
return unless defined ($user);
|
||||
return unless defined ($iter);
|
||||
return unless defined ($salt);
|
||||
|
||||
return unless ($user =~ m/^[A-Za-z0-9+\/=]{0,76}$/);
|
||||
|
||||
$user = decode_base64 ($user);
|
||||
|
||||
return unless (length ($user) <= 57);
|
||||
|
||||
return unless ($iter =~ m/^[1-9][0-9]{0,7}$/);
|
||||
|
||||
$iter = int ($iter);
|
||||
|
||||
return unless ($salt =~ m/^[A-Za-z0-9+\/=]{24}$/);
|
||||
|
||||
$salt = decode_base64 ($salt);
|
||||
|
||||
my $word_packed = pack_if_HEX_notation ($word);
|
||||
|
||||
my $new_hash = module_generate_hash ($word_packed, $salt, $iter, $user);
|
||||
|
||||
return ($new_hash, $word);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
##
|
||||
## Author......: See docs/credits.txt
|
||||
## License.....: MIT
|
||||
##
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use MIME::Base64 qw (decode_base64 encode_base64);
|
||||
use Digest::SHA qw (sha256);
|
||||
use Digest::HMAC qw (hmac);
|
||||
use Crypt::PBKDF2;
|
||||
|
||||
sub module_constraints { [[0, 256], [28, 28], [-1, -1], [-1, -1], [-1, -1]] }
|
||||
|
||||
my $ITERATIONS = 15000;
|
||||
my $HMAC_SALT = "Server Key";
|
||||
|
||||
sub module_generate_hash
|
||||
{
|
||||
my $word = shift;
|
||||
my $salt = shift;
|
||||
my $iter = shift // $ITERATIONS;
|
||||
my $user = shift // random_string (random_number (0, 64));
|
||||
|
||||
my $pbkdf = Crypt::PBKDF2->new
|
||||
(
|
||||
hasher => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA2', 256),
|
||||
iterations => $iter,
|
||||
output_len => 32
|
||||
);
|
||||
|
||||
my $pbkdf2_dgst = $pbkdf->PBKDF2 ($salt, $word);
|
||||
|
||||
my $hash_buf = hmac ($HMAC_SALT, $pbkdf2_dgst, \&sha256);
|
||||
|
||||
my $hash = sprintf ('$mongodb-scram$*1*%s*%i*%s*%s', encode_base64 ($user, ""), $iter, encode_base64 ($salt, ""), encode_base64 ($hash_buf, ""));
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
sub module_verify_hash
|
||||
{
|
||||
my $line = shift;
|
||||
|
||||
my $idx = index ($line, ':');
|
||||
|
||||
return unless $idx >= 0;
|
||||
|
||||
my $hash = substr ($line, 0, $idx);
|
||||
my $word = substr ($line, $idx + 1);
|
||||
|
||||
return unless substr ($hash, 0, 17) eq '$mongodb-scram$*1';
|
||||
|
||||
my (undef, undef, $user, $iter, $salt) = split ('\*', $hash);
|
||||
|
||||
return unless defined ($user);
|
||||
return unless defined ($iter);
|
||||
return unless defined ($salt);
|
||||
|
||||
return unless ($user =~ m/^[A-Za-z0-9+\/=]{0,88}$/);
|
||||
|
||||
$user = decode_base64 ($user);
|
||||
|
||||
return unless (length ($user) <= 64);
|
||||
|
||||
return unless ($iter =~ m/^[1-9][0-9]{0,7}$/);
|
||||
|
||||
$iter = int ($iter);
|
||||
|
||||
return unless ($salt =~ m/^[A-Za-z0-9+\/=]{40}$/);
|
||||
|
||||
$salt = decode_base64 ($salt);
|
||||
|
||||
my $word_packed = pack_if_HEX_notation ($word);
|
||||
|
||||
my $new_hash = module_generate_hash ($word_packed, $salt, $iter, $user);
|
||||
|
||||
return ($new_hash, $word);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,277 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
##
|
||||
## Author......: See docs/credits.txt
|
||||
## License.....: MIT
|
||||
##
|
||||
|
||||
# based off m10500 but added the owner password part ($o) to be able to test the edit password
|
||||
# two TODOs still (now only works if no user password is set):
|
||||
# 1. TODO use user password as input for md5 of o_digest if no owner password is set
|
||||
# 2. TODO dynamically add user password including padding to the RC4 input for the computation of the pdf o-value
|
||||
|
||||
# easy test shortcut for debugging
|
||||
# a=$(echo 1 | tools/test.pl passthrough 10500 | tail -n1); echo $a; echo 1 | ./hashcat --potfile-disable --runtime 400 --hwmon-disable -O -D 2 --backend-vector-width 4 -a 0 -m 10500 $a
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Crypt::RC4;
|
||||
use Digest::MD5 qw (md5);
|
||||
|
||||
my $PDF_PADDING =
|
||||
[
|
||||
0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56,
|
||||
0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
|
||||
0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
|
||||
];
|
||||
|
||||
sub module_constraints { [[0, 15], [32, 32], [-1, -1], [-1, -1], [-1, -1]] }
|
||||
|
||||
sub pdf_compute_encryption_key_user
|
||||
{
|
||||
my $word = shift;
|
||||
my $padding = shift;
|
||||
my $id = shift;
|
||||
my $u = shift;
|
||||
my $o = shift;
|
||||
my $P = shift;
|
||||
my $V = shift;
|
||||
my $R = shift;
|
||||
my $enc = shift;
|
||||
|
||||
## start
|
||||
|
||||
my $data;
|
||||
|
||||
$data .= $word;
|
||||
|
||||
$data .= substr ($padding, 0, 32 - length $word);
|
||||
|
||||
$data .= pack ("H*", $o);
|
||||
$data .= pack ("I", $P);
|
||||
$data .= pack ("H*", $id);
|
||||
|
||||
if ($R >= 4)
|
||||
{
|
||||
if (!$enc)
|
||||
{
|
||||
$data .= pack ("I", -1);
|
||||
}
|
||||
}
|
||||
|
||||
my $res = md5 ($data);
|
||||
|
||||
if ($R >= 3)
|
||||
{
|
||||
for (my $i = 0; $i < 50; $i++)
|
||||
{
|
||||
$res = md5 ($res);
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
sub pdf_compute_encryption_key_owner
|
||||
{
|
||||
my $word = shift;
|
||||
my $padding = shift;
|
||||
my $id = shift;
|
||||
my $u = shift;
|
||||
my $o = shift;
|
||||
my $P = shift;
|
||||
my $V = shift;
|
||||
my $R = shift;
|
||||
my $enc = shift;
|
||||
|
||||
# TODO use user password as input for md5 of o_digest if no owner password is set
|
||||
my $data;
|
||||
$data .= $word;
|
||||
$data .= substr ($padding, 0, 32 - length $word);
|
||||
my $o_digest = md5 ($data);
|
||||
|
||||
if ($R >= 3)
|
||||
{
|
||||
for (my $i = 0; $i < 50; $i++)
|
||||
{
|
||||
$o_digest = md5 ($o_digest);
|
||||
}
|
||||
}
|
||||
|
||||
#printf("\$o_digest = %s\n", unpack ("H*", $o_digest));
|
||||
|
||||
|
||||
my $o_key;
|
||||
if ($R == 2)
|
||||
{
|
||||
$o_key = substr($o_digest, 0, 8); # rc4 key is always 5 for revision 2, but for 3 or greather is dependent on the value of the encryption dictionaries length entry
|
||||
}
|
||||
else
|
||||
{
|
||||
$o_key = substr($o_digest, 0, 16); #length is always 128 bits or 16 bytes
|
||||
}
|
||||
#printf("\$o_key = %s\n", unpack ("H*", $o_key));
|
||||
|
||||
return $o_key;
|
||||
}
|
||||
|
||||
sub module_generate_hash
|
||||
{
|
||||
my $word = shift;
|
||||
my $id = shift;
|
||||
my $u = shift;
|
||||
my $o = shift;
|
||||
my $P = shift;
|
||||
my $V = shift;
|
||||
my $R = shift;
|
||||
my $enc = shift;
|
||||
|
||||
if (defined $u == 0)
|
||||
{
|
||||
$u = "0" x 64;
|
||||
}
|
||||
|
||||
my $u_save = $u;
|
||||
|
||||
if (defined $o == 0)
|
||||
{
|
||||
$o = "0" x 64;
|
||||
}
|
||||
|
||||
my $o_save = $u;
|
||||
|
||||
if (defined $R == 0)
|
||||
{
|
||||
$R = random_number (3, 4);
|
||||
}
|
||||
|
||||
if (defined $V == 0)
|
||||
{
|
||||
$V = ($R == 3) ? 2 : 4;
|
||||
}
|
||||
|
||||
if (defined $P == 0)
|
||||
{
|
||||
$P = ($R == 3) ? -4 : -1028;
|
||||
}
|
||||
|
||||
if (defined $enc == 0)
|
||||
{
|
||||
$enc = ($R == 3) ? 1 : random_number (0, 1);
|
||||
}
|
||||
|
||||
my $padding;
|
||||
|
||||
for (my $i = 0; $i < 32; $i++)
|
||||
{
|
||||
$padding .= pack ("C", $PDF_PADDING->[$i]);
|
||||
}
|
||||
|
||||
|
||||
################ USER PASSWORD #################
|
||||
my $res = pdf_compute_encryption_key_user($word, $padding, $id, $u, $o, $P, $V, $R, $enc);
|
||||
|
||||
my $digest = md5 ($padding . pack ("H*", $id));
|
||||
|
||||
my $m = Crypt::RC4->new ($res);
|
||||
$u = $m->RC4 ($digest);
|
||||
|
||||
my @ress = split "", $res;
|
||||
|
||||
#do xor of rc4 19 times
|
||||
for (my $x = 1; $x <= 19; $x++)
|
||||
{
|
||||
my @xor;
|
||||
|
||||
for (my $i = 0; $i < 16; $i++)
|
||||
{
|
||||
$xor[$i] = chr (ord ($ress[$i]) ^ $x);
|
||||
}
|
||||
|
||||
my $s = join ("", @xor);
|
||||
|
||||
my $m2 = Crypt::RC4->new ($s);
|
||||
|
||||
$u = $m2->RC4 ($u);
|
||||
}
|
||||
|
||||
|
||||
################ OWNER PASSWORD #################
|
||||
my $o_key = pdf_compute_encryption_key_owner($word, $padding, $id, $u, $o, $P, $V, $R, $enc);
|
||||
my $n = Crypt::RC4->new ($o_key);
|
||||
$o = $n->RC4(substr ($padding, 0, 32 - length "")); # TODO dynamically add user password including padding to the RC4 input for the computation of the pdf o-value
|
||||
|
||||
#printf("padding_empty_str = %s\n", unpack ("H*", substr ($padding, 0, 32 - length "")));
|
||||
|
||||
my @ress2 = split "", $o_key;
|
||||
|
||||
if ($R >= 3)
|
||||
{
|
||||
#do xor of rc4 19 times
|
||||
for (my $x = 1; $x <= 19; $x++)
|
||||
{
|
||||
my @xor;
|
||||
|
||||
for (my $i = 0; $i < 16; $i++)
|
||||
{
|
||||
$xor[$i] = chr (ord ($ress2[$i]) ^ $x);
|
||||
}
|
||||
|
||||
my $s = join ("", @xor);
|
||||
|
||||
my $n2 = Crypt::RC4->new ($s);
|
||||
|
||||
$o = $n2->RC4 ($o);
|
||||
}
|
||||
}
|
||||
|
||||
#printf("\$u = %s\n", unpack ("H*", $u));
|
||||
|
||||
$u .= substr (pack ("H*", $u_save), 16, 16);
|
||||
|
||||
#printf("\$o = %s\n", unpack ("H*", $o));
|
||||
#printf("\$u = %s\n", unpack ("H*", $u));
|
||||
|
||||
my $hash = sprintf ('$pdf$%d*%d*128*%d*%d*16*%s*32*%s*32*%s', $V, $R, $P, $enc, $id, unpack ("H*", $u), unpack ("H*", $o));
|
||||
|
||||
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 == 11;
|
||||
|
||||
my $V = shift @data; $V = substr ($V, 5, 1);
|
||||
my $R = shift @data;
|
||||
return unless (shift @data eq '128'); # length is always 128 here
|
||||
my $P = shift @data;
|
||||
my $enc = shift @data;
|
||||
return unless (shift @data eq '16');
|
||||
my $id = shift @data;
|
||||
return unless (shift @data eq '32');
|
||||
my $u = shift @data;
|
||||
return unless (shift @data eq '32');
|
||||
my $o = shift @data;
|
||||
|
||||
return unless defined $id;
|
||||
return unless defined $word;
|
||||
|
||||
$word = pack_if_HEX_notation ($word);
|
||||
|
||||
my $new_hash = module_generate_hash ($word, $id, $u, $o, $P, $V, $R, $enc);
|
||||
|
||||
return ($new_hash, $word);
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user