pdf_sec.ps 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. % Copyright (C) 1996, 1997 Geoffrey Keating.
  2. % This file may be freely distributed with or without modifications,
  3. % so long as proper attribution is given and copyright notices are
  4. % not removed.
  5. % pdf_sec.ps (version 1.0.3)
  6. % Implementation of security hooks for PDF reader.
  7. % This file contains the procedures that have to take encryption into
  8. % account when reading a PDF file. It replaces the stub version of this
  9. % file that is shipped with GhostScript. It requires GhostScript version 4.02
  10. % or later.
  11. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  12. .currentglobal true .setglobal
  13. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  14. pdfdict begin
  15. % Older ghostscript versions do not have .pdftoken, so we use 'token' instead.
  16. /.pdftoken where { pop } { /.pdftoken /token load def } ifelse
  17. % An implementation of an algorithm compatible with the RSA Data Security
  18. % Inc. RC4 stream encryption algorithm.
  19. % <string> rc4setkey <dict>
  20. /rc4setkey
  21. {
  22. 6 dict begin
  23. /k exch def
  24. /a 256 string def
  25. 0 1 255 { a exch dup put } for
  26. /l k length def
  27. /j 0 def
  28. 0 1 255
  29. {
  30. /i exch def
  31. /j a i get k i l mod get add j add 255 and def
  32. a i a j get a j a i get put put
  33. } for
  34. 3 dict dup begin
  35. /a a def
  36. /x 0 def
  37. /y 0 def
  38. end
  39. end
  40. } bind def
  41. % <rc4key> <string> rc4 <string> <rc4key>
  42. /rc4
  43. {
  44. 1 index begin
  45. dup dup length 1 sub 0 exch 1 exch
  46. {
  47. /x x 1 add 255 and def
  48. /y a x get y add 255 and def
  49. a x a y get a y a x get put put
  50. % stack: string string index
  51. 2 copy get
  52. a dup x get a y get add 255 and get
  53. xor put dup
  54. } for
  55. pop
  56. end
  57. } bind def
  58. % take a stream and rc4 decrypt it.
  59. % <stream> <key> rc4decodefilter <stream>
  60. /rc4decodefilter {
  61. currentglobal exch true setglobal
  62. dup length string copy rc4setkey
  63. exch setglobal
  64. exch 512 string
  65. % stack: <key> <stream> <string>
  66. { readstring pop rc4 exch pop } aload pop
  67. 8 array astore cvx 0 () /SubFileDecode filter
  68. } bind def
  69. % MD5 derived from RFC 1321, "The MD5 Message-Digest Algorithm",
  70. % R. Rivest, MIT, RSADSI; implemented in PostScript by Geoffrey Keating.
  71. % We construct the MD5 transform by a sort of inline expansion.
  72. % this takes up quite a bit of memory (around 17k), but gives a
  73. % factor-of-two speed increase.
  74. % This also allows us to take advantage of interpreters with 64-bit
  75. % wide integers.
  76. % This will not run on interpreters with 16-bit wide integers, if such
  77. % things exist.
  78. 20 dict begin
  79. /T [
  80. 16#d76aa478 16#e8c7b756 16#242070db 16#c1bdceee
  81. 16#f57c0faf 16#4787c62a 16#a8304613 16#fd469501
  82. 16#698098d8 16#8b44f7af 16#ffff5bb1 16#895cd7be
  83. 16#6b901122 16#fd987193 16#a679438e 16#49b40821
  84. 16#f61e2562 16#c040b340 16#265e5a51 16#e9b6c7aa
  85. 16#d62f105d 16#02441453 16#d8a1e681 16#e7d3fbc8
  86. 16#21e1cde6 16#c33707d6 16#f4d50d87 16#455a14ed
  87. 16#a9e3e905 16#fcefa3f8 16#676f02d9 16#8d2a4c8a
  88. 16#fffa3942 16#8771f681 16#6d9d6122 16#fde5380c
  89. 16#a4beea44 16#4bdecfa9 16#f6bb4b60 16#bebfbc70
  90. 16#289b7ec6 16#eaa127fa 16#d4ef3085 16#04881d05
  91. 16#d9d4d039 16#e6db99e5 16#1fa27cf8 16#c4ac5665
  92. 16#f4292244 16#432aff97 16#ab9423a7 16#fc93a039
  93. 16#655b59c3 16#8f0ccc92 16#ffeff47d 16#85845dd1
  94. 16#6fa87e4f 16#fe2ce6e0 16#a3014314 16#4e0811a1
  95. 16#f7537e82 16#bd3af235 16#2ad7d2bb 16#eb86d391
  96. ] def
  97. /F [
  98. { c d /xor b /and d /xor } { b c /xor d /and c /xor }
  99. { b c /xor d /xor } { d /not b /or c /xor }
  100. ] def
  101. /R [
  102. 16#0007 16#010c 16#0211 16#0316 16#0407 16#050c 16#0611 16#0716
  103. 16#0807 16#090c 16#0a11 16#0b16 16#0c07 16#0d0c 16#0e11 16#0f16
  104. 16#0105 16#0609 16#0b0e 16#0014 16#0505 16#0a09 16#0f0e 16#0414
  105. 16#0905 16#0e09 16#030e 16#0814 16#0d05 16#0209 16#070e 16#0c14
  106. 16#0504 16#080b 16#0b10 16#0e17 16#0104 16#040b 16#0710 16#0a17
  107. 16#0d04 16#000b 16#0310 16#0617 16#0904 16#0c0b 16#0f10 16#0217
  108. 16#0006 16#070a 16#0e0f 16#0515 16#0c06 16#030a 16#0a0f 16#0115
  109. 16#0806 16#0f0a 16#060f 16#0d15 16#0406 16#0b0a 16#020f 16#0915
  110. ] def
  111. /W 1 31 bitshift 0 gt def
  112. /A W { /add } { /md5add } ifelse def
  113. /t W { 1744 } { 1616 } ifelse array def
  114. /C 0 def
  115. 0 1 63 {
  116. /i exch def
  117. /r R i get def
  118. /a/b/c/d 4 i 3 and roll [ /d/c/b/a ] { exch def } forall
  119. t C [
  120. a F i -4 bitshift get exec
  121. a A /x r -8 bitshift /get A T i get A
  122. W { 1 32 bitshift 1 sub /and } if
  123. /dup r 31 and /bitshift /exch r 31 and 32 sub /bitshift /or
  124. b A
  125. /def
  126. ] dup length C add /C exch def putinterval
  127. } for
  128. 1 1 C 1 sub {
  129. dup 1 sub t exch get /def cvx eq
  130. {pop}
  131. {t exch 2 copy get cvx put}
  132. ifelse
  133. } for
  134. % If we could put t into a _packed_ array, its memory requirements
  135. % would go from about 13k to about 4k. Unfortunately, we'd need around
  136. % 1600 stack positions, around 3 times what we can expect to have
  137. % available---and if that kind of memory is available, we don't really
  138. % need to pack t. Sigh.
  139. % In fact, it's worse than that. You can't even determine what t will
  140. % be and write it in directly (something like
  141. % { /a c d xor b and d xor a md5add x 0 get md5add -680876936 md5add dup 7
  142. % bitshift exch -25 bitshift or b md5add def /d b c xor a ...
  143. % ) because the scanner uses the operand stack to accumulate procedures.
  144. % So the only way to have md5transform as a single procedure is the above
  145. % trick.
  146. W /md5transform t end cvx bind def
  147. % Unfortunately, PostScript & its imitators convert large
  148. % integers to floating-point. Worse, the fp representation probably
  149. % won't have 32 significant bits.
  150. % This procedure accounts for about 35% of the total time on 32-bit
  151. % machines.
  152. not {
  153. /md5add {
  154. 2 copy xor 0 lt
  155. % if one is positive and one is negative, can't overflow
  156. { add }
  157. % if both are positive or negative
  158. { 16#80000000 xor add 16#80000000 xor }
  159. % same as subtracting (or adding) 2^31 and then subtracting (or
  160. % adding) it back.
  161. ifelse
  162. } bind def
  163. } {
  164. /md5add {
  165. add 16#0FFFFFFFF and
  166. } bind def
  167. } ifelse
  168. /md5 {
  169. 20 dict begin
  170. % initialise a,b,c,d,x
  171. /a 16#67452301 def
  172. /b 16#efcdab89 def
  173. /c 16#98badcfe def
  174. /d 16#10325476 def
  175. /x 16 array def
  176. % parameters
  177. /origs exch def
  178. /oslen origs length def
  179. % pad string to multiple of 512 bits
  180. /s oslen 72 add 64 idiv 64 mul dup /slen exch def string def
  181. s 0 origs putinterval
  182. s oslen 16#80 put
  183. s slen 8 sub oslen 31 and 3 bitshift put
  184. s slen 7 sub oslen -5 bitshift 255 and put
  185. s slen 6 sub oslen -13 bitshift 255 and put
  186. 0 64 slen 64 sub {
  187. dup 1 exch 63 add { s exch get } for
  188. 15 -1 0 { x exch 6 2 roll 3 { 8 bitshift or } repeat put } for
  189. a b c d
  190. md5transform
  191. d md5add /d exch def
  192. c md5add /c exch def
  193. b md5add /b exch def
  194. a md5add /a exch def
  195. } for
  196. 16 string
  197. [ [ a b c d ] { 3 { dup -8 bitshift } repeat } forall ]
  198. 0 1 15 {
  199. 3 copy dup 3 1 roll get 255 and put pop
  200. } for
  201. pop
  202. end
  203. } bind def
  204. % Pad a key out to 32 bytes.
  205. /pdf_pad_key % <key> pdf_pad_key <padded key>
  206. { dup length 32 gt { 0 32 getinterval } if
  207. <28bf4e5e4e758a41 64004e56fffa0108
  208. 2e2e00b6d0683e80 2f0ca9fe6453697a>
  209. 0 32 3 index length sub getinterval
  210. concatstrings
  211. } bind def
  212. % Try a user key for a PDF file.
  213. /pdf_try_key % <key> pdf_try_key <filekey> true
  214. % <key> pdf_try_key false
  215. { Trailer /Encrypt oget
  216. dup /O oget exch
  217. /P oget 4 string exch
  218. 2 copy 255 and 0 exch put
  219. 2 copy -8 bitshift 255 and 1 exch put
  220. 2 copy -16 bitshift 255 and 2 exch put
  221. 2 copy -24 bitshift 255 and 3 exch put pop
  222. Trailer /ID oget 0 oget
  223. 3 { concatstrings } repeat
  224. md5 0 5 getinterval
  225. dup
  226. Trailer /Encrypt oget /U oget dup length string copy exch
  227. rc4setkey exch rc4 exch pop
  228. <28bf4e5e4e758a41 64004e56fffa0108
  229. 2e2e00b6d0683e80 2f0ca9fe6453697a> eq
  230. dup not { exch pop } if
  231. } bind def
  232. % Process the encryption information in the Trailer.
  233. /pdf_process_Encrypt
  234. { Trailer /Encrypt oget
  235. /Filter oget /Standard eq not
  236. { (****This file uses an unknown security handler.\n) print flush
  237. /pdf_process_Encrypt cvx /undefined signalerror
  238. }
  239. if
  240. () pdf_pad_key pdf_try_key
  241. { /FileKey exch def }
  242. { /PDFPassword where
  243. { PDFPassword pdf_pad_key pdf_try_key
  244. { true }
  245. { PDFPassword pdf_pad_key md5 0 5 getinterval rc4setkey
  246. Trailer /Encrypt oget /O oget dup length string copy
  247. rc4 exch pop
  248. pdf_try_key
  249. }
  250. ifelse
  251. { /FileKey exch def }
  252. { (****Password did not work.\n) print flush
  253. /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  254. }
  255. ifelse
  256. }
  257. { (****This file has a user password set.\n) print flush
  258. /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  259. }
  260. ifelse
  261. }
  262. ifelse
  263. Trailer /Encrypt oget /P oget 4 and 0 eq #? and
  264. { (****This owner of this file has requested you do not print it.\n)
  265. print flush
  266. /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  267. }
  268. if
  269. } bind def
  270. % Calculate the key used to decrypt an object (to pass to .decpdfrun or
  271. % put into a stream dictionary).
  272. /computeobjkey % <object#> <generation#> computeobjkey <keystring>
  273. {
  274. exch
  275. 10 string
  276. dup 0 FileKey putinterval
  277. exch
  278. % stack: gen# string obj#
  279. 2 copy 255 and 5 exch put
  280. 2 copy -8 bitshift 255 and 6 exch put
  281. 2 copy -16 bitshift 255 and 7 exch put
  282. pop exch
  283. 2 copy 255 and 8 exch put
  284. 2 copy -8 bitshift 255 and 9 exch put
  285. pop md5 0 10 getinterval
  286. } bind def
  287. % As .pdfrun, but decrypt strings with key <key>.
  288. /.decpdfrun % <file> <keystring> <opdict> .decpdfrun -
  289. { % Construct a procedure with the file, opdict and key bound into it.
  290. 2 index cvlit mark mark 5 2 roll
  291. { .pdftoken not { (%%EOF) cvn cvx } if
  292. dup xcheck
  293. { DEBUG { dup == flush } if
  294. 3 -1 roll pop
  295. 2 copy .knownget
  296. { exch pop exch pop exec }
  297. { (%stderr) (w) file
  298. dup (****************Unknown operator: ) writestring
  299. dup 3 -1 roll .writecvs dup (\n) writestring flushfile
  300. pop
  301. }
  302. ifelse
  303. }
  304. { exch pop DEBUG { dup ==only ( ) print flush } if
  305. dup type /stringtype eq
  306. { exch rc4setkey exch rc4 }
  307. if
  308. exch pop
  309. }
  310. ifelse
  311. }
  312. aload pop .packtomark cvx
  313. /loop cvx 2 packedarray cvx
  314. { stopped /PDFsource } aload pop
  315. PDFsource
  316. { store { stop } if } aload pop .packtomark cvx
  317. /PDFsource 3 -1 roll store exec
  318. } bind def
  319. % Run the code to resolve an object reference.
  320. /pdf_run_resolve
  321. { /FileKey where
  322. { pop
  323. 2 copy computeobjkey dup 4 1 roll
  324. PDFfile exch resolveopdict .decpdfrun
  325. dup dup dup 5 2 roll
  326. % stack: object object key object object
  327. xcheck exch type /dicttype eq and
  328. { /StreamKey exch put }
  329. { pop pop }
  330. ifelse
  331. }
  332. { PDFfile resolveopdict .pdfrun }
  333. ifelse
  334. } bind def
  335. % Prefix a decryption filter to a stream if needed.
  336. % Stack: readdata? dict parms file/string filternames
  337. % (both before and after).
  338. /pdf_decrypt_stream
  339. { 3 index /StreamKey known
  340. {
  341. exch
  342. % Stack: readdata? dict parms filternames file/string
  343. 3 index /Length oget () /SubFileDecode filter
  344. 3 index /StreamKey get rc4decodefilter
  345. exch
  346. } if
  347. } bind def
  348. end % pdfdict
  349. .setglobal