diff options
Diffstat (limited to 'Master/tlpkg/tlgs/Resource/Init/pdf_sec.ps')
-rw-r--r-- | Master/tlpkg/tlgs/Resource/Init/pdf_sec.ps | 829 |
1 files changed, 0 insertions, 829 deletions
diff --git a/Master/tlpkg/tlgs/Resource/Init/pdf_sec.ps b/Master/tlpkg/tlgs/Resource/Init/pdf_sec.ps deleted file mode 100644 index 9e6c1c0f074..00000000000 --- a/Master/tlpkg/tlgs/Resource/Init/pdf_sec.ps +++ /dev/null @@ -1,829 +0,0 @@ -% Copyright (C) 2001-2021 Artifex Software, Inc. -% All Rights Reserved. -% -% This software is provided AS-IS with no warranty, either express or -% implied. -% -% This software is distributed under license and may not be copied, -% modified or distributed except as expressly authorized under the terms -% of the license contained in the file LICENSE in this distribution. -% -% Refer to licensing information at http://www.artifex.com or contact -% Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, -% CA 94945, U.S.A., +1(415)492-9861, for further information. -% -% Copyright (C) 1996-1998 Geoffrey Keating. -% Copyright (C) 2001-2008 Artifex Software, Inc. -% This file may be freely distributed with or without modifications, -% so long as modified versions are marked as such and copyright notices are -% not removed. - -% Implementation of security hooks for PDF reader. - -% This file contains the procedures that have to take encryption into -% account when reading a PDF file. It was originally distributed -% separately by Geoffrey Keating as an add-on to version 6 and earlier. - -% Modified by Alex Cherepanov to work with GS 6.60 and higher. -% New versions of GS require explicit checks for /true, /false, and /null -% in .decpdfrun. This fix is backward-compatible. - -% Modified by Raph Levien and Ralph Giles to use the new C -% implementations of md5 and arcfour in ghostscript 7.01, and to -% be compatible with PDF 1.4 128-bit encryption. - -% Modified by Ralph Giles for PDF 1.6 AES encryption. - -% Modified by Michael Constant for PDF 1.7 ExtensionLevel 3 -% AES-256 encryption. - -/.setlanguagelevel where { pop 2 .setlanguagelevel } if -.currentglobal //true .setglobal -pdfdict begin - -% Older ghostscript versions do not have .pdftoken, so we use 'token' instead. -/.pdftoken where { pop } { /.pdftoken /token load def } ifelse - -% take a stream and arc4 decrypt it. -% <stream> <key> arc4decodefilter <stream> -/arc4decodefilter { - 1 dict begin - /Key exch def - currentdict end /ArcfourDecode filter -} bind executeonly def - -% <ciphertext> <key> arc4decode <plaintext> -/arc4decode { - 1 index length 0 eq { - pop - } { - 1 index length string 3 1 roll arc4decodefilter exch readstring pop - } ifelse -} bind executeonly def - -% take a stream and aes decrypt it. -% <stream> <key> aesdecodefilter <stream> -/aesdecodefilter { - 1 dict begin - /Key exch def - currentdict end - /AESDecode filter -} bind executeonly def - -% AES decrypt a string, returning a string. The second argument can -% be a dictionary of the form << /Key key /Padding false >>, which -% specifies the key and any options for the AESDecode filter, or it -% can just be a string (the key). -% -% <ciphertext> <dict> aesdecode <plaintext> -% <ciphertext> <key> aesdecode <plaintext> -/aesdecode { - 1 index length 0 eq { - pop - } { - 1 index length string 3 1 roll - - % If our second argument is a dictionary, it's the full set - % of decoding options (including the key); pass it directly - % to the AESDecode filter. Otherwise, it's just the key, so - % call aesdecodefilter to construct the dictionary. - dup type /dicttype eq { /AESDecode filter } { aesdecodefilter } ifelse - - exch readstring pop - } ifelse -} bind executeonly def - -/md5 { - 16 string dup /MD5Encode filter dup 4 3 roll writestring closefile -} bind executeonly def - -/md5_trunk { - md5 0 pdf_key_length getinterval -} bind executeonly def - -/sha256 { - 32 string dup /SHA256Encode filter dup 4 3 roll writestring closefile -} bind executeonly def - -% <string> contains_non_ascii <bool> -/contains_non_ascii { - //false exch { 128 ge { pop //true exit } if } forall -} bind executeonly def - -/pdf_padding_string - <28bf4e5e4e758a41 64004e56fffa0108 - 2e2e00b6d0683e80 2f0ca9fe6453697a> -def - -% Pad a key out to 32 bytes. -/pdf_pad_key { % <key> pdf_pad_key <padded key> - dup length 32 gt { 0 32 getinterval } if - pdf_padding_string - 0 32 3 index length sub getinterval - concatstrings -} bind executeonly def - -/pdf_xorbytes { % <iter-num> <key> pdf_xorbytes <xored-key> - dup length dup string - exch 1 sub 0 1 3 2 roll { - % <iter-num> <key> <new-key> <byte-num> - dup 3 index exch get 4 index xor - % <iter-num> <key> <new-key> <byte-num> <byte> - 3 copy put pop pop - } for - 3 1 roll pop pop -} bind executeonly def - -% Get length of encryption key in bytes -/pdf_key_length { % pdf_key_length <key_length> - Trailer /Encrypt oget - dup /V knownoget not { 0 } if 1 eq - { pop 5 } % If V == 1 then always use 40 bits - { /Length knownoget { -3 bitshift } { 5 } ifelse } - ifelse -} bind executeonly def - -% Algorithm 3.2 -/pdf_compute_encryption_key { % <password> pdf_compute_encryption_key <key> - % Step 1. - pdf_pad_key - - % Step 2, 3. - Trailer /Encrypt oget dup /O oget - % <padded-key> <encrypt> <O> - - % Step 4. - exch /P oget 4 string exch - 2 copy 255 and 0 exch put - 2 copy -8 bitshift 255 and 1 exch put - 2 copy -16 bitshift 255 and 2 exch put - 2 copy -24 bitshift 255 and 3 exch put pop - % <padded-key> <O> <P> - - % Step 5. - Trailer /ID knownoget { 0 oget } { - () - ( **** Error: ID key in the trailer is required for encrypted files.\n) pdfformaterror - ( File may not be possible to decrypt.\n) pdfformaterror - } ifelse - 3 { concatstrings } repeat - % We will finish step 5 after possibly including step 6. - - % The following only executed for /R equal to 3 or more - Trailer /Encrypt oget dup /R oget dup 3 ge { - - % Step 6. If EncryptMetadata is false, pass 0xFFFFFFFF to md5 function - % The PDF 1.5 Spec says that EncryptMetadata is an undocumented - % feature of PDF 1.4. That implies that this piece of logic should - % be executed if R >= 3. However testing with Acrobat 5.0 and 6.0 shows - % that this step is not executed if R equal to 3. Thus we have a test for - % R being >= 4. - 4 ge { - /EncryptMetadata knownoget % Get EncryptMetadata (if present) - not { //true } if % Default is true - not { % If EncryptMetadata is false - <ff ff ff ff> concatstrings % Add 0xFFFFFFFF to working string - } if - } { - pop % Remove Encrypt dict - } ifelse - md5_trunk % Finish step 5 and 6. - - % Step 7. Executed as part of step 6 - % Step 8. (This step is defintely a part of PDF 1.4.) - 50 { md5_trunk } repeat - } { - pop pop md5_trunk % Remove R, Encrypt dict, finish step 5 - } ifelse - - % Step 9 - Done in md5_trunk. -} bind executeonly def - -% Algorithm 3.4 -/pdf_gen_user_password_R2 { % <filekey> pdf_gen_user_password_R2 <U> - - % Step 2. - pdf_padding_string exch arc4decode -} bind executeonly def - -% Algorithm 3.5 -/pdf_gen_user_password_R3 { % <filekey> pdf_gen_user_password_R3 <U> - - % Step 2. - pdf_padding_string - - % Step 3. - Trailer /ID knownoget { 0 oget } { - () - ( **** Error: ID key in the trailer is required for encrypted files.\n) pdfformaterror - ( File may not be possible to decrypt.\n) pdfformaterror - } ifelse - concatstrings md5 - - % Step 4. - 1 index arc4decode - - % Step 5. - 1 1 19 { - 2 index pdf_xorbytes arc4decode - } for - exch pop - -} bind executeonly def - -/pdf_gen_user_password { % <password> pdf_gen_user_password <filekey> <U> - % common Step 1 of Algorithms 3.4 and 3.5. - pdf_compute_encryption_key dup - - Trailer /Encrypt oget - - /R oget dup 2 eq { - pop pdf_gen_user_password_R2 - } { - dup 3 eq { - pop pdf_gen_user_password_R3 - } { - dup 4 eq { % 4 uses the algorithm as 3 - pop pdf_gen_user_password_R3 - } { - % This procedure is only used if R is between 2 and 4, - % so we should never get here. - /pdf_gen_user_password cvx /undefined signalerror - } ifelse - } ifelse - } ifelse -} bind executeonly def - -% Algorithm 3.6 -% <password> pdf_check_pre_r5_user_password <filekey> true -% <password> pdf_check_pre_r5_user_password false -/pdf_check_pre_r5_user_password { - pdf_gen_user_password - - Trailer /Encrypt oget /U oget - - 0 2 index length getinterval eq { - //true - } { - pop //false - } ifelse -} bind executeonly def - -% Compute an owner key, ie the result of step 4 of Algorithm 3.3 -/pdf_owner_key % <password> pdf_owner_key <owner-key> -{ - % Step 1. - pdf_pad_key - - % Step 2. - md5_trunk - - % 3.3 Step 3. Only executed for /R equal to 3 or more - Trailer /Encrypt oget /R oget 3 ge { - 50 { md5_trunk } repeat - } if - - % Step 4 - Done in md5_trunk. -} bind executeonly def - -% Algorithm 3.7 -% <password> pdf_check_pre_r5_owner_password <filekey> true -% <password> pdf_check_pre_r5_owner_password false -/pdf_check_pre_r5_owner_password { - % Step 1. - pdf_owner_key - - % Step 2. - Trailer /Encrypt oget dup /O oget 2 index arc4decode - % <encryption-key> <encrypt-dict> <decrypted-O> - - % Step 3. Only executed for /R equal to 3 or more - exch /R oget 3 ge { - 1 1 19 { - 2 index pdf_xorbytes arc4decode - } for - } if - exch pop - % <result-of-step-3> - - pdf_check_pre_r5_user_password -} bind executeonly def - -% Algorithm 3.2a -% <password> pdf_check_r5_password <filekey> true -% <password> pdf_check_r5_password false -/pdf_check_r5_password { - 10 dict begin % temporary dict for local variables - - % Step 1. - % If the .saslprep operator isn't available (because ghostscript - % wasn't built with libidn support), just skip this step. ASCII - % passwords will still work fine, and even most non-ASCII passwords - % will be okay; any non-ASCII passwords that fail will produce a - % warning from pdf_process_Encrypt. - /.saslprep where { pop .saslprep } if - - % Step 2. - dup length 127 gt { 0 127 getinterval } if - /Password exch def - - % Step 3. - /O Trailer /Encrypt oget /O oget def - /U Trailer /Encrypt oget /U oget def - - Password O 32 8 getinterval concatstrings - U 0 48 getinterval concatstrings sha256 - - O 0 32 getinterval eq { - % Step 3, second paragraph. - - Password O 40 8 getinterval concatstrings - U 0 48 getinterval concatstrings sha256 - - 16 string Trailer /Encrypt oget /OE oget concatstrings - << /Key 4 -1 roll /Padding //false >> aesdecode //true - } { - % Step 4. - Password U 32 8 getinterval concatstrings sha256 - U 0 32 getinterval eq { - % Step 4, second paragraph. - Password U 40 8 getinterval concatstrings sha256 - - 16 string Trailer /Encrypt oget /UE oget concatstrings - << /Key 4 -1 roll /Padding //false >> aesdecode //true - } { - //false - } ifelse - } ifelse - - % Step 5. - dup { - % Adobe says to decrypt the Perms string using "ECB mode with - % an initialization vector of zero", which must be a mistake -- - % ECB mode doesn't use initialization vectors. It looks like - % they meant "ECB mode, or CBC mode with an initialization - % vector of zero", since the two are equivalent for a single- - % block message. We use the latter. - 16 string Trailer /Encrypt oget /Perms oget concatstrings - << /Key 4 index /Padding //false >> aesdecode - - 9 3 getinterval (adb) eq not { - ( **** Error: Failed to decrypt Perms string.\n) pdfformaterror - ( Cannot decrypt PDF file.\n) pdfformaterror - printProducer - /pdf_check_r5_password cvx /rangecheck signalerror - } if - } if - - end -} bind executeonly def - -% <password> pdf_check_password <filekey> true -% <password> pdf_check_password false -/pdf_check_password { - % If R is 2, 3, or 4, use Algorithms 3.6 and 3.7 to see if this is - % a valid user or owner password. Following historical practice, - % we treat the password as an arbitrary string of bytes and don't - % interpret it in any way. (If the password fails, it would be - % nice to try some plausible character set conversions, but this - % gets complicated. Even Adobe products don't seem to handle it - % consistently.) - % - % If R is 5, use Algorithm 3.2a. The password should be text, in - % either UTF-8 or the current locale's charset. - - Trailer /Encrypt oget /R oget - - dup dup 2 ge exch 4 le and { - pop - dup pdf_check_pre_r5_user_password { - exch pop //true - } { - pdf_check_pre_r5_owner_password - } ifelse - } { - dup 5 eq { - pop - % First, try the password as UTF-8. - dup pdf_check_r5_password { - exch pop //true - } { - % The password didn't work as UTF-8, so maybe it's in the - % locale character set instead. If possible, convert it to - % UTF-8 and try again. - /.locale_to_utf8 where { - pop .locale_to_utf8 pdf_check_r5_password - } { - pop //false - } ifelse - } ifelse - } { - dup 6 eq { - pop - % First, try the password as UTF-8. - dup Trailer /Encrypt oget //check_r6_password exec { - exch pop //true - } { - % The password didn't work as UTF-8, so maybe it's in the - % locale character set instead. If possible, convert it to - % UTF-8 and try again. - /.locale_to_utf8 where { - pop .locale_to_utf8 Trailer /Encrypt oget //check_r6_password exec - } { - pop //false - } ifelse - } ifelse - } { - ( **** Warning: This file uses an unknown standard security handler revision: ) - exch =string cvs concatstrings (\n) concatstrings pdfformatwarning - ( Cannot decrypt PDF file.\n) pdfformaterror - printProducer - /pdf_check_password cvx /undefined signalerror - } ifelse - } ifelse - } ifelse -} bind executeonly def -systemdict /check_r6_password .forceundef - -% Process the encryption information in the Trailer. -/pdf_process_Encrypt { - Trailer /Encrypt oget - /Filter oget /Standard eq not { - ( **** Warning: This file uses an unknown security handler.\n) pdfformatwarning - ( Cannot decrypt PDF file.\n) pdfformaterror - printProducer - /pdf_process_Encrypt cvx /undefined signalerror - } if - - % Bug 702598: We can have a trailer dictionary with an /Encrypt entry, and if the - % Encrypt dictionary is V 4 or greater we can (should ?) have StrF and stmF entries. - % - % The code below checks for the existence of StmF and StrF entries. Its possible - % that both may be /Identity (which means no encryption) in which case we don't need to check - % the password, as we won't need to decrypt any streams or strings. Note that the dict may still - % have a non-Identity /EFF (embedded files) key, but Ghostscript doesn't process embedded - % files so we don't have to worry about that. - Trailer /Encrypt oget dup - /V get 4 ge { - % NB: Entries in the Encrypt dictionary cannot be indirect references - dup /StmF .knownget { - /Identity eq not - } { - false % default StmF is Identity - }ifelse - 1 index /StrF .knownget { - /Identity eq not - } { - false % default StrF is Identity - }ifelse - or - % ...still in the V4 or above checking... - % Even if StmF and StrF are Identity, if the StdCF is missing AuthEvent - % or it is DocOpen, we require the password. Check for that. - 1 index /CF .knownget { - oforce dup type /dicttype eq { - /StdCF .knownget { - oforce dup type /dicttype eq { - /AuthEvent .knownget { - oforce dup type /nametype eq { - /DocOpen eq - or - }{ - ( **** Error: AuthEvent has wrong type.\n) pdfformaterror - ( Cannot decrypt PDF file.\n) pdfformaterror - /pdf_process_Encrypt cvx /invalidfileaccess signalerror - } ifelse - } { - pop true % no AuthEvent, default is DocOpen, require password - } ifelse - }{ - ( **** Error: StdCF has wrong type.\n) pdfformaterror - ( Cannot decrypt PDF file.\n) pdfformaterror - /pdf_process_Encrypt cvx /invalidfileaccess signalerror - } ifelse - } { - pop true % no StdCF, require password - } ifelse - }{ - ( **** Error: CF has wrong type.\n) pdfformaterror - ( Cannot decrypt PDF file.\n) pdfformaterror - /pdf_process_Encrypt cvx /invalidfileaccess signalerror - } ifelse - } { - pop true % no CF, require password - } ifelse - exch pop % discard Encrypt dict - }{ - % Not V4 or later - pop true % discard Encrypt dict, require password - } ifelse - % If we were given a PDFPassword, check it anyway, even if the - % code above said we didn't need one. This will allow us to process - % PDF files with an initial CryptFilter which has StrF=StmF=Identity, - % but contains streams which themselves have non-Identity StmF or StrF. - /PDFPassword where { - pop true - } - { - false - } ifelse - or - { - () pdf_check_password - { - /FileKey exch def - } { - /PDFPassword where { - pop PDFPassword pdf_check_password - { - /FileKey exch def - } { - ( **** Error: Password did not work.\n) pdfformaterror - ( Cannot decrypt PDF file.\n) pdfformaterror - - % If ghostscript was built without libidn, it's missing the - % .saslprep operator and thus can't do proper Unicode password - % normalization. Similarly, if the system provides neither - % iconv nor the Windows MultiByteToWideChar function, then we - % won't have the .locale_to_utf8 operator to convert passwords - % from the locale character set to UTF-8. - % - % It's not a huge problem if you're missing either or both of - % these. ASCII passwords will work fine regardless, and even - % Unicode passwords will often be okay. - % - % However, if .saslprep or .locale_to_utf8 is missing, and the - % user enters a non-ASCII password that doesn't work, we give - % a warning message. - PDFPassword contains_non_ascii { - /.saslprep where not { - ( **** WARNING: Ghostscript was configured without libidn,\n) - ( **** so non-ASCII passwords aren't supported!\n) - concatstrings pdfformaterror - } { - pop - /.locale_to_utf8 where not { - ( **** WARNING: Ghostscript was configured without iconv,\n) - ( **** so non-ASCII passwords aren't supported!\n) - concatstrings pdfformaterror - } { - pop - } ifelse - } ifelse - } if - - /pdf_process_Encrypt cvx /invalidfileaccess signalerror - } ifelse - } { - ( **** This file requires a password for access.\n) pdfformaterror - /pdf_process_Encrypt cvx /invalidfileaccess signalerror - } ifelse - } ifelse - } - { - ( **** This file has an Encryption dictionary, but both the StmF and StrF entries\n) pdfformatwarning - ( **** are /Identity, and AuthEvent allows the document to be opened. It is possible\n) pdfformatwarning - ( **** that embedded streams may still use encryption, if the file fails to process\n) pdfformatwarning - ( **** you may need to supply a User or Owner password by setting -sPDFPassword=\n) pdfformatwarning - } ifelse -} bind executeonly def - -% Calculate the key used to decrypt an object (to pass to .decpdfrun or -% put into a stream dictionary). -/computeobjkey % <object#> <generation#> computeobjkey <keystring> -{ - Trailer /Encrypt oget /V oget 5 eq { - % Encrypt version 5 doesn't use object keys; everything is - % encrypted with the file key. - pop pop FileKey - } { - exch - FileKey length 5 add string - dup 0 FileKey putinterval - exch - % stack: gen# string obj# - 2 copy 255 and FileKey length exch put - 2 copy -8 bitshift 255 and FileKey length 1 add exch put - 2 copy -16 bitshift 255 and FileKey length 2 add exch put - pop exch - 2 copy 255 and FileKey length 3 add exch put - 2 copy -8 bitshift 255 and FileKey length 4 add exch put - pop - % this step is for the AES cipher only - Trailer /Encrypt oget - dup /StmF knownoget { - %% Treat StmF of 'Identity' the same as if it is missing. - dup /Identity eq { - pop pop - } { - exch /CF knownoget { - exch oget /CFM oget /AESV2 eq { - (sAlT) concatstrings - } if - } { - pop - } ifelse - } ifelse - } { - pop - } ifelse - md5 0 FileKey length 5 add 2 index length .min getinterval - } ifelse -} bind executeonly def - -% As .pdfrun, but decrypt strings with key <key>. -/PDFScanRules_true << /PDFScanRules //true >> def -/PDFScanRules_null << /PDFScanRules //null >> def -/.decpdfrun % <file> <keystring> <opdict> .decpdfrun - - { % Construct a procedure with the file, opdict and key bound into it. - 2 index cvlit mark - /PDFScanRules .getuserparam //null eq { - //PDFScanRules_true { setuserparams } 0 get % force PDF scanning mode - mark 7 4 roll - } { - mark 5 2 roll - } ifelse - { .pdftoken not { (%%EOF) cvn cvx } if - dup xcheck - { PDFDEBUG { dup //== exec flush } if - 3 -1 roll pop - 2 copy .knownget - { exch pop exch pop exec - } - { exch pop - dup /true eq - { pop //true - } - { dup /false eq - { pop //false - } - { dup /null eq - { pop //null - } - { ( **** Error: Unknown operator: ) - exch =string cvs concatstrings (\n) concatstrings - pdfformaterror - ( Output may be incorrect.\n) pdfformaterror - } - ifelse - } - ifelse - } - ifelse - } - ifelse - } - { exch pop PDFDEBUG { dup ==only ( ) print flush } if - dup type /stringtype eq - { - % Check if we have encrypted strings R>=4 allows for - % selection of encryption on streams and strings - Trailer /Encrypt oget % Get encryption dictionary - dup /R oget 4 lt % only >=4 has selectable - { % R < 4 --> arc4 strings - pop 1 index arc4decode % Decrypt string - PDFDEBUG { (%Decrypted: ) print dup //== exec flush } if - } { % Else R >= 4 - /StrF knownoget % Get StrF (if present) - { % If StrF is present ... - dup /Identity eq not % Check if StrF != Identity - { /StdCF eq - { Trailer /Encrypt oget /CF knownoget { - /StdCF oget /CFM oget - dup /AESV2 eq exch /AESV3 eq or - } { - //false - } ifelse { % Decrypt string - 1 index aesdecode - } { - 1 index arc4decode - } ifelse - } - { 1 index arc4decode } - ifelse % If StrF != StdCF - PDFDEBUG { (%Decrypted: ) print dup //== exec flush } if - } - { pop } - ifelse % If StrF != identity - } - if % If StrF is known - } - ifelse % Ifelse R < 4 - } { - dup type /nametype eq { - .pdffixname - } if - } - ifelse - exch pop - } - ifelse - } - aload pop //.packtomark exec cvx - { loop } 0 get 2 packedarray cvx - { stopped } 0 get - /PDFScanRules .getuserparam //null eq { - //PDFScanRules_null { setuserparams } 0 get % reset PDF scannig mode if it was off - } if - /PDFsource PDFsource - { store { stop } if } aload pop //.packtomark exec cvx - /PDFsource 3 -1 roll store exec - } bind executeonly def -currentdict /PDFScanRules_true undef -currentdict /PDFScanRules_null undef - -% Run the code to resolve an object reference. -/pdf_run_resolve -{ /FileKey where % Check if the file is encrypted - { pop % File is encrypted - 2 copy computeobjkey dup 4 1 roll - PDFfile exch resolveopdict .decpdfrun - dup dup dup 5 2 roll - % stack: object object key object object - { % Use loop to provide an exitable context. - xcheck exch type /dicttype eq and % Check if executable dictionary - not { % If object is not ... - pop pop % ignore object - exit % Exit 'loop' context - } if % If not possible stream - % Starting with PDF 1.4 (R = 3), there are some extra features - % which control encryption of streams. The EncryptMetadata entry - % in the Encrypt dict controls the encryption of metadata streams. - Trailer /Encrypt oget % Get encryption dictionary - dup /R oget dup 3 lt % Only PDF 1.4 and higher has options - { % R < 3 --> all streams encrypted - pop pop /StreamKey exch put % Insert StreamKey in dictionary - exit % Exit 'loop' context - } if - % Check EncryptMeta. stack: object object key Encrypt R - exch dup /EncryptMetadata knownoget % Get EncryptMetadata (if present) - not { //true } if % If not present default = true - not % Check if EncryptMetadata = false - { % if false we need to check the stream type - 3 index /Type knownoget % Get stream type (if present) - not { //null } if % If type not present use fake name - /Metadata eq % Check if the type is Metadata - { pop pop pop pop % Type == Metadata --> no encryption - exit % Exit 'loop' context - } if - } if - % PDF 1.5 encryption (R == 4) has selectable encryption handlers. If - % this is not PDF 1.5 encryption (R < 4) then we are done checking and - % we need to decrypt the stream. stack: object object key R Encrypt - exch 4 lt % Check for less than PDF 1.5 - { pop /StreamKey exch put % Insert StreamKey in dictionary - exit % Exit 'loop' context - } if - % Check if the stream encryption handler (StmF) == Identity. - PDFDEBUG { - Trailer /Encrypt oget /CF knownoget { - /StdCF oget /CFM oget - (Encrypt StmF is StdCF with CFM ) print = - } if - } if - /StmF knownoget % Get StmF (if present) - not { /Identity } if % If StmF not present default = Identity - /Identity eq % Check if StmF == Identity - { pop pop % Identity --> no encryption - exit % Exit 'loop' context - } if - % If we get here then we need to decrypt the stream. - /StreamKey exch put % Insert StreamKey into dictionary - exit % Exit 'loop' context, never loop - } loop % End of loop exitable context - } { % Else file is not encrypted - PDFfile resolveopdict .pdfrun - } ifelse % Ifelse encrypted -} bind executeonly def - -% Prefix a decryption filter to a stream if needed. -% Stack: readdata? dict parms file/string filternames -% (both before and after). -/pdf_decrypt_stream - { 3 index /StreamKey known % Check if the file is encrypted - { - exch - % Stack: readdata? dict parms filternames file/string - 3 index /StreamKey get - Trailer /Encrypt oget - dup /StmF knownoget - { % stack: key Encrypt StmF - exch /CF knownoget { - exch oget /CFM oget % stack: key StmF-CFM - dup /AESV2 eq exch /AESV3 eq or - } { pop //false } ifelse - { aesdecodefilter } % install the requested filter - { arc4decodefilter } - ifelse - } - { pop arc4decodefilter } % fallback for no StmF - ifelse - exch - } if - } bind executeonly def - -end % pdfdict - -systemdict /pdfdict .forceundef % hide pdfdict - -.setglobal |