shithub: riscv

Download patch

ref: 0b016a77e42dfc33df4d46bdd4c817fa3ed5ac90
parent: 13508a99a8955b98609ec7dcbf5f57069179a4de
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Feb 19 19:21:45 EST 2015

gs: backport aes support for pdf-1.6

--- a/sys/lib/ghostscript/pdf_base.ps
+++ b/sys/lib/ghostscript/pdf_base.ps
@@ -641,7 +641,7 @@
 	      	% of the objects in sthe stream and place them into the Objects
 	      	% array.
 		% Stack: savepos objpos obj# objectstream#
-	resolveobjectstream
+        resolveobjectstream
         resolved? {		% If object has already been resolved ...
 	  exch pop		% Remove object pos from stack.
 	} {
--- a/sys/lib/ghostscript/pdf_sec.ps
+++ b/sys/lib/ghostscript/pdf_sec.ps
@@ -39,6 +39,12 @@
   currentdict end /ArcfourDecode filter
 } bind def
 
+/aesdecodefilter {
+  1 dict begin
+  /Key exch def
+  currentdict end /AESDecode filter
+} bind def
+
 % <ciphertext> <key> arc4decode <plaintext>
 /arc4decode {
   %(key: ) print dup == (ct: ) print 1 index ==
@@ -49,6 +55,22 @@
   } ifelse
 } bind def
 
+/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 def
+
 /md5 {
   16 string dup /MD5Encode filter dup 4 3 roll writestring closefile
 } bind def
@@ -294,18 +316,38 @@
 % put into a stream dictionary).
 /computeobjkey	% <object#> <generation#> computeobjkey <keystring>
 {
-  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 md5 0 FileKey length 5 add 2 index length .min getinterval
+  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 {
+        exch /CF knownoget {
+          exch oget /CFM oget /AESV2 eq {
+            (sAlT) concatstrings
+          } if
+        } {
+          pop
+        } ifelse
+      } {
+        pop
+      } ifelse
+    md5 0 FileKey length 5 add 2 index length .min getinterval
+  } ifelse
 } bind def
 
 % As .pdfrun, but decrypt strings with key <key>.
@@ -351,17 +393,31 @@
              {				% R < 4 --> encrypted strings
 	       pop 1 index arc4decode	% Decrypt string
 	       PDFDEBUG { (%Decrypted: ) print dup == flush } if
-             } {			% Else R = 4
-	       /StrF knownoget		% Get StrF (if present)
-	        {			% If StrF is present ...
-		  /Identity eq not	% Check if StrF != Identity
-	  	   { 1 index arc4decode	% Decrypt string
-		     PDFDEBUG { (%Decrypted: ) print dup == flush } if
-		   }
-		  if			% If StrF != identity
-		}
-	       if			% If StrF is known
-      	     }
+             } {			% Else R &gt;= 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
 	  }
 	 if				% If  = stringtype
@@ -384,7 +440,7 @@
     2 copy computeobjkey dup 4 1 roll
     PDFfile exch resolveopdict .decpdfrun
     dup dup dup 5 2 roll
-	% stack: object object key object object
+        % 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 ...
@@ -391,42 +447,48 @@
         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.
+        % 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
+      {					% R &lt; 3 --&gt; all streams encrypted
         pop pop /StreamKey exch put	% Insert StreamKey in dictionary
-	exit				% Exit 'loop' context
+        exit				% Exit 'loop' context
       } if
