diff --git a/sys/lib/ghostscript/pdf_base.ps b/sys/lib/ghostscript/pdf_base.ps index 438762cfb..f969b883a 100644 --- a/sys/lib/ghostscript/pdf_base.ps +++ b/sys/lib/ghostscript/pdf_base.ps @@ -641,7 +641,7 @@ pdfdict begin % 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. } { diff --git a/sys/lib/ghostscript/pdf_sec.ps b/sys/lib/ghostscript/pdf_sec.ps index d982a740e..7a4cb1a03 100644 --- a/sys/lib/ghostscript/pdf_sec.ps +++ b/sys/lib/ghostscript/pdf_sec.ps @@ -39,6 +39,12 @@ pdfdict begin currentdict end /ArcfourDecode filter } bind def +/aesdecodefilter { + 1 dict begin + /Key exch def + currentdict end /AESDecode filter +} bind def + % arc4decode /arc4decode { %(key: ) print dup == (ct: ) print 1 index == @@ -49,6 +55,22 @@ pdfdict begin } 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 @@ def % 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 @@ def { % 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,49 +440,55 @@ def 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 ... 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. + PDFDEBUG { + Trailer /Encrypt oget /CF knownoget { + /StdCF oget /CFM oget + (Encrypt StmF is StdCF with CFM ) print = + } if } if - % Check if the stream encryption handler (StmF) == Identity. /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 @@ def /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 diff --git a/sys/src/cmd/gs/lib/pdf_base.ps b/sys/src/cmd/gs/lib/pdf_base.ps index 710e15c79..f969b883a 100644 --- a/sys/src/cmd/gs/lib/pdf_base.ps +++ b/sys/src/cmd/gs/lib/pdf_base.ps @@ -412,11 +412,10 @@ pdfdict begin ( **** 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 @@ pdfdict begin % 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. } { diff --git a/sys/src/cmd/gs/lib/pdf_main.ps b/sys/src/cmd/gs/lib/pdf_main.ps index c4c352085..12ee8e6fc 100644 --- a/sys/src/cmd/gs/lib/pdf_main.ps +++ b/sys/src/cmd/gs/lib/pdf_main.ps @@ -25,6 +25,8 @@ pdfdict begin % 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> diff --git a/sys/src/cmd/gs/lib/pdf_sec.ps b/sys/src/cmd/gs/lib/pdf_sec.ps index d982a740e..7a4cb1a03 100644 --- a/sys/src/cmd/gs/lib/pdf_sec.ps +++ b/sys/src/cmd/gs/lib/pdf_sec.ps @@ -39,6 +39,12 @@ pdfdict begin 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 @@ pdfdict begin } 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 @@ def % 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 @@ def { % 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,49 +440,55 @@ def 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 ... 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. + PDFDEBUG { + Trailer /Encrypt oget /CF knownoget { + /StdCF oget /CFM oget + (Encrypt StmF is StdCF with CFM ) print = + } if } if - % Check if the stream encryption handler (StmF) == Identity. /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 @@ def /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 diff --git a/sys/src/cmd/gs/mkfile b/sys/src/cmd/gs/mkfile index 50f162bf4..2567b2ddb 100644 --- a/sys/src/cmd/gs/mkfile +++ b/sys/src/cmd/gs/mkfile @@ -64,7 +64,8 @@ BIN=/$objtype/bin 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=\ diff --git a/sys/src/cmd/gs/src/gconfig.h b/sys/src/cmd/gs/src/gconfig.h index 24375cdf6..b1f4ffa42 100644 --- a/sys/src/cmd/gs/src/gconfig.h +++ b/sys/src/cmd/gs/src/gconfig.h @@ -287,6 +287,7 @@ psfile_("gs_cff.ps",9) #ifdef oper_ oper_(zfmd5_op_defs) oper_(zfarc4_op_defs) +oper_(zfaes_op_defs) #endif #ifdef psfile_ psfile_("gs_mgl_e.ps",11) diff --git a/sys/src/cmd/gs/src/gconfxx.h b/sys/src/cmd/gs/src/gconfxx.h index 24375cdf6..b1f4ffa42 100644 --- a/sys/src/cmd/gs/src/gconfxx.h +++ b/sys/src/cmd/gs/src/gconfxx.h @@ -287,6 +287,7 @@ psfile_("gs_cff.ps",9) #ifdef oper_ oper_(zfmd5_op_defs) oper_(zfarc4_op_defs) +oper_(zfaes_op_defs) #endif #ifdef psfile_ psfile_("gs_mgl_e.ps",11) diff --git a/sys/src/cmd/gs/src/int.mak b/sys/src/cmd/gs/src/int.mak index 6074373ef..b63d2fb29 100644 --- a/sys/src/cmd/gs/src/int.mak +++ b/sys/src/cmd/gs/src/int.mak @@ -1289,6 +1289,13 @@ $(PSD)farc4.dev : $(INT_MAK) $(ECHOGS_XE) $(farc4_) $(GLD)sarc4.dev $(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) diff --git a/sys/src/cmd/gs/src/ld.tr b/sys/src/cmd/gs/src/ld.tr index e5ad63eba..c738fb38c 100644 --- 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 \ diff --git a/sys/src/cmd/gs/src/lib.mak b/sys/src/cmd/gs/src/lib.mak index cecdccce7..ac5a8516c 100644 --- a/sys/src/cmd/gs/src/lib.mak +++ b/sys/src/cmd/gs/src/lib.mak @@ -475,6 +475,7 @@ sjpeg_h=$(GLSRC)sjpeg.h 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 @@ -1370,6 +1371,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 ---------------- # sjbig2_=$(GLOBJ)sjbig2.$(OBJ) diff --git a/sys/src/cmd/gs/src/saes.c b/sys/src/cmd/gs/src/saes.c new file mode 100644 index 000000000..14d60dd77 --- /dev/null +++ b/sys/src/cmd/gs/src/saes.c @@ -0,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 +}; diff --git a/sys/src/cmd/gs/src/saes.h b/sys/src/cmd/gs/src/saes.h new file mode 100644 index 000000000..a11695145 --- /dev/null +++ b/sys/src/cmd/gs/src/saes.h @@ -0,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 */ diff --git a/sys/src/cmd/gs/src/zfaes.c b/sys/src/cmd/gs/src/zfaes.c new file mode 100644 index 000000000..010c9d574 --- /dev/null +++ b/sys/src/cmd/gs/src/zfaes.c @@ -0,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) +};