gs: backport aes support for pdf-1.6
This commit is contained in:
parent
13508a99a8
commit
0b016a77e4
14 changed files with 564 additions and 119 deletions
|
@ -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,6 +316,11 @@ def
|
|||
% put into a stream dictionary).
|
||||
/computeobjkey % <object#> <generation#> computeobjkey <keystring>
|
||||
{
|
||||
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
|
||||
|
@ -305,7 +332,22 @@ def
|
|||
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
|
||||
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,14 +393,28 @@ def
|
|||
{ % R < 4 --> encrypted strings
|
||||
pop 1 index arc4decode % Decrypt string
|
||||
PDFDEBUG { (%Decrypted: ) print dup == flush } if
|
||||
} { % Else R = 4
|
||||
} { % 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
|
||||
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
|
||||
}
|
||||
if % If StrF != identity
|
||||
{ 1 index arc4decode }
|
||||
ifelse % If StrF != StdCF
|
||||
PDFDEBUG { (%Decrypted: ) print dup //== exec flush } if
|
||||
}
|
||||
{ pop }
|
||||
ifelse % If StrF != identity
|
||||
}
|
||||
if % If StrF is known
|
||||
}
|
||||
|
@ -396,34 +452,40 @@ def
|
|||
% 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
|
||||
} if
|
||||
% 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
|
||||
{ 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
|
||||
% 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
|
||||
} 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
|
||||
/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
|
||||
{ pop pop % Identity --> no encryption
|
||||
exit % Exit 'loop' context
|
||||
} if
|
||||
% If we get here then we need to decrypt the stream.
|
||||
|
@ -443,14 +505,20 @@ def
|
|||
{
|
||||
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
|
||||
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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,6 +316,11 @@ def
|
|||
% put into a stream dictionary).
|
||||
/computeobjkey % <object#> <generation#> computeobjkey <keystring>
|
||||
{
|
||||
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
|
||||
|
@ -305,7 +332,22 @@ def
|
|||
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
|
||||
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,14 +393,28 @@ def
|
|||
{ % R < 4 --> encrypted strings
|
||||
pop 1 index arc4decode % Decrypt string
|
||||
PDFDEBUG { (%Decrypted: ) print dup == flush } if
|
||||
} { % Else R = 4
|
||||
} { % 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
|
||||
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
|
||||
}
|
||||
if % If StrF != identity
|
||||
{ 1 index arc4decode }
|
||||
ifelse % If StrF != StdCF
|
||||
PDFDEBUG { (%Decrypted: ) print dup //== exec flush } if
|
||||
}
|
||||
{ pop }
|
||||
ifelse % If StrF != identity
|
||||
}
|
||||
if % If StrF is known
|
||||
}
|
||||
|
@ -396,34 +452,40 @@ def
|
|||
% 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
|
||||
} if
|
||||
% 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
|
||||
{ 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
|
||||
% 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
|
||||
} 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
|
||||
/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
|
||||
{ pop pop % Identity --> no encryption
|
||||
exit % Exit 'loop' context
|
||||
} if
|
||||
% If we get here then we need to decrypt the stream.
|
||||
|
@ -443,14 +505,20 @@ def
|
|||
{
|
||||
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
|
||||
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
|
||||
|
|
|
@ -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=\
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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)
|
||||
|
|
160
sys/src/cmd/gs/src/saes.c
Normal file
160
sys/src/cmd/gs/src/saes.c
Normal file
|
@ -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
|
||||
};
|
63
sys/src/cmd/gs/src/saes.h
Normal file
63
sys/src/cmd/gs/src/saes.h
Normal file
|
@ -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 */
|
62
sys/src/cmd/gs/src/zfaes.c
Normal file
62
sys/src/cmd/gs/src/zfaes.c
Normal file
|
@ -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)
|
||||
};
|
Loading…
Reference in a new issue