-	% Check EncryptMeta.  stack:  object object key Encrypt R
+        % 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 { //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 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 --&gt; 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
+        % PDF 1.5 encryption (R == 4) has selectable encryption handlers.  If
+        % this is not PDF 1.5 encryption (R &lt; 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
+        exit				% Exit 'loop' context
       } if
-	% Check if the stream encryption handler (StmF) == Identity.
+        % 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
+      /Identity eq			% Check if StmF == Identity
+      { pop pop				% Identity --&gt; no encryption
+        exit				% Exit 'loop' context
       } if
-      	% If we get here then we need to decrypt the stream.
+        % 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
@@ -441,16 +503,22 @@
 /pdf_decrypt_stream
  { 3 index /StreamKey known	% Check if the file is encrypted
    {
-      exch 
-	% Stack: readdata? dict parms filternames file/string
-      3 index /Length oget
-      dup 0 eq {
-	% Handle Length=0 case specially to avoid SubFileDecode semantics
-        pop pop ()
-      } {
-        () /SubFileDecode filter
-      } ifelse
-      3 index /StreamKey get arc4decodefilter
+      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 def
--- a/sys/src/cmd/gs/lib/pdf_base.ps
+++ b/sys/src/cmd/gs/lib/pdf_base.ps
@@ -412,11 +412,10 @@
 	(   **** Warning: wrong generation: )
       } ifelse
       2 index =string cvs concatstrings ( ) concatstrings	% put obj #
-      exch =string cvs concatstrings ( R\n) concatstrings	% put gen #
+      1 index =string cvs concatstrings ( R\n) concatstrings	% put gen #
       pdfformaterror			% Output warning message
-    } {					% Else QUIET ...
-      pop				% Pop generation umber
-    } ifelse false			% Return false if gen # not match
+    } if
+    0 eq
   } ifelse
 } bind def
 /R {		% <object#> <generation#> R <object>
@@ -642,7 +641,7 @@
 	      	% of the objects in sthe stream and place them into the Objects
 	      	% array.
 		% Stack: savepos objpos obj# objectstream#
-	resolveobjectstream
+        resolveobjectstream
         resolved? {		% If object has already been resolved ...
 	  exch pop		% Remove object pos from stack.
 	} {
--- a/sys/src/cmd/gs/lib/pdf_main.ps
+++ b/sys/src/cmd/gs/lib/pdf_main.ps
@@ -25,6 +25,8 @@
 % Patch in an obsolete variable used by some third-party software.
 /#? false def
 
+/NoVerifyXref true def
+
 % Test whether the current output device handles pdfmark.
 /.writepdfmarkdict 1 dict dup /pdfmark null put readonly def
 /.writepdfmarks {	% - .writepdfmarks <bool>
--- a/sys/src/cmd/gs/lib/pdf_sec.ps
+++ b/sys/src/cmd/gs/lib/pdf_sec.ps
@@ -39,6 +39,12 @@
   currentdict end /ArcfourDecode filter
 } bind def
 
+/aesdecodefilter {
+  1 dict begin
+  /Key exch def
+  currentdict end /AESDecode filter
+} bind def
+
 % <ciphertext> <key> arc4decode <plaintext>
 /arc4decode {
   %(key: ) print dup == (ct: ) print 1 index ==
@@ -49,6 +55,22 @@
   } ifelse
 } bind def
 
+/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 def
+
 /md5 {
   16 string dup /MD5Encode filter dup 4 3 roll writestring closefile
 } bind def
@@ -294,18 +316,38 @@
 % put into a stream dictionary).
 /computeobjkey	% <object#> <generation#> computeobjkey <keystring>
 {
-  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 md5 0 FileKey length 5 add 2 index length .min getinterval
+  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 {
+        exch /CF knownoget {
+          exch oget /CFM oget /AESV2 eq {
+            (sAlT) concatstrings
+          } if
+        } {
+          pop
+        } ifelse
+      } {
+        pop
+      } ifelse
+    md5 0 FileKey length 5 add 2 index length .min getinterval
+  } ifelse
 } bind def
 
 % As .pdfrun, but decrypt strings with key <key>.
