From 012c5b16cd1c98c9d8211186f14c230d40470855 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 13 Jul 2021 00:22:06 +0200 Subject: [PATCH] m25400.pm take the user-password into account --- tools/test_modules/m25400.pm | 96 +++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/tools/test_modules/m25400.pm b/tools/test_modules/m25400.pm index 0f0d15e85..7b4b03363 100644 --- a/tools/test_modules/m25400.pm +++ b/tools/test_modules/m25400.pm @@ -86,7 +86,6 @@ sub pdf_compute_encryption_key_owner 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); @@ -110,7 +109,7 @@ sub pdf_compute_encryption_key_owner } else { - $o_key = substr($o_digest, 0, 16); #length is always 128 bits or 16 bytes + $o_key = substr($o_digest, 0, 16); #length is always 128 bits or 16 bytes } #printf("\$o_key = %s\n", unpack ("H*", $o_key)); @@ -127,6 +126,7 @@ sub module_generate_hash my $V = shift; my $R = shift; my $enc = shift; + my $u_pass = shift; if (defined $u == 0) { @@ -173,45 +173,56 @@ sub module_generate_hash ################ USER PASSWORD ################# # do not change $u if it exists, keep this the same, as we don't know the user password, # we cannot calculate this part of the hash again - if("".$u eq "0000000000000000000000000000000000000000000000000000000000000000") + my $res; + if("".$u_pass eq "") { - 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); - } - $u .= substr (pack ("H*", $u_save), 16, 16); + $res = pdf_compute_encryption_key_user($word, $padding, $id, $u, $o, $P, $V, $R, $enc); } else { - $u = pack("H*", $u) + #$u = pack("H*", $u) + #now that we know the user-password we can generate it + $res = pdf_compute_encryption_key_user($u_pass, $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); + } + $u .= substr (pack ("H*", $u_save), 16, 16); + ################ 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 - + if("".$u_pass eq "") + { + $o = $n->RC4(substr ($padding, 0, 32 - length "")); + } + else + { + #dynamically add user password including padding to the RC4 input for the computation of the pdf o-value + $o = $n->RC4($u_pass.substr ($padding, 0, 32 - length $u_pass)); + } + #printf("padding_empty_str = %s\n", unpack ("H*", substr ($padding, 0, 32 - length ""))); my @ress2 = split "", $o_key; @@ -240,7 +251,15 @@ sub module_generate_hash #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)); + my $hash; + if("".$u_pass eq "") + { + $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)); + } + else + { + $hash = sprintf ('$pdf$%d*%d*128*%d*%d*16*%s*32*%s*32*%s*%s', $V, $R, $P, $enc, $id, unpack ("H*", $u), unpack ("H*", $o), $u_pass); + } #print("hash\n".$hash."\n"); return $hash; } @@ -256,7 +275,8 @@ sub module_verify_hash my @data = split /\*/, $hash_in; - return unless scalar @data == 11; + my $i_data = scalar @data; + return unless ($i_data == 11) || ($i_data == 12); #or 12 if user-password is included my $V = shift @data; $V = substr ($V, 5, 1); my $R = shift @data; @@ -270,12 +290,18 @@ sub module_verify_hash return unless (shift @data eq '32'); my $o = shift @data; + my $u_pass = ""; + if($i_data == 12) { + $u_pass = shift @data; + #printf("u_pass = %s\n", $u_pass); + } + 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); + my $new_hash = module_generate_hash ($word, $id, $u, $o, $P, $V, $R, $enc, $u_pass); return ($new_hash, $word); }