# HG changeset patch # User Simon Josefsson # Date 1129733672 0 # Node ID ca60471103cc3af20bae5b22c5fd18dc29a6f473 # Parent 3a6f48afc45f5a5644c187dd7b36d355dc740f94 Add gc-rijndael and gc-rijndael-tests modules. diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-10-19 Simon Josefsson + + * tests/test-gc-rijndael.c: New file. + + * modules/gc-rijndael, modules/gc-rijndael-test: New files. + 2005-10-19 Simon Josefsson * tests/test-gc-md4.c, tests/test-gc-md5.c: Test gc_hash_buffer diff --git a/lib/ChangeLog b/lib/ChangeLog --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,5 +1,10 @@ 2005-10-19 Simon Josefsson + * gc-gnulib.c: Implement gc_cipher_* API, currently only with AES + support. + + * gc.h: Add ECB enum type. + * hmac-md5.c, hmac-sha1.c: Include memxor.h. 2005-10-19 Simon Josefsson diff --git a/lib/gc-gnulib.c b/lib/gc-gnulib.c --- a/lib/gc-gnulib.c +++ b/lib/gc-gnulib.c @@ -49,6 +49,9 @@ #ifdef GC_USE_HMAC_MD5 # include "hmac.h" #endif +#ifdef GC_USE_RIJNDAEL +# include "rijndael-api-fst.h" +#endif Gc_rc gc_init (void) @@ -144,6 +147,217 @@ { return; } +/* Ciphers. */ + +typedef struct _gc_cipher_ctx { + Gc_cipher alg; + Gc_cipher_mode mode; +#ifdef GC_USE_RIJNDAEL + rijndaelKeyInstance aesEncKey; + rijndaelKeyInstance aesDecKey; + rijndaelCipherInstance aesContext; +#endif +} _gc_cipher_ctx; + +Gc_rc +gc_cipher_open (Gc_cipher alg, Gc_cipher_mode mode, + gc_cipher_handle * outhandle) +{ + _gc_cipher_ctx *ctx; + Gc_rc rc = GC_OK; + + ctx = calloc (sizeof (*ctx), 1); + + ctx->alg = alg; + ctx->mode = mode; + + switch (alg) + { +#ifdef GC_USE_RIJNDAEL + case GC_AES128: + case GC_AES192: + case GC_AES256: + switch (mode) + { + case GC_ECB: + case GC_CBC: + break; + + default: + rc = GC_INVALID_CIPHER; + } + break; +#endif + + default: + rc = GC_INVALID_CIPHER; + } + + if (rc == GC_OK) + *outhandle = ctx; + else + free (ctx); + + return rc; +} + +Gc_rc +gc_cipher_setkey (gc_cipher_handle handle, size_t keylen, const char *key) +{ + _gc_cipher_ctx *ctx = handle; + + switch (ctx->alg) + { +#ifdef GC_USE_RIJNDAEL + case GC_AES128: + case GC_AES192: + case GC_AES256: + { + rijndael_rc rc; + size_t i; + char keyMaterial[RIJNDAEL_MAX_KEY_SIZE + 1]; + + for (i = 0; i < keylen; i++) + sprintf (&keyMaterial[2*i], "%02x", key[i] & 0xFF); + + rc = rijndaelMakeKey (&ctx->aesEncKey, RIJNDAEL_DIR_ENCRYPT, + keylen * 8, keyMaterial); + if (rc < 0) + return GC_INVALID_CIPHER; + + rc = rijndaelMakeKey (&ctx->aesDecKey, RIJNDAEL_DIR_DECRYPT, + keylen * 8, keyMaterial); + if (rc < 0) + return GC_INVALID_CIPHER; + + rc = rijndaelCipherInit (&ctx->aesContext, RIJNDAEL_MODE_ECB, NULL); + if (rc < 0) + return GC_INVALID_CIPHER; + } + break; +#endif + + default: + return GC_INVALID_CIPHER; + } + + return GC_OK; +} + +Gc_rc +gc_cipher_setiv (gc_cipher_handle handle, size_t ivlen, const char *iv) +{ + _gc_cipher_ctx *ctx = handle; + + switch (ctx->alg) + { +#ifdef GC_USE_RIJNDAEL + case GC_AES128: + case GC_AES192: + case GC_AES256: + switch (ctx->mode) + { + case GC_ECB: + /* Doesn't use IV. */ + break; + + case GC_CBC: + { + rijndael_rc rc; + size_t i; + char ivMaterial[2 * RIJNDAEL_MAX_IV_SIZE + 1]; + + for (i = 0; i < ivlen; i++) + sprintf (&ivMaterial[2*i], "%02x", iv[i] & 0xFF); + + rc = rijndaelCipherInit (&ctx->aesContext, RIJNDAEL_MODE_CBC, + ivMaterial); + if (rc < 0) + return GC_INVALID_CIPHER; + } + break; + + default: + return GC_INVALID_CIPHER; + } + break; +#endif + + default: + return GC_INVALID_CIPHER; + } + + return GC_OK; +} + +Gc_rc +gc_cipher_encrypt_inline (gc_cipher_handle handle, size_t len, char *data) +{ + _gc_cipher_ctx *ctx = handle; + + switch (ctx->alg) + { +#ifdef GC_USE_RIJNDAEL + case GC_AES128: + case GC_AES192: + case GC_AES256: + { + int nblocks; + + nblocks = rijndaelBlockEncrypt (&ctx->aesContext, &ctx->aesEncKey, + data, 8 * len, data); + if (nblocks < 0) + return GC_INVALID_CIPHER; + } + break; +#endif + + default: + return GC_INVALID_CIPHER; + } + + return GC_OK; +} + +Gc_rc +gc_cipher_decrypt_inline (gc_cipher_handle handle, size_t len, char *data) +{ + _gc_cipher_ctx *ctx = handle; + + switch (ctx->alg) + { +#ifdef GC_USE_RIJNDAEL + case GC_AES128: + case GC_AES192: + case GC_AES256: + { + int nblocks; + + nblocks = rijndaelBlockDecrypt (&ctx->aesContext, &ctx->aesDecKey, + data, 8 * len, data); + if (nblocks < 0) + return GC_INVALID_CIPHER; + } + break; +#endif + + default: + return GC_INVALID_CIPHER; + } + + return GC_OK; +} + +Gc_rc +gc_cipher_close (gc_cipher_handle handle) +{ + _gc_cipher_ctx *ctx = handle; + + if (ctx) + free (ctx); + + return GC_OK; +} /* Hashes. */ diff --git a/lib/gc.h b/lib/gc.h --- a/lib/gc.h +++ b/lib/gc.h @@ -77,6 +77,7 @@ enum Gc_cipher_mode { + GC_ECB, GC_CBC, GC_STREAM }; diff --git a/m4/ChangeLog b/m4/ChangeLog --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,7 @@ +2005-10-19 Simon Josefsson + + * gc-rijndael.m4: New file. + 2005-10-19 Simon Josefsson * m4/gc-hmac-md5.m4, m4/gc-hmac-sha1.m4, m4/gc-md4.m4, diff --git a/m4/gc-rijndael.m4 b/m4/gc-rijndael.m4 new file mode 100644 --- /dev/null +++ b/m4/gc-rijndael.m4 @@ -0,0 +1,15 @@ +# gc-rijndael.m4 serial 1 +dnl Copyright (C) 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_GC_RIJNDAEL], +[ + AC_REQUIRE([gl_GC]) + AC_DEFINE(GC_USE_RIJNDAEL, 1, + [Define if you want to support RIJNDAEL through GC.]) + if test "$ac_cv_libgcrypt" != yes; then + gl_RIJNDAEL + fi +]) diff --git a/modules/gc-rijndael b/modules/gc-rijndael new file mode 100644 --- /dev/null +++ b/modules/gc-rijndael @@ -0,0 +1,28 @@ +Description: +Generic crypto wrappers for rijndael block cipher. + +Files: +m4/gc-rijndael.m4 +lib/rijndael-alg-fst.c +lib/rijndael-alg-fst.h +lib/rijndael-api-fst.c +lib/rijndael-api-fst.h +m4/rijndael.m4 + +Depends-on: +stdint +gc + +configure.ac: +gl_GC_RIJNDAEL + +Makefile.am: + +Include: +"gc.h" + +License: +LGPL + +Maintainer: +Simon Josefsson diff --git a/modules/gc-rijndael-tests b/modules/gc-rijndael-tests new file mode 100644 --- /dev/null +++ b/modules/gc-rijndael-tests @@ -0,0 +1,11 @@ +Files: +tests/test-gc-rijndael.c + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-gc-rijndael +noinst_PROGRAMS += test-gc-rijndael +test_gc_rijndael_SOURCES = test-gc-rijndael.c diff --git a/tests/test-gc-rijndael.c b/tests/test-gc-rijndael.c new file mode 100644 --- /dev/null +++ b/tests/test-gc-rijndael.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2005 Free Software Foundation + * Written by Simon Josefsson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "gc.h" + +int +main (int argc, char *argv[]) +{ + Gc_rc rc; + + rc = gc_init (); + if (rc != GC_OK) + { + printf ("gc_init() failed\n"); + return 1; + } + + { + char buf[16]; + char key[] = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + char pt[] = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + char ct[] = "\xC3\x4C\x05\x2C\xC0\xDA\x8D\x73" + "\x45\x1A\xFE\x5F\x03\xBE\x29\x7F"; + gc_cipher_handle ctx; + size_t i; + + rc = gc_cipher_open (GC_AES128, GC_ECB, &ctx); + if (rc != GC_OK) + return 1; + + rc = gc_cipher_setkey (ctx, 16, key); + if (rc != GC_OK) + return 1; + + memcpy (buf, pt, 16); + + for (i = 0; i < 10000; i++) + { + rc = gc_cipher_encrypt_inline (ctx, 16, buf); + if (rc != GC_OK) + { + printf ("encrypt failed %d\n", rc); + return 1; + } + } + + if (memcmp (buf, ct, 16) != 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", ct[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", buf[i] & 0xFF); + printf ("\n"); + return 1; + } + + for (i = 0; i < 10000; i++) + { + rc = gc_cipher_decrypt_inline (ctx, 16, buf); + if (rc != GC_OK) + { + printf ("decrypt failed %d\n", rc); + return 1; + } + } + + if (memcmp (buf, pt, 16) != 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", pt[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", buf[i] & 0xFF); + printf ("\n"); + return 1; + } + + gc_cipher_close (ctx); + } + + + { + char buf[16]; + char iv[] = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + char key[] = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + char pt[] = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00"; + char ct[] = "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b" + "\x88\x4c\xfa\x59\xca\x34\x2b\x2e"; + gc_cipher_handle ctx; + size_t i; + + rc = gc_cipher_open (GC_AES128, GC_CBC, &ctx); + if (rc != GC_OK) + return 1; + + rc = gc_cipher_setkey (ctx, 16, key); + if (rc != GC_OK) + return 1; + + rc = gc_cipher_setiv (ctx, 16, iv); + if (rc != GC_OK) + return 1; + + memcpy (buf, pt, 16); + + for (i = 0; i < 10000; i++) + { + rc = gc_cipher_encrypt_inline (ctx, 16, buf); + if (rc != GC_OK) + { + printf ("encrypt failed %d\n", rc); + return 1; + } + } + + if (memcmp (buf, ct, 16) != 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", ct[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", buf[i] & 0xFF); + printf ("\n"); + return 1; + } + + gc_cipher_close (ctx); + } + + gc_done (); + + return 0; +}