@@ -351,17 +393,31 @@
              {				% R < 4 --> encrypted strings
 	       pop 1 index arc4decode	% Decrypt string
 	       PDFDEBUG { (%Decrypted: ) print dup == flush } if
-             } {			% Else R = 4
-	       /StrF knownoget		% Get StrF (if present)
-	        {			% If StrF is present ...
-		  /Identity eq not	% Check if StrF != Identity
-	  	   { 1 index arc4decode	% Decrypt string
-		     PDFDEBUG { (%Decrypted: ) print dup == flush } if
-		   }
-		  if			% If StrF != identity
-		}
-	       if			% If StrF is known
-      	     }
+             } {			% Else R &gt;= 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
 	  }
 	 if				% If  = stringtype
@@ -384,7 +440,7 @@
     2 copy computeobjkey dup 4 1 roll
     PDFfile exch resolveopdict .decpdfrun
     dup dup dup 5 2 roll
-	% stack: object object key object object
+        % 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 ...
@@ -391,42 +447,48 @@
         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.
+        % 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
+      {					% R &lt; 3 --&gt; all streams encrypted
         pop pop /StreamKey exch put	% Insert StreamKey in dictionary
-	exit				% Exit 'loop' context
+        exit				% Exit 'loop' context
       } if
-	% Check EncryptMeta.  stack:  object object key Encrypt R
+        % 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 { //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 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 --&gt; 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
+        % PDF 1.5 encryption (R == 4) has selectable encryption handlers.  If
+        % this is not PDF 1.5 encryption (R &lt; 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
+        exit				% Exit 'loop' context
       } if
-	% Check if the stream encryption handler (StmF) == Identity.
+        % 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
+      /Identity eq			% Check if StmF == Identity
+      { pop pop				% Identity --&gt; no encryption
+        exit				% Exit 'loop' context
       } if
-      	% If we get here then we need to decrypt the stream.
+        % 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
@@ -441,16 +503,22 @@
 /pdf_decrypt_stream
  { 3 index /StreamKey known	% Check if the file is encrypted
    {
-      exch 
-	% Stack: readdata? dict parms filternames file/string
-      3 index /Length oget
-      dup 0 eq {
-	% Handle Length=0 case specially to avoid SubFileDecode semantics
-        pop pop ()
-      } {
-        () /SubFileDecode filter
-      } ifelse
-      3 index /StreamKey get arc4decodefilter
+      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 def
--- a/sys/src/cmd/gs/mkfile
+++ b/sys/src/cmd/gs/mkfile
@@ -64,7 +64,8 @@
 TARG=gs
 OFILES=\
 	obj/gs.$O\
-	`{sed 's#^./obj/(.*)\.o .*#obj/\1.$O#' src/ld.tr >[2] /dev/null | sort}
+	`{sed 's#^./obj/(.*)\.o .*#obj/\1.$O#' src/ld.tr >[2] /dev/null | sort} \
+	/$objtype/lib/ape/libcrypto.a
 
 # The first driver is the default.
 DRIVERS=\
--- a/sys/src/cmd/gs/src/gconfig.h
+++ b/sys/src/cmd/gs/src/gconfig.h
@@ -287,6 +287,7 @@
 #ifdef oper_
 oper_(zfmd5_op_defs)
 oper_(zfarc4_op_defs)
+oper_(zfaes_op_defs)
 #endif
 #ifdef psfile_
 psfile_("gs_mgl_e.ps",11)
--- a/sys/src/cmd/gs/src/gconfxx.h
+++ b/sys/src/cmd/gs/src/gconfxx.h
@@ -287,6 +287,7 @@
 #ifdef oper_
 oper_(zfmd5_op_defs)
 oper_(zfarc4_op_defs)
+oper_(zfaes_op_defs)
 #endif
 #ifdef psfile_
 psfile_("gs_mgl_e.ps",11)
--- a/sys/src/cmd/gs/src/int.mak
+++ b/sys/src/cmd/gs/src/int.mak
@@ -1289,6 +1289,13 @@
 	$(ADDMOD) $(PSD)farc4 -include $(GLD)sarc4
 	$(ADDMOD) $(PSD)farc4 -oper zfarc4
 
+# AES cipher filter
+faes4_=$(PSOBJ)zfaes.$(OBJ)
+$(PSD)faes.dev : $(INT_MAK) $(ECHOGS_XE) $(faes_) $(GLD)saes.dev
+	$(SETMOD) $(PSD)faes $(faes_)
+	$(ADDMOD) $(PSD)faes -include $(GLD)saes
+	$(ADDMOD) $(PSD)faes -oper zfaes
+
 $(PSOBJ)zfarc4.$(OBJ) : $(PSSRC)zfarc4.c $(OP) $(memory__h)\
  $(gsstruct_h) $(ialloc_h) $(idict_h) $(ifilter_h)\
  $(sarc4_h) $(stream_h) $(strimpl_h)
--- a/sys/src/cmd/gs/src/ld.tr
+++ b/sys/src/cmd/gs/src/ld.tr
@@ -285,6 +285,8 @@
 ./obj/md5.o \
 ./obj/zfarc4.o \
 ./obj/sarc4.o \
+./obj/zfaes.o \
+./obj/saes.o \
 ./obj/zicc.o \
 ./obj/gsicc.o \
 ./obj/icc.o \
--- a/sys/src/cmd/gs/src/lib.mak
+++ b/sys/src/cmd/gs/src/lib.mak
@@ -475,6 +475,7 @@
 slzwx_h=$(GLSRC)slzwx.h
 smd5_h=$(GLSRC)smd5.h $(md5_h)
 sarc4_h=$(GLSRC)sarc4.h $(scommon_h)
+saes_h=$(GLSRC)saes.h $(scommon_h)
 sjbig2_h=$(GLSRC)sjbig2.h $(stdint__h) $(scommon_h)
 sjpx_h=$(GLSRC)sjpx.h $(scommon_h)
 spdiffx_h=$(GLSRC)spdiffx.h
@@ -1369,6 +1370,16 @@
 $(GLOBJ)sarc4.$(OBJ) : $(GLSRC)sarc4.c $(AK) $(memory__h)\
  $(gserror_h) $(gserrors_h) $(sarc4_h) $(strimpl_h)
 	$(GLCC) $(GLO_)sarc4.$(OBJ) $(C_) $(GLSRC)sarc4.c
+
+# -------------- AES cipher filter --------------- #
+
+saes_=$(GLOBJ)saes.$(OBJ)
+$(GLD)saes.dev : $(LIB_MAK) $(ECHOGS_XE) $(saes_)
+	$(SETMOD) $(GLD)saes $(saes_)
+
+$(GLOBJ)saes.$(OBJ) : $(GLSRC)saes.c $(AK) $(memory__h)\
+ $(gserror_h) $(gserrors_h) $(saes_h) $(strimpl_h)
+	$(GLCC) $(GLO_)saes.$(OBJ) $(C_) $(GLSRC)saes.c
 
 # ---------------- JBIG2 compression filter ---------------- #
 
--- /dev/null
+++ b/sys/src/cmd/gs/src/saes.c
@@ -1,0 +1,160 @@
+/* Copyright (C) 2001-2012 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.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
+   CA  94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+
+/* AES filter implementation */
+
+#include "memory_.h"
+#include "gserrors.h"
+#include "gserror.h"
+#include "strimpl.h"
+#include "saes.h"
+
+/* stream implementation */
+
+private_st_aes_state();	/* creates a gc object for our state,
+                           defined in saes.h */
+
+/* Store a key in our crypt context */
+int
+s_aes_set_key(stream_aes_state * state, const unsigned char *key,
+                  int keylength)
+{
+    if ( (keylength < 1) || (keylength > SAES_MAX_KEYLENGTH) )
+        return_error(gs_error_rangecheck);
+    if (key == NULL)
+        return_error(gs_error_invalidaccess);
+
+    /* we can't set the key here because the interpreter's
+       filter implementation wants to duplicate our state
+       after the zfaes.c binding calls us. So stash it now
+       and handle it in our process method. */
+    memcpy(state->key, key, keylength);
+    state->keylength = keylength;
+
+    /* return successfully */
+    return 0;
+}
+
+/* Specify whether the plaintext stream uses RFC 1423-style padding
+ * (allowing it to be an arbitrary length), or is unpadded (and must
+ * therefore be a multiple of 16 bytes long). */
+void
+s_aes_set_padding(stream_aes_state *state, int use_padding)
+{
+    state->use_padding = use_padding;
+}
+
+/* initialize our state object. */
+static int
+s_aes_init(stream_state *ss)
+{
+    stream_aes_state *const state = (stream_aes_state *) ss;
+
+    /* clear the flags so we know we're at the start of a stream */
+    state->initialized = 0;
+    memset(&state->aes, 0, sizeof(state->aes));
+
+    return 0;
+}
+
+/* release our private storage */
+static void
+s_aes_release(stream_state *)
+{
+}
+
+/* (de)crypt a section of text--the procedure is the same
+ * in each direction. see strimpl.h for return codes.
+ */
+static int
+s_aes_process(stream_state * ss, stream_cursor_read * pr,
+                  stream_cursor_write * pw, bool last)
+{
+    stream_aes_state *const state = (stream_aes_state *) ss;
+    const unsigned char *limit;
+    const long in_size = pr->limit - pr->ptr;
+    const long out_size = pw->limit - pw->ptr;
+    unsigned char temp[16];
+    int status = 0;
+
+    /* figure out if we're going to run out of space */
+    if (in_size > out_size) {
+        limit = pr->ptr + out_size;
+        status = 1; /* need more output space */
+    } else {
+        limit = pr->limit;
+        status = last ? EOFC : 0; /* need more input */
+    }
+    if (state->keylength < 1 || state->keylength > SAES_MAX_KEYLENGTH)
+        return ERRC;
+    if (!state->initialized) {
+        memset(&state->aes, 0, sizeof(state->aes));
+        AES_set_decrypt_key(state->key, state->keylength*8, &state->aes);
+
+        /* read the initialization vector from the first 16 bytes */
+        if (in_size < 16) return 0; /* get more data */
+        memcpy(state->iv, pr->ptr + 1, 16);
+        state->initialized = 1;
+        pr->ptr += 16;
+    }
+
+    /* decrypt available blocks */
+    while (pr->ptr + 16 <= limit) {
+      AES_cbc_encrypt(pr->ptr + 1, temp, 16, &state->aes, state->iv, AES_DECRYPT);
+      pr->ptr += 16;
+      if (last && pr->ptr == pr->limit) {
+        /* we're on the last block; unpad if necessary */
+        int pad;
+
+        if (state->use_padding) {
+          /* we are using RFC 1423-style padding, so the last byte of the
+             plaintext gives the number of bytes to discard */
+          pad = temp[15];
+          if (pad < 1 || pad > 16) {
+            /* Bug 692343 - don't error here, just warn. Take padding to be
+             * zero. This may give us a stream that's too long - preferable
+             * to the alternatives. */
+            pad = 0;
+          }
+        } else {
+          /* not using padding */
+          pad = 0;
+        }
+
+        memcpy(pw->ptr + 1, temp, 16 - pad);
+        pw->ptr +=  16 - pad;
+        return EOFC;
+      }
+      memcpy(pw->ptr + 1, temp, 16);
+      pw->ptr += 16;
+    }
+
+    /* if we got to the end of the file without triggering the padding
+       check, the input must not have been a multiple of 16 bytes long.
+       complain. */
+    if (status == EOFC)
+      return 0;
+
+    return status;
+}
+
+/* stream template */
+const stream_template s_aes_template = {
+    &st_aes_state, s_aes_init,
+    s_aes_process, 16, 16,
+    s_aes_release
+};
--- /dev/null
+++ b/sys/src/cmd/gs/src/saes.h
@@ -1,0 +1,63 @@
+/* Copyright (C) 2001-2012 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.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
+   CA  94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* Stream wrapper for the AES cypher implementation */
+/* Requires scommon.h; strimpl.h if any templates are referenced */
+
+#ifndef saes_INCLUDED
+#  define saes_INCLUDED
+
+#include "scommon.h"
+#include <openssl/aes.h>
+
+/* maximum supported key length in bytes */
+#define SAES_MAX_KEYLENGTH 32
+
+/* AES is a symmetric block cipher so we share the stream states.
+   The internal cypher state is all held in the ctx pointer */
+struct stream_aes_state_s
+{
+    stream_state_common;	/* a define from scommon.h */
+    unsigned char key[SAES_MAX_KEYLENGTH];
+    unsigned int keylength;
+    unsigned char iv[16];	/* CBC initialization vector */
+    int initialized;		/* whether we're set up */
+    int use_padding;		/* are we using RFC 1423-style padding? */
+    AES_KEY aes;
+};
+
+#ifndef stream_aes_state_DEFINED
+#define stream_aes_state_DEFINED
+typedef struct stream_aes_state_s stream_aes_state;
+#endif
+
+int s_aes_set_key(stream_aes_state * state,
+                        const unsigned char *key, int keylength);
+void s_aes_set_padding(stream_aes_state *state, int use_padding);
+
+/* state declaration macro;
+   should be updated for the aes_context finalization */
+#define private_st_aes_state()	\
+  gs_private_st_simple(st_aes_state, stream_aes_state, "aes filter state")
+
+extern const stream_template s_aes_template;
+
+/* (de)crypt a section of text in a buffer -- the procedure is the same
+ * in each direction. see strimpl.h for return codes.
+ */
+int s_aes_process_buffer(stream_aes_state *ss, byte *buf, int buf_size);
+
+#endif /* saes_INCLUDED */
--- /dev/null
+++ b/sys/src/cmd/gs/src/zfaes.c
@@ -1,0 +1,62 @@
+/* Copyright (C) 2001 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.
+  
+  For more information about licensing, please refer to
+  http://www.ghostscript.com/licensing/. For information on
+  commercial licensing, go to http://www.artifex.com/licensing/ or
+  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
+  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
+*/
+
+/* this is the ps interpreter interface to the aescbc cipher filter
+   used in PDF decryption. */
+
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gsstruct.h"
+#include "ialloc.h"
+#include "idict.h"
+#include "stream.h"
+#include "strimpl.h"
+#include "ifilter.h"
+#include "saes.h"
+
+/* <source> <dict> aes/filter <file> */
+
+private int
+z_aes_d(i_ctx_t * i_ctx_p)
+{
+    os_ptr op = osp;		/* i_ctx_p->op_stack.stack.p defined in osstack.h */
+    ref *sop = NULL;
+    stream_aes_state state;
+
+    /* extract the key from the parameter dictionary */
+    check_type(*op, t_dictionary);
+    check_dict_read(*op);
+    if (dict_find_string(op, "Key", &sop) <= 0)
+	return_error(e_rangecheck);
+
+    s_aes_set_key(&state, sop->value.const_bytes, r_size(sop));
+
+    /* we pass npop=0, since we've no arguments left to consume */
+    /* we pass 0 instead of the usual rspace(sop) will allocate storage for 
+       filter state from the same memory pool as the stream it's coding. this
+       causes no trouble because we maintain no pointers */
+    return filter_read(i_ctx_p, 0, &s_aes_template,
+		       (stream_state *) & state, 0);
+}
+
+/* match the above routines to their postscript filter names
+   this is how our 'private' routines get called externally */
+const op_def zfaes_op_defs[] = {
+    op_def_begin_filter(),
+    {"2AESDecode", z_aes_d},
+    op_def_end(0)
+};
--