diff --git a/pdfcrypt.ml b/pdfcrypt.ml index 9742be3..66c9121 100644 --- a/pdfcrypt.ml +++ b/pdfcrypt.ml @@ -4,6 +4,10 @@ open Pdfio let crypt_debug = ref false +let nums pdf = + Pdf.objiter (fun n _ -> Printf.printf "%n " n) pdf; + flprint "\n" + (* Given an object number, generation number, input key and key length in bits, apply Algorithm 3.1 from the PDF Reference manual to obtain the hash to be used by the encryption function. *) @@ -1088,11 +1092,57 @@ let is_encrypted pdf = (* recrypt_pdf pdf password re-encrypts a PDF document which was decrypted with the user or owner password given using that same user password *) let recrypt_pdf_user pdf pw = - let pdf = Pdf.renumber (Pdf.changes pdf) pdf in - let (crypt_type, u, o, p, id, ue, oe), encrypt_metadata, perms = - match pdf.Pdf.saved_encryption with - None -> raise (Pdf.PDFError "recrypt_pdf: no saved encryption") - | Some x -> (x.Pdf.from_get_encryption_values, x.Pdf.encrypt_metadata, x.Pdf.perms) + let (crypt_type, u, o, p, id, ue, oe), encrypt_metadata, perms = + match pdf.Pdf.saved_encryption with + None -> raise (Pdf.PDFError "recrypt_pdf: no saved encryption") + | Some x -> (x.Pdf.from_get_encryption_values, x.Pdf.encrypt_metadata, x.Pdf.perms) + in + match crypt_type with + | Pdf.AESV3 iso -> + let oe = + match oe with + Some oe -> oe + | None -> raise (Pdf.PDFError "recrypt_pdf: bad /oe") + and ue = + match ue with + Some ue -> ue + | None -> raise (Pdf.PDFError "recrypt_pdf: bad /ue") + in + let key = + if authenticate_user_password_aesv3 iso (make_utf8 pw) u + then file_encryption_key_aesv3_user iso (make_utf8 pw) u ue + else raise (Pdf.PDFError "recrypt_pdf: failed AESV3 fek.") + in + encrypt_pdf_AES256_inner + iso encrypt_metadata o u p perms oe ue id + (string_of_bytes key) pdf + | Pdf.AESV2 -> + encrypt_pdf_AES_inner o u p pw id encrypt_metadata pdf + | Pdf.ARC4 (40, _) -> + encrypt_pdf_40bit_inner o u p pw id pdf + | Pdf.ARC4 (128, 4) -> + encrypt_pdf_128bit_inner_r4 o u p pw id pdf encrypt_metadata + | Pdf.ARC4 (128, _) -> + encrypt_pdf_128bit_inner o u p pw id pdf + | _ -> raise (Pdf.PDFError "recrypt_pdf: bad encryption") + +(* recrypt_pdf_owner password re-encrypts a PDF document which was decrypted with +the user or owner password given using that same owner password *) +let recrypt_pdf_owner pdf owner_pw = + let (crypt_type, u, o, p, id, ue, oe), encrypt_metadata, perms = + match pdf.Pdf.saved_encryption with + None -> + raise (Pdf.PDFError "recrypt_pdf: no saved encryption") + | Some x -> + (x.Pdf.from_get_encryption_values, x.Pdf.encrypt_metadata, x.Pdf.perms) + in + let key, pw = + match + key_or_user_password_from_owner + ~encryption_values:(crypt_type, u, o, oe) owner_pw pdf + with + None -> raise (Pdf.PDFError "Recrypt with owner password failed.") + | Some (key, pw) -> (key, pw) in match crypt_type with | Pdf.AESV3 iso -> @@ -1105,14 +1155,8 @@ let recrypt_pdf_user pdf pw = Some ue -> ue | None -> raise (Pdf.PDFError "recrypt_pdf: bad /ue") in - let key = - if authenticate_user_password_aesv3 iso (make_utf8 pw) u - then file_encryption_key_aesv3_user iso (make_utf8 pw) u ue - else raise (Pdf.PDFError "recrypt_pdf: failed AESV3 fek.") - in - encrypt_pdf_AES256_inner - iso encrypt_metadata o u p perms oe ue id - (string_of_bytes key) pdf + encrypt_pdf_AES256_inner + iso encrypt_metadata o u p perms oe ue id key pdf | Pdf.AESV2 -> encrypt_pdf_AES_inner o u p pw id encrypt_metadata pdf | Pdf.ARC4 (40, _) -> @@ -1121,53 +1165,16 @@ let recrypt_pdf_user pdf pw = encrypt_pdf_128bit_inner_r4 o u p pw id pdf encrypt_metadata | Pdf.ARC4 (128, _) -> encrypt_pdf_128bit_inner o u p pw id pdf - | _ -> raise (Pdf.PDFError "recrypt_pdf: bad encryption") + | _ -> raise (Pdf.PDFError "recrypt_pdf_owner: bad encryption") -(* recrypt_pdf_owner password re-encrypts a PDF document which was decrypted with -the user or owner password given using that same owner password *) -let recrypt_pdf_owner pdf owner_pw = - let pdf = Pdf.renumber (Pdf.changes pdf) pdf in - let (crypt_type, u, o, p, id, ue, oe), encrypt_metadata, perms = - match pdf.Pdf.saved_encryption with - None -> - raise (Pdf.PDFError "recrypt_pdf: no saved encryption") - | Some x -> - (x.Pdf.from_get_encryption_values, x.Pdf.encrypt_metadata, x.Pdf.perms) - in - let key, pw = - match - key_or_user_password_from_owner - ~encryption_values:(crypt_type, u, o, oe) owner_pw pdf - with - None -> raise (Pdf.PDFError "Recrypt with owner password failed.") - | Some (key, pw) -> (key, pw) - in - match crypt_type with - | Pdf.AESV3 iso -> - let oe = - match oe with - Some oe -> oe - | None -> raise (Pdf.PDFError "recrypt_pdf: bad /oe") - and ue = - match ue with - Some ue -> ue - | None -> raise (Pdf.PDFError "recrypt_pdf: bad /ue") - in - encrypt_pdf_AES256_inner - iso encrypt_metadata o u p perms oe ue id key pdf - | Pdf.AESV2 -> - encrypt_pdf_AES_inner o u p pw id encrypt_metadata pdf - | Pdf.ARC4 (40, _) -> - encrypt_pdf_40bit_inner o u p pw id pdf - | Pdf.ARC4 (128, 4) -> - encrypt_pdf_128bit_inner_r4 o u p pw id pdf encrypt_metadata - | Pdf.ARC4 (128, _) -> - encrypt_pdf_128bit_inner o u p pw id pdf - | _ -> raise (Pdf.PDFError "recrypt_pdf_owner: bad encryption") - -let recrypt_pdf pdf pw = - try - try recrypt_pdf_user pdf pw with _ -> recrypt_pdf_owner pdf pw - with - _ -> raise (Pdf.PDFError "recrypt_pdf failed. Wrong password?") +let recrypt_pdf ?(renumber=true) pdf pw = + Printf.printf "******************************************recrypt_pdf, renumber = %b\n" renumber; + let pdf = + if renumber then Pdf.renumber (Pdf.changes pdf) pdf + else pdf + in + try + try recrypt_pdf_user pdf pw with _ -> recrypt_pdf_owner pdf pw + with + _ -> raise (Pdf.PDFError "recrypt_pdf failed. Wrong password?") diff --git a/pdfcrypt.mli b/pdfcrypt.mli index 7d29640..bfea8bb 100644 --- a/pdfcrypt.mli +++ b/pdfcrypt.mli @@ -36,7 +36,7 @@ val is_encrypted : Pdf.t -> bool (** [recrypt_pdf decrypted_and_modified] re-encrypts a PDF document which was decrypted using the user password and owner password from the original encrypted file and the same permissions and encryption parameters. *) -val recrypt_pdf : Pdf.t -> string -> Pdf.t +val recrypt_pdf : ?renumber:bool -> Pdf.t -> string -> Pdf.t (** Encrypt a PDF documnent, using 40 bit encryption, with given user and owner passwords. *) diff --git a/pdfwrite.ml b/pdfwrite.ml index 637810d..b7cfb84 100644 --- a/pdfwrite.ml +++ b/pdfwrite.ml @@ -579,15 +579,11 @@ let dummy_encryption = (* Flatten a PDF document to an Pdfio.output. *) let pdf_to_output - ?(preserve_objstm = false) ?(generate_objstm = false) ?(compress_objstm = true) - ?(recrypt = None) - linearize encrypt pdf o + ?(preserve_objstm = false) ?(generate_objstm = false) + ?(compress_objstm = true) ?(recrypt = None) linearize encrypt pdf o = if !write_debug then - begin - flprint "****pdf_to_output\n"; - debug_whole_pdf pdf - end; + begin flprint "****pdf_to_output\n"; debug_whole_pdf pdf end; if !write_debug then Printf.printf "pdf_to_output: preserve %b, generate %b, linearize %b\n" preserve_objstm generate_objstm linearize; @@ -609,10 +605,7 @@ let pdf_to_output ([], false) (* Weren't asked to preserve, or nothing to put in streams *) in if !write_debug then - begin - flprint "****after object streams built\n"; - debug_whole_pdf pdf - end; + begin flprint "****after object streams built\n"; debug_whole_pdf pdf end; let encrypt = match recrypt with None -> encrypt @@ -632,15 +625,16 @@ let pdf_to_output in if !write_debug then flprint "Finished renumber\n"; if !write_debug then - begin - flprint "****after renumbering\n"; - debug_whole_pdf pdf - end; + begin flprint "****after renumbering\n"; debug_whole_pdf pdf end; let pdf = match recrypt with None -> pdf - | Some pw -> Pdfcrypt.recrypt_pdf pdf pw + | Some pw -> + Pdfcrypt.recrypt_pdf + ~renumber:(not (preserve_objstm || generate_objstm)) pdf pw in + if !write_debug then + begin flprint "****just before crypt_if_necessary\n"; debug_whole_pdf pdf end; let pdf = crypt_if_necessary pdf encrypt in if !write_debug then begin @@ -648,10 +642,7 @@ let pdf_to_output if Pdfcrypt.is_encrypted pdf then flprint "FILE IS ENCRYPTED\n" end; if !write_debug then - begin - flprint "****crypted, ready to write\n"; - debug_whole_pdf pdf - end; + begin flprint "****crypted, ready to write\n"; debug_whole_pdf pdf end; o.output_string (header pdf); let xrefs = ref [] and objiter = @@ -734,15 +725,11 @@ let change_id pdf f = (* Write a PDF to a channel. Don't use mk_id when the file is encrypted.*) let pdf_to_channel - ?(preserve_objstm = false) - ?(generate_objstm = false) - ?(compress_objstm = true) - ?(recrypt = None) + ?(preserve_objstm = false) ?(generate_objstm = false) + ?(compress_objstm = true) ?(recrypt = None) linearize encrypt mk_id pdf ch = - let pdf = - if mk_id then change_id pdf "" else pdf - in + let pdf = if mk_id then change_id pdf "" else pdf in pdf_to_output ~preserve_objstm ~generate_objstm ~compress_objstm ~recrypt linearize encrypt pdf (output_of_channel ch) @@ -754,18 +741,19 @@ existing object streams will be preserved. If [generate_objstm] is set, new ones will be generated in addition. To get totally fresh object streams, set [preserve_objstm=false, generate_objstm=true]. *) let pdf_to_file_options - ?(preserve_objstm = false) - ?(generate_objstm = false) - ?(compress_objstm = true) - ?(recrypt = None) + ?(preserve_objstm = false) ?(generate_objstm = false) + ?(compress_objstm = true) ?(recrypt = None) linearize encrypt mk_id pdf f = let pdf' = if mk_id then change_id pdf f else pdf and ch = open_out_bin f in - pdf_to_channel - ~preserve_objstm ~generate_objstm ~compress_objstm ~recrypt - linearize encrypt false pdf' ch; - close_out ch + try + pdf_to_channel + ~preserve_objstm ~generate_objstm ~compress_objstm ~recrypt + linearize encrypt false pdf' ch; + close_out ch + with + e -> close_out ch; raise e let pdf_to_file pdf f = pdf_to_file_options