星火微课系统客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pdf_sec.ps 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. % Copyright (C) 1996-1998 Geoffrey Keating.
  2. % Copyright (C) 2001-2008 Artifex Software, Inc.
  3. % This file may be freely distributed with or without modifications,
  4. % so long as modified versions are marked as such and copyright notices are
  5. % not removed.
  6. % $Id: pdf_sec.ps 9740 2009-05-13 23:37:28Z alexcher $
  7. % Implementation of security hooks for PDF reader.
  8. % This file contains the procedures that have to take encryption into
  9. % account when reading a PDF file. It was originally distributed
  10. % separately by Geoffrey Keating as an add-on to version 6 and earlier.
  11. % Modified by Alex Cherepanov to work with GS 6.60 and higher.
  12. % New versions of GS require explicit checks for /true, /false, and /null
  13. % in .decpdfrun. This fix is backward-compatible.
  14. % Modified by Raph Levien and Ralph Giles to use the new C
  15. % implementations of md5 and arcfour in ghostscript 7.01, and to
  16. % be compatible with PDF 1.4 128-bit encryption.
  17. % Modified by Ralph Giles for PDF 1.6 AES encryption.
  18. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  19. .currentglobal true .setglobal
  20. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  21. pdfdict begin
  22. % Older ghostscript versions do not have .pdftoken, so we use 'token' instead.
  23. /.pdftoken where { pop } { /.pdftoken /token load def } ifelse
  24. % take a stream and arc4 decrypt it.
  25. % <stream> <key> arc4decodefilter <stream>
  26. /arc4decodefilter {
  27. 1 dict begin
  28. /Key exch def
  29. currentdict end /ArcfourDecode filter
  30. } bind def
  31. % <ciphertext> <key> arc4decode <plaintext>
  32. /arc4decode {
  33. 1 index length 0 eq {
  34. pop
  35. } {
  36. 1 index length string 3 1 roll arc4decodefilter exch readstring pop
  37. } ifelse
  38. } bind def
  39. % take a stream and aes decrypt it.
  40. % <stream> <key> aesdecodefilter <stream>
  41. /aesdecodefilter {
  42. 1 dict begin
  43. /Key exch def
  44. currentdict end
  45. /AESDecode filter
  46. } bind def
  47. % <ciphertext> <key> aesdecode <plaintext>
  48. /aesdecode {
  49. 1 index length 0 eq {
  50. pop
  51. } {
  52. 1 index length string 3 1 roll
  53. aesdecodefilter exch readstring pop
  54. } ifelse
  55. } bind def
  56. /md5 {
  57. 16 string dup /MD5Encode filter dup 4 3 roll writestring closefile
  58. } bind def
  59. /md5_trunk {
  60. md5 0 pdf_key_length getinterval
  61. } bind def
  62. /pdf_padding_string
  63. <28bf4e5e4e758a41 64004e56fffa0108
  64. 2e2e00b6d0683e80 2f0ca9fe6453697a>
  65. def
  66. % Pad a key out to 32 bytes.
  67. /pdf_pad_key { % <key> pdf_pad_key <padded key>
  68. dup length 32 gt { 0 32 getinterval } if
  69. pdf_padding_string
  70. 0 32 3 index length sub getinterval
  71. concatstrings
  72. } bind def
  73. /pdf_xorbytes { % <iter-num> <key> pdf_xorbytes <xored-key>
  74. dup length dup string
  75. exch 1 sub 0 1 3 2 roll {
  76. % <iter-num> <key> <new-key> <byte-num>
  77. dup 3 index exch get 4 index xor
  78. % <iter-num> <key> <new-key> <byte-num> <byte>
  79. 3 copy put pop pop
  80. } for
  81. 3 1 roll pop pop
  82. } bind def
  83. % Get length of encryption key in bytes
  84. /pdf_key_length { % pdf_key_length <key_length>
  85. Trailer /Encrypt oget
  86. dup /V knownoget not { 0 } if 1 eq
  87. { pop 5 } % If V == 1 then always use 40 bits
  88. { /Length knownoget { -3 bitshift } { 5 } ifelse }
  89. ifelse
  90. } bind def
  91. % Algorithm 3.2
  92. /pdf_compute_encryption_key { % <password> pdf_compute_encryption_key <key>
  93. % Step 1.
  94. pdf_pad_key
  95. % Step 2, 3.
  96. Trailer /Encrypt oget dup /O oget
  97. % <padded-key> <encrypt> <O>
  98. % Step 4.
  99. exch /P oget 4 string exch
  100. 2 copy 255 and 0 exch put
  101. 2 copy -8 bitshift 255 and 1 exch put
  102. 2 copy -16 bitshift 255 and 2 exch put
  103. 2 copy -24 bitshift 255 and 3 exch put pop
  104. % <padded-key> <O> <P>
  105. % Step 5.
  106. Trailer /ID knownoget { 0 oget } {
  107. ()
  108. ( **** ID key in the trailer is required for encrypted files.\n) pdfformaterror
  109. } ifelse
  110. 3 { concatstrings } repeat
  111. % We will finish step 5 after possibly including step 6.
  112. % The following only executed for /R equal to 3 or more
  113. Trailer /Encrypt oget dup /R oget dup 3 ge {
  114. % Step 6. If EncryptMetadata is false, pass 0xFFFFFFFF to md5 function
  115. % The PDF 1.5 Spec says that EncryptMetadata is an undocumented
  116. % feature of PDF 1.4. That implies that this piece of logic should
  117. % be executed if R >= 3. However testing with Acrobat 5.0 and 6.0 shows
  118. % that this step is not executed if R equal to 3. Thus we have a test for
  119. % R being >= 4.
  120. 4 ge {
  121. /EncryptMetadata knownoget % Get EncryptMetadata (if present)
  122. not { true } if % Default is true
  123. not { % If EncryptMetadata is false
  124. <ff ff ff ff> concatstrings % Add 0xFFFFFFFF to working string
  125. } if
  126. } {
  127. pop % Remove Encrypt dict
  128. } ifelse
  129. md5_trunk % Finish step 5 and 6.
  130. % Step 7. Executed as part of step 6
  131. % Step 8. (This step is defintely a part of PDF 1.4.)
  132. 50 { md5_trunk } repeat
  133. } {
  134. pop pop md5_trunk % Remove R, Encrypt dict, finish step 5
  135. } ifelse
  136. % Step 9 - Done in md5_trunk.
  137. } bind def
  138. % Algorithm 3.4
  139. /pdf_gen_user_password_R2 { % <filekey> pdf_gen_user_password_R2 <U>
  140. % Step 2.
  141. pdf_padding_string exch arc4decode
  142. } bind def
  143. % Algorithm 3.5
  144. /pdf_gen_user_password_R3 { % <filekey> pdf_gen_user_password_R3 <U>
  145. % Step 2.
  146. pdf_padding_string
  147. % Step 3.
  148. Trailer /ID knownoget { 0 oget } {
  149. ()
  150. ( **** ID key in the trailer is required for encrypted files.\n) pdfformaterror
  151. } ifelse
  152. concatstrings md5
  153. % Step 4.
  154. 1 index arc4decode
  155. % Step 5.
  156. 1 1 19 {
  157. 2 index pdf_xorbytes arc4decode
  158. } for
  159. exch pop
  160. } bind def
  161. /pdf_gen_user_password { % <password> pdf_gen_user_password <filekey> <U>
  162. % common Step 1 of Algorithms 3.4 and 3.5.
  163. pdf_compute_encryption_key dup
  164. Trailer /Encrypt oget
  165. /R oget dup 2 eq {
  166. pop pdf_gen_user_password_R2
  167. } {
  168. dup 3 eq {
  169. pop pdf_gen_user_password_R3
  170. } {
  171. dup 4 eq { % 4 uses the algorithm as 3
  172. pop pdf_gen_user_password_R3
  173. } {
  174. ( **** This file uses an unknown standard security handler revision: )
  175. exch =string cvs concatstrings pdfformaterror printProducer
  176. /pdf_check_user_password cvx /undefined signalerror
  177. } ifelse
  178. } ifelse
  179. } ifelse
  180. } bind def
  181. % Algorithm 3.6
  182. /pdf_check_user_password { % <password> pdf_check_user_password <filekey> true
  183. % <password> pdf_check_user_password false
  184. pdf_gen_user_password
  185. Trailer /Encrypt oget /U oget
  186. 0 2 index length getinterval eq {
  187. true
  188. } {
  189. pop false
  190. } ifelse
  191. } bind def
  192. % Compute an owner key, ie the result of step 4 of Algorithm 3.3
  193. /pdf_owner_key % <password> pdf_owner_key <owner-key>
  194. {
  195. % Step 1.
  196. pdf_pad_key
  197. % Step 2.
  198. md5_trunk
  199. % 3.3 Step 3. Only executed for /R equal to 3 or more
  200. Trailer /Encrypt oget /R oget 3 ge {
  201. 50 { md5_trunk } repeat
  202. } if
  203. % Step 4 - Done in md5_trunk.
  204. } bind def
  205. % Algorithm 3.7
  206. /pdf_check_owner_password { % <password> pdf_check_owner_password <filekey> true
  207. % <password> pdf_check_owner_password false
  208. % Step 1.
  209. pdf_owner_key
  210. % Step 2.
  211. Trailer /Encrypt oget dup /O oget 2 index arc4decode
  212. % <encryption-key> <encrypt-dict> <decrypted-O>
  213. % Step 3. Only executed for /R equal to 3 or more
  214. exch /R oget 3 ge {
  215. 1 1 19 {
  216. 2 index pdf_xorbytes arc4decode
  217. } for
  218. } if
  219. exch pop
  220. % <result-of-step-3>
  221. pdf_check_user_password
  222. } bind def
  223. % Process the encryption information in the Trailer.
  224. /pdf_process_Encrypt {
  225. Trailer /Encrypt oget
  226. /Filter oget /Standard eq not {
  227. ( **** This file uses an unknown security handler.\n) pdfformaterror
  228. printProducer
  229. /pdf_process_Encrypt cvx /undefined signalerror
  230. } if
  231. () pdf_check_user_password
  232. {
  233. /FileKey exch def
  234. } {
  235. /PDFPassword where {
  236. pop PDFPassword pdf_check_user_password
  237. {
  238. /FileKey exch def
  239. } {
  240. PDFPassword pdf_check_owner_password
  241. {
  242. /FileKey exch def
  243. } {
  244. ( **** Password did not work.\n) pdfformaterror
  245. printProducer
  246. /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  247. } ifelse
  248. } ifelse
  249. } {
  250. ( **** This file requires a password for access.\n) pdfformaterror
  251. printProducer
  252. /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  253. } ifelse
  254. } ifelse
  255. % Trailer /Encrypt oget /P oget 4 and 0 eq #? and
  256. % { ( ****This owner of this file has requested you do not print it.\n)
  257. % pdfformaterror printProducer
  258. % /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  259. % }
  260. % if
  261. } bind def
  262. % Calculate the key used to decrypt an object (to pass to .decpdfrun or
  263. % put into a stream dictionary).
  264. /computeobjkey % <object#> <generation#> computeobjkey <keystring>
  265. {
  266. exch
  267. FileKey length 5 add string
  268. dup 0 FileKey putinterval
  269. exch
  270. % stack: gen# string obj#
  271. 2 copy 255 and FileKey length exch put
  272. 2 copy -8 bitshift 255 and FileKey length 1 add exch put
  273. 2 copy -16 bitshift 255 and FileKey length 2 add exch put
  274. pop exch
  275. 2 copy 255 and FileKey length 3 add exch put
  276. 2 copy -8 bitshift 255 and FileKey length 4 add exch put
  277. pop
  278. % this step is for the AES cipher only
  279. Trailer /Encrypt oget
  280. dup /StmF knownoget {
  281. exch /CF knownoget {
  282. exch oget /CFM oget /AESV2 eq {
  283. (sAlT) concatstrings
  284. } if
  285. } {
  286. pop
  287. } ifelse
  288. } {
  289. pop
  290. } ifelse
  291. md5 0 FileKey length 5 add 2 index length .min getinterval
  292. } bind def
  293. % As .pdfrun, but decrypt strings with key <key>.
  294. /PDFScanRules_true << /PDFScanRules true >> def
  295. /PDFScanRules_null << /PDFScanRules null >> def
  296. /.decpdfrun % <file> <keystring> <opdict> .decpdfrun -
  297. { % Construct a procedure with the file, opdict and key bound into it.
  298. 2 index cvlit mark
  299. /PDFScanRules .getuserparam //null eq {
  300. //PDFScanRules_true { setuserparams } 0 get % force PDF scanning mode
  301. mark 7 4 roll
  302. } {
  303. mark 5 2 roll
  304. } ifelse
  305. { .pdftoken not { (%%EOF) cvn cvx } if
  306. dup xcheck
  307. { PDFDEBUG { dup == flush } if
  308. 3 -1 roll pop
  309. 2 copy .knownget
  310. { exch pop exch pop exec
  311. }
  312. { exch pop
  313. dup /true eq
  314. { pop //true
  315. }
  316. { dup /false eq
  317. { pop //false
  318. }
  319. { dup /null eq
  320. { pop //null
  321. }
  322. { ( **** Unknown operator: )
  323. exch =string cvs concatstrings (\n) concatstrings
  324. pdfformaterror
  325. }
  326. ifelse
  327. }
  328. ifelse
  329. }
  330. ifelse
  331. }
  332. ifelse
  333. }
  334. { exch pop PDFDEBUG { dup ==only ( ) print flush } if
  335. dup type /stringtype eq
  336. {
  337. % Check if we have encrypted strings R=4 allows for
  338. % selection of encryption on streams and strings
  339. Trailer /Encrypt oget % Get encryption dictionary
  340. dup /R oget 4 lt % only 4 has selectable
  341. { % R < 4 --> arc4 strings
  342. pop 1 index arc4decode % Decrypt string
  343. PDFDEBUG { (%Decrypted: ) print dup == flush } if
  344. } { % Else R = 4
  345. /StrF knownoget % Get StrF (if present)
  346. { % If StrF is present ...
  347. dup /Identity eq not % Check if StrF != Identity
  348. { /StdCF eq
  349. { Trailer /Encrypt oget /CF knownoget {
  350. /StdCF oget /CFM oget /AESV2 eq
  351. } {
  352. //false
  353. } ifelse { % Decrypt string
  354. 1 index aesdecode
  355. } {
  356. 1 index arc4decode
  357. } ifelse
  358. }
  359. { 1 index arc4decode }
  360. ifelse % If StrF != StdCF
  361. PDFDEBUG { (%Decrypted: ) print dup == flush } if
  362. }
  363. { pop }
  364. ifelse % If StrF != identity
  365. }
  366. if % If StrF is known
  367. }
  368. ifelse % Ifelse R < 4
  369. }
  370. if % If = stringtype
  371. exch pop
  372. }
  373. ifelse
  374. }
  375. aload pop .packtomark cvx
  376. { loop } 0 get 2 packedarray cvx
  377. { stopped } 0 get
  378. /PDFScanRules .getuserparam //null eq {
  379. //PDFScanRules_null { setuserparams } 0 get % reset PDF scannig mode if it was off
  380. } if
  381. /PDFsource PDFsource
  382. { store { stop } if } aload pop .packtomark cvx
  383. /PDFsource 3 -1 roll store exec
  384. } bind def
  385. currentdict /PDFScanRules_true undef
  386. currentdict /PDFScanRules_null undef
  387. % Run the code to resolve an object reference.
  388. /pdf_run_resolve
  389. { /FileKey where % Check if the file is encrypted
  390. { pop % File is encrypted
  391. 2 copy computeobjkey dup 4 1 roll
  392. PDFfile exch resolveopdict .decpdfrun
  393. dup dup dup 5 2 roll
  394. % stack: object object key object object
  395. { % Use loop to provide an exitable context.
  396. xcheck exch type /dicttype eq and % Check if executable dictionary
  397. not { % If object is not ...
  398. pop pop % ignore object
  399. exit % Exit 'loop' context
  400. } if % If not possible stream
  401. % Starting with PDF 1.4 (R = 3), there are some extra features
  402. % which control encryption of streams. The EncryptMetadata entry
  403. % in the Encrypt dict controls the encryption of metadata streams.
  404. Trailer /Encrypt oget % Get encryption dictionary
  405. dup /R oget dup 3 lt % Only PDF 1.4 and higher has options
  406. { % R < 3 --> all streams encrypted
  407. pop pop /StreamKey exch put % Insert StreamKey in dictionary
  408. exit % Exit 'loop' context
  409. } if
  410. % Check EncryptMeta. stack: object object key Encrypt R
  411. exch dup /EncryptMetadata knownoget % Get EncryptMetadata (if present)
  412. not { true } if % If not present default = true
  413. not % Check if EncryptMetadata = false
  414. { % if false we need to check the stream type
  415. 3 index /Type knownoget % Get stream type (if present)
  416. not { //null } if % If type not present use fake name
  417. /Metadata eq % Check if the type is Metadata
  418. { pop pop pop pop % Type == Metadata --> no encryption
  419. exit % Exit 'loop' context
  420. } if
  421. } if
  422. % PDF 1.5 encryption (R == 4) has selectable encryption handlers. If
  423. % this is not PDF 1.5 encryption (R < 4) then we are done checking and
  424. % we need to decrypt the stream. stack: object object key R Encrypt
  425. exch 4 lt % Check for less than PDF 1.5
  426. { pop /StreamKey exch put % Insert StreamKey in dictionary
  427. exit % Exit 'loop' context
  428. } if
  429. % Check if the stream encryption handler (StmF) == Identity.
  430. PDFDEBUG {
  431. Trailer /Encrypt oget /CF knownoget {
  432. /StdCF oget /CFM oget
  433. (Encrypt StmF is StdCF with CFM ) print =
  434. } if
  435. } if
  436. /StmF knownoget % Get StmF (if present)
  437. not { /Identity } if % If StmF not present default = Identity
  438. /Identity eq % Check if StmF == Identity
  439. { pop pop % Identity --> no encryption
  440. exit % Exit 'loop' context
  441. } if
  442. % If we get here then we need to decrypt the stream.
  443. /StreamKey exch put % Insert StreamKey into dictionary
  444. exit % Exit 'loop' context, never loop
  445. } loop % End of loop exitable context
  446. } { % Else file is not encrypted
  447. PDFfile resolveopdict .pdfrun
  448. } ifelse % Ifelse encrypted
  449. } bind def
  450. % Prefix a decryption filter to a stream if needed.
  451. % Stack: readdata? dict parms file/string filternames
  452. % (both before and after).
  453. /pdf_decrypt_stream
  454. { 3 index /StreamKey known % Check if the file is encrypted
  455. {
  456. exch
  457. % Stack: readdata? dict parms filternames file/string
  458. 3 index /StreamKey get
  459. Trailer /Encrypt oget
  460. dup /StmF knownoget
  461. { % stack: key Encrypt StmF
  462. exch /CF knownoget {
  463. exch oget /CFM oget % stack: key StmF-CFM
  464. /AESV2 eq
  465. } { pop //false } ifelse
  466. { aesdecodefilter } % install the requested filter
  467. { arc4decodefilter }
  468. ifelse
  469. }
  470. { pop arc4decodefilter } % fallback for no StmF
  471. ifelse
  472. exch
  473. } if
  474. } bind def
  475. end % pdfdict
  476. .setglobal