[gs-cvs] rev 9117 - trunk/gs/base

giles at ghostscript.com giles at ghostscript.com
Wed Sep 24 04:07:44 PDT 2008


Author: giles
Date: 2008-09-24 04:07:43 -0700 (Wed, 24 Sep 2008)
New Revision: 9117

Added:
   trunk/gs/base/saes.c
   trunk/gs/base/saes.h
Modified:
   trunk/gs/base/lib.mak
Log:
Initial support for aes decryption streams.

Details:

This adds support for compiling the xyssl aes implementation added
in r8870, and a stream library wrapper which calls it.

Note that while an s_aes_set_key() procedure is provided to set a
key in an allocated stream state, it merely stores the key, and the
actual allocation of the aes_context structure and initialization
with the key happen the first time the stream's process() method is
called.

This is because a typical call to filter_read() in the interpreter
binding will end up memcpy()ing this to its own separately allocated
stream state. This preserves any static initialization performed by
the caller, such as passing in the key, but the xyssl aes_context
structure includes an internal pointer, and this is not updated when
the state is copied.

The internal pointer provides an indirect reference to support optional
storage of the sbox in secure memory. We're not using this feature, so
we could remove it, or update the pointer ourselves when our process()
method is first called. However, working around the issue by delaying
all opaque initialization until the stream is working is more robust.


Modified: trunk/gs/base/lib.mak
===================================================================
--- trunk/gs/base/lib.mak	2008-09-23 18:57:30 UTC (rev 9116)
+++ trunk/gs/base/lib.mak	2008-09-24 11:07:43 UTC (rev 9117)
@@ -278,6 +278,12 @@
 	$(GLCC) $(GLO_)md5.$(OBJ) $(C_) $(GLGEN)md5.c
 	$(RM_) $(GLGEN)md5.c $(GLGEN)md5.h
 
+# AES cipher
+aes_h=$(GLSRC)aes.h
+aes_=$(GLOBJ)aes.$(OBJ)
+$(GLOBJ)aes.$(OBJ) : $(GLSRC)aes.c $(AK) $(aes_h)
+	$(GLCC) $(GLO_)aes.$(OBJ) $(C_) $(GLSRC)aes.c
+
 # Visual Debugging
 $(GLOBJ)vdtrace.$(OBJ) : $(GLSRC)vdtrace.c $(math__h)\
  $(gxfixed_h) $(vdtrace_h)
@@ -473,6 +479,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) $(aes_h)
 sjbig2_h=$(GLSRC)sjbig2.h $(stdint__h) $(scommon_h)
 sjbig2_luratech_h=$(GLSRC)sjbig2_luratech.h $(scommon_h)
 sjpx_h=$(GLSRC)sjpx.h $(scommon_h)
@@ -1402,6 +1409,16 @@
  $(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_) $(aes_)
+	$(SETMOD) $(GLD)saes $(saes_) $(aes_)
+
+$(GLOBJ)saes.$(OBJ) : $(GLSRC)saes.c $(AK) $(memory__h)\
+ $(gserror_h) $(gserrors_h) $(strimpl_h) $(saes_h)
+	$(GLCC) $(GLO_)saes.$(OBJ) $(C_) $(GLSRC)saes.c
+
 # ---------------- JBIG2 compression filter ---------------- #
 
 $(GLD)sjbig2.dev : $(LIB_MAK) $(ECHOGS_XE) $(GLD)sjbig2_$(JBIG2_LIB).dev

Added: trunk/gs/base/saes.c
===================================================================
--- trunk/gs/base/saes.c	2008-09-23 18:57:30 UTC (rev 9116)
+++ trunk/gs/base/saes.c	2008-09-24 11:07:43 UTC (rev 9117)
@@ -0,0 +1,153 @@
+/* Copyright (C) 2001-2008 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 that
+   license.  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.
+*/
+
+/* $Id$ */
+
+/* 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)
+{
+    int code = 0;
+
+    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;
+
+    if (code) {
+      return gs_throw(gs_error_rangecheck, "could not set AES key");
+    }
+
+    /* return successfully */
+    return 0;
+}
+
+/* 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;
+    state->ctx = NULL;
+
+    return 0;
+}
+
+/* release our private storage */
+static void
+s_aes_release(stream_state *ss)
+{
+    stream_aes_state *const state = (stream_aes_state *) ss;
+
+    if (state->ctx != NULL)
+        gs_free_object(state->memory, state->ctx, "aes context structure");
+}
+
+/* (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 */
+    }
+
+    /* set up state and context */
+    if (state->ctx == NULL) {
+      /* allocate the aes context. this is a public struct but it
+         contains internal pointers, so we need to store it separately
+         in immovable memory like any opaque structure. */
+      state->ctx = (aes_context *)gs_alloc_bytes_immovable(state->memory,
+		sizeof(aes_context), "aes context structure");
+      if (state->ctx == NULL) {
+	gs_throw(gs_error_VMerror, "could not allocate aes context");
+	return ERRC;
+      }
+      if (state->keylength < 1 || state->keylength > SAES_MAX_KEYLENGTH) {
+	gs_throw1(gs_error_rangecheck, "invalid aes key length (%d bytes)",
+		state->keylength);
+	return ERRC;
+      }
+      aes_setkey_dec(state->ctx, state->key, state->keylength * 8);
+    }
+    if (!state->initialized) {
+	/* 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_crypt_cbc(state->ctx, AES_DECRYPT, 16, state->iv,
+				pr->ptr + 1, temp);
+      pr->ptr += 16;
+      if (last && pr->ptr == pr->limit) {
+        /* we're on the last block; unpad */
+        int pad = temp[15];
+        if (pad < 1 || pad > 16) return ERRC;
+        memcpy(pw->ptr + 1, temp, 16 - pad);
+        pw->ptr +=  16 - pad;
+        return EOFC;
+      }
+      memcpy(pw->ptr + 1, temp, 16);
+      pw->ptr += 16;
+    }
+
+    return status;
+}
+
+/* stream template */
+const stream_template s_aes_template = {
+    &st_aes_state, s_aes_init,
+    s_aes_process, 16, 16,
+    s_aes_release
+};

Added: trunk/gs/base/saes.h
===================================================================
--- trunk/gs/base/saes.h	2008-09-23 18:57:30 UTC (rev 9116)
+++ trunk/gs/base/saes.h	2008-09-24 11:07:43 UTC (rev 9117)
@@ -0,0 +1,59 @@
+/* Copyright (C) 2001-2008 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 that
+   license.  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.
+*/
+
+/* $Id$ */
+/* 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 "aes.h"
+
+/* maximum supported key length in bytes */
+#define SAES_MAX_KEYLENGTH 16
+
+/* 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 */
+    aes_context *ctx;		/* from aes.h */
+};
+
+#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);
+
+/* 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 */



More information about the gs-cvs mailing list