From: Nikos Mavrogiannopoulos Date: Sat, 5 Feb 2011 22:22:25 +0000 (+0100) Subject: * gcm.c: New file. X-Git-Tag: nettle_2.2_release_20110711~195 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=342ad32a2efb4f84d3a0c83859360ac717dc41b2;p=thirdparty%2Fnettle.git * gcm.c: New file. * gcm.h: New file. Rev: nettle/gcm.c:1.1 Rev: nettle/gcm.h:1.1 --- diff --git a/gcm.c b/gcm.c new file mode 100644 index 00000000..6e85728a --- /dev/null +++ b/gcm.c @@ -0,0 +1,253 @@ +/* gcm.h + * + * Galois counter mode, specified by NIST, + * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * + */ + +/* NOTE: Tentative interface, subject to change. No effort will be + made to avoid incompatible changes. */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2011 Niels Möller + * Copyright (C) 2011 Katholieke Universiteit Leuven + * + * Contributed by Nikos Mavrogiannopoulos + * + * A few functions copied from Tom S. Dennis' libtomcrypt, which is in + * the public domain. + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "gcm.h" + +#include "memxor.h" +#include "nettle-internal.h" +#include "macros.h" + +/* The gcm_rightshift and gcm_gf_mul was copied from + * libtomcrypt, which is under public domain. + * Written by Tom S. Dennis. + */ + +/* FIXME: Change representation so we can to word-sized shifts? */ +static void +gcm_rightshift (uint8_t * a) +{ + int x; + for (x = 15; x > 0; x--) + { + a[x] = (a[x] >> 1) | ((a[x - 1] << 7) & 0x80); + } + a[0] >>= 1; +} + +/** + GCM GF multiplier (internal use only) bitserial + @param a First value (and destination) + @param b Second value + */ +static void +gcm_gf_mul (uint8_t * a, const uint8_t * b) +{ + static const uint8_t mask[] = + { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + static const uint8_t poly[] = { 0x00, 0xE1 }; + + uint8_t Z[16], V[16]; + unsigned x, z; + + memset (Z, 0, 16); + memcpy (V, a, 16); + for (x = 0; x < 128; x++) + { + if (b[x >> 3] & mask[x & 7]) + { + memxor (Z, V, 16); + } + z = V[15] & 0x01; + gcm_rightshift (V); + V[0] ^= poly[z]; + } + memcpy (a, Z, 16); +} + +/* Increment the rightmost 32 bits. */ +#define INC32(block) INCREMENT(4, (block) + GCM_BLOCK_SIZE - 4) + +/* Initialization of GCM. + * @ctx: The context of GCM + * @cipher: The context of the underlying block cipher + * @f: The underlying cipher encryption function + */ +void +gcm_set_key(struct gcm_ctx *ctx, + void *cipher, nettle_crypt_func f) +{ + memset (ctx->h, 0, sizeof (ctx->h)); + f (cipher, GCM_BLOCK_SIZE, ctx->h, ctx->h); /* H */ +#if GCM_TABLE_BITS + /* FIXME: Expand hash subkey */ + abort(); +#endif +} + +/* + * @length: The size of the iv (fixed for now to GCM_NONCE_SIZE) + * @iv: The iv + */ +void +gcm_set_iv(struct gcm_ctx *ctx, unsigned length, const uint8_t* iv) +{ + /* FIXME: remove the iv size limitation */ + assert (length == GCM_IV_SIZE); + + memcpy (ctx->iv, iv, GCM_BLOCK_SIZE - 4); + ctx->iv[GCM_BLOCK_SIZE - 4] = 0; + ctx->iv[GCM_BLOCK_SIZE - 3] = 0; + ctx->iv[GCM_BLOCK_SIZE - 2] = 0; + ctx->iv[GCM_BLOCK_SIZE - 1] = 1; + + memcpy (ctx->ctr, ctx->iv, GCM_BLOCK_SIZE); + INC32 (ctx->ctr); + + /* Reset the rest of the message-dependent state. */ + memset(ctx->x, 0, sizeof(ctx->x)); + ctx->auth_size = ctx->data_size = 0; +} + +static void +gcm_hash(struct gcm_ctx *ctx, unsigned length, const uint8_t *data) +{ + for (; length >= GCM_BLOCK_SIZE; + length -= GCM_BLOCK_SIZE, data += GCM_BLOCK_SIZE) + { + memxor (ctx->x, data, GCM_BLOCK_SIZE); + gcm_gf_mul (ctx->x, ctx->h); + } + if (length > 0) + { + memxor (ctx->x, data, length); + gcm_gf_mul (ctx->x, ctx->h); + } +} + +void +gcm_auth(struct gcm_ctx *ctx, + unsigned length, const uint8_t *data) +{ + assert(ctx->auth_size % GCM_BLOCK_SIZE == 0); + assert(ctx->data_size % GCM_BLOCK_SIZE == 0); + + gcm_hash(ctx, length, data); + + ctx->auth_size += length; +} + +static void +gcm_crypt(struct gcm_ctx *ctx, void *cipher, nettle_crypt_func *f, + unsigned length, + uint8_t *dst, const uint8_t *src) +{ + uint8_t buffer[GCM_BLOCK_SIZE]; + + if (src != dst) + { + for (; length >= GCM_BLOCK_SIZE; + (length -= GCM_BLOCK_SIZE, + src += GCM_BLOCK_SIZE, dst += GCM_BLOCK_SIZE)) + { + f (cipher, GCM_BLOCK_SIZE, dst, ctx->ctr); + memxor (dst, src, GCM_BLOCK_SIZE); + INC32 (ctx->ctr); + } + } + else + { + for (; length >= GCM_BLOCK_SIZE; + (length -= GCM_BLOCK_SIZE, + src += GCM_BLOCK_SIZE, dst += GCM_BLOCK_SIZE)) + { + f (cipher, GCM_BLOCK_SIZE, buffer, ctx->ctr); + memxor3 (dst, src, buffer, GCM_BLOCK_SIZE); + INC32 (ctx->ctr); + } + } + if (length > 0) + { + /* A final partial block */ + f (cipher, GCM_BLOCK_SIZE, buffer, ctx->ctr); + memxor3 (dst, src, buffer, length); + INC32 (ctx->ctr); + } +} + +void +gcm_encrypt (struct gcm_ctx *ctx, void *cipher, nettle_crypt_func *f, + unsigned length, + uint8_t *dst, const uint8_t *src) +{ + assert(ctx->data_size % GCM_BLOCK_SIZE == 0); + + gcm_crypt(ctx, cipher, f, length, dst, src); + gcm_hash(ctx, length, dst); + + ctx->data_size += length; +} + +void +gcm_decrypt(struct gcm_ctx *ctx, void *cipher, nettle_crypt_func *f, + unsigned length, uint8_t *dst, const uint8_t *src) +{ + assert(ctx->data_size % GCM_BLOCK_SIZE == 0); + + gcm_hash(ctx, length, src); + gcm_crypt(ctx, cipher, f, length, dst, src); + + ctx->data_size += length; +} + +void +gcm_digest(struct gcm_ctx *ctx, void *cipher, nettle_crypt_func *f, + unsigned length, uint8_t *digest) +{ + uint8_t buffer[GCM_BLOCK_SIZE]; + + assert (length <= GCM_BLOCK_SIZE); + + ctx->data_size *= 8; + ctx->auth_size *= 8; + + WRITE_UINT64 (buffer, ctx->auth_size); + WRITE_UINT64 (buffer + 8, ctx->data_size); + + gcm_hash(ctx, GCM_BLOCK_SIZE, buffer); + + f (cipher, GCM_BLOCK_SIZE, buffer, ctx->iv); + memxor3 (digest, ctx->x, buffer, length); + + return; +} diff --git a/gcm.h b/gcm.h new file mode 100644 index 00000000..ad34d702 --- /dev/null +++ b/gcm.h @@ -0,0 +1,157 @@ +/* gcm.h + * + * Galois counter mode, specified by NIST, + * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * + */ + +/* NOTE: Tentative interface, subject to change. No effort will be + made to avoid incompatible changes. */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2011 Niels Möller + * Copyright (C) 2011 Katholieke Universiteit Leuven + * + * Contributed by Nikos Mavrogiannopoulos + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef NETTLE_GCM_H_INCLUDED +#define NETTLE_GCM_H_INCLUDED + +#include "nettle-types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Name mangling */ +#define gcm_set_key nettle_gcm_set_key +#define gcm_set_iv nettle_gcm_set_iv +#define gcm_auth nettle_gcm_auth +#define gcm_encrypt nettle_gcm_encrypt +#define gcm_decrypt nettle_gcm_decrypt +#define gcm_digest nettle_gcm_digest + +#define GCM_BLOCK_SIZE 16 +#define GCM_IV_SIZE (GCM_BLOCK_SIZE - 4) + +#define GCM_TABLE_BITS 0 + +struct gcm_ctx { + /* Key-dependent state. */ + /* Hashing subkey */ + uint8_t h[GCM_BLOCK_SIZE]; +#if GCM_TABLE_BITS + uint8_t h[1 << GCM_TABLE_BITS][GCM_BLOCK_SIZE]; +#endif + /* Per-message state, depending on the iv */ + /* Original counter block */ + uint8_t iv[GCM_BLOCK_SIZE]; + /* Updated for each block. */ + uint8_t ctr[GCM_BLOCK_SIZE]; + /* Hashing state */ + uint8_t x[GCM_BLOCK_SIZE]; + uint64_t auth_size; + uint64_t data_size; +}; + +/* FIXME: Should use const for the cipher context. Then needs const for + nettle_crypt_func, which also rules out using that abstraction for + arcfour. */ +void +gcm_set_key(struct gcm_ctx *ctx, + void *cipher, nettle_crypt_func *f); + +void +gcm_set_iv(struct gcm_ctx *ctx, unsigned length, const uint8_t *iv); + +void +gcm_auth(struct gcm_ctx *ctx, unsigned length, const uint8_t *data); + +void +gcm_encrypt(struct gcm_ctx *ctx, void *cipher, nettle_crypt_func *f, + unsigned length, uint8_t *dst, const uint8_t *src); + +void +gcm_decrypt(struct gcm_ctx *ctx, void *cipher, nettle_crypt_func *f, + unsigned length, uint8_t *dst, const uint8_t *src); + +void +gcm_digest(struct gcm_ctx *ctx, void *cipher, nettle_crypt_func *f, + unsigned length, uint8_t *digest); + +#if 0 +/* FIXME: IS this macrology useful? */ +#define GCM_KEY(type) \ +{ type cipher; struct gcm_ctx gcm; } + +#define GCM_SET_KEY(ctx, set_key, encrypt, length, data) \ + do { \ + (set_key)(&(ctx)->cipher, (length), (data)); \ + gcm_set_key(&(ctx)->gcm, &(ctx)->cipher, (encrypt)); \ + } while (0) + +#define GCM_AUTH(ctx, encrypt, length, data) \ + gcm_auth((ctx)->gcm, &(ctx)->cipher, (encrypt), \ + (length), (data)) + +#define GCM_ENCRYPT(ctx, encrypt, length, dst, src) \ + gcm_encrypt((ctx)->gcm, &(ctx)->cipher, (encrypt), \ + (length), (dst), (src)) + +#define GCM_DECRYPT(ctx, key, encrypt, length, dst, src) \ + gcm_decrypt((ctx)->gcm, &(ctx)->cipher, (encrypt), \ + (length), (dst), (src)) + +#define GCM_DIGEST(ctx, key, encrypt, length, digest) \ + gcm_digest((ctx)->gcm, &(ctx)->cipher, (encrypt), \ + (length), (digest)) + +struct gcm_aes_ctx GCM_CTX(struct aes_ctx); + +void +gcm_aes_set_key(struct gcm_aes_ctx *ctx, + unsigned length, const uint8_t *key); + +void +gcm_aes_set_iv(struct gcm_aes_ctx *ctx, + unsigned length, const uint8_t *iv); + +void +gcm_aes_auth(struct gcm_aes_ctx *ctx, + unsigned length, const uint8_t *data); + +void +gcm_aes_encrypt(struct gcm_aes_ctx *ctx, + unsigned length, uint8_t *dst, const uint8_t *src); + +void +gcm_aes_decrypt(struct gcm_aes_ctx *ctx, + unsigned length, uint8_t *dst, const uint8_t *src); + +void +gcm_aes_digest(struct gcm_aes_ctx *ctx, + unsigned length, uint8_t *digest); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_GCM_H_INCLUDED */