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 >= 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 < 3 --> 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 --> 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 < 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 --> 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 >= 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 < 3 --> 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 --> 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 < 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 --> 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)
+};
--
⑨