From 79ba130cb5776f994f6a3f0f87159d8cbc5ff129 Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 10 Dec 1999 23:17:39 +0000 Subject: [PATCH] Split mode macros into interface and implementation. --- cbc-def.h | 542 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cbc.h | 401 ++++----------------------------------------- cfb-def.h | 499 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cfb.h | 354 +++++----------------------------------- ecb-def.h | 462 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ecb.h | 345 ++++----------------------------------- genmodes | 9 +- hash.h | 30 +++- hmac-def.h | 343 ++++++++++++++++++++++++++++++++++++++ hmac.h | 218 +++++-------------------- ofb-def.h | 538 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ofb.h | 294 +++++---------------------------- 12 files changed, 2589 insertions(+), 1446 deletions(-) create mode 100644 cbc-def.h create mode 100644 cfb-def.h create mode 100644 ecb-def.h create mode 100644 hmac-def.h create mode 100644 ofb-def.h diff --git a/cbc-def.h b/cbc-def.h new file mode 100644 index 0000000..aff245c --- /dev/null +++ b/cbc-def.h @@ -0,0 +1,542 @@ +/* -*-c-*- + * + * $Id: cbc-def.h,v 1.1 1999/12/10 23:16:39 mdw Exp $ + * + * Definitions for cipher block chaining mode + * + * (c) 1999 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: cbc-def.h,v $ + * Revision 1.1 1999/12/10 23:16:39 mdw + * Split mode macros into interface and implementation. + * + */ + +#ifndef CATACOMB_CBC_DEF_H +#define CATACOMB_CBC_DEF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include + +#include +#include + +#ifndef CATACOMB_BLKC_H +# include "blkc.h" +#endif + +#ifndef CATACOMB_GCIPHER_H +# include "gcipher.h" +#endif + +/*----- Macros ------------------------------------------------------------*/ + +/* --- @CBC_DEF@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher + * + * Use: Creates an implementation for CBC stealing mode. + */ + +#define CBC_DEF(PRE, pre) \ + \ +/* --- @pre_cbcgetiv@ --- * \ + * \ + * Arguments: @const pre_cbcctx *ctx@ = pointer to CBC context block \ + * @void *iv#@ = pointer to output data block \ + * \ + * Returns: --- \ + * \ + * Use: Reads the currently set IV. Reading and setting an IV \ + * is transparent to the CBC encryption or decryption \ + * process. \ + */ \ + \ +void pre##_cbcgetiv(const pre##_cbcctx *ctx, void *iv) \ +{ \ + BLKC_STORE(PRE, iv, ctx->iv); \ +} \ + \ +/* --- @pre_cbcsetiv@ --- * \ + * \ + * Arguments: @pre_cbcctx *ctx@ = pointer to CBC context block \ + * @cnost void *iv@ = pointer to IV to set \ + * \ + * Returns: --- \ + * \ + * Use: Sets the IV to use for subsequent encryption. \ + */ \ + \ +void pre##_cbcsetiv(pre##_cbcctx *ctx, const void *iv) \ +{ \ + BLKC_LOAD(PRE, ctx->iv, iv); \ +} \ + \ +/* --- @pre_cbcsetkey@ --- * \ + * \ + * Arguments: @pre_cbcctx *ctx@ = pointer to CBC context block \ + * @const pre_ctx *k@ = pointer to cipher context \ + * \ + * Returns: --- \ + * \ + * Use: Sets the CBC context to use a different cipher key. \ + */ \ + \ +void pre##_cbcsetkey(pre##_cbcctx *ctx, const pre##_ctx *k) \ +{ \ + ctx->ctx = *k; \ +} \ + \ +/* --- @pre_cbcinit@ --- * \ + * \ + * Arguments: @pre_cbcctx *ctx@ = pointer to cipher context \ + * @const void *key@ = pointer to the key buffer \ + * @size_t sz@ = size of the key \ + * @const void *iv@ = pointer to initialization vector \ + * \ + * Returns: --- \ + * \ + * Use: Initializes a CBC context ready for use. The @iv@ \ + * argument may be passed as a null pointer to set a zero \ + * IV. Apart from that, this call is equivalent to calls \ + * to @pre_init@, @pre_cbcsetkey@ and @pre_cbcsetiv@. \ + */ \ + \ +void pre##_cbcinit(pre##_cbcctx *ctx, \ + const void *key, size_t sz, \ + const void *iv) \ +{ \ + static octet zero[PRE##_BLKSZ] = { 0 }; \ + pre##_init(&ctx->ctx, key, sz); \ + BLKC_LOAD(PRE, ctx->iv, iv ? iv : zero); \ +} \ + \ +/* --- @pre_cbcencrypt@ --- * \ + * \ + * Arguments: @pre_cbcctx *ctx@ = pointer to CBC context block \ + * @const void *src@ = pointer to source data \ + * @void *dest@ = pointer to destination data \ + * @size_t sz@ = size of block to be encrypted \ + * \ + * Returns: --- \ + * \ + * Use: Encrypts a block with a block cipher in CBC mode, with \ + * ciphertext stealing and other clever tricks. \ + * Essentially, data can be encrypted in arbitrary sized \ + * chunks, although decryption must use the same chunks. \ + */ \ + \ +void pre##_cbcencrypt(pre##_cbcctx *ctx, \ + const void *src, void *dest, \ + size_t sz) \ +{ \ + const octet *s = src; \ + octet *d = dest; \ + \ + /* --- Empty blocks are trivial --- */ \ + \ + if (!sz) \ + return; \ + \ + /* --- Extra magical case for a short block --- * \ + * \ + * Encrypt the IV, then exclusive-or the plaintext with the octets \ + * of the encrypted IV, shifting ciphertext octets in instead. This \ + * basically switches over to CFB. \ + */ \ + \ + if (sz < PRE##_BLKSZ) { \ + octet b[PRE##_BLKSZ]; \ + unsigned i; \ + \ + pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv); \ + BLKC_STORE(PRE, b, ctx->iv); \ + for (i = 0; i < sz; i++) \ + d[i] = b[i] ^ s[i]; \ + memmove(b, b + sz, PRE##_BLKSZ - sz); \ + memcpy(b + PRE##_BLKSZ - sz, d, sz); \ + BLKC_LOAD(PRE, ctx->iv, b); \ + return; \ + } \ + \ + /* --- Do the main chunk of encryption --- * \ + * \ + * This will do the whole lot if it's a whole number of blocks. For \ + * each block, XOR it with the previous ciphertext in @iv@, encrypt, \ + * and keep a copy of the ciphertext for the next block. \ + */ \ + \ + while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) { \ + BLKC_XLOAD(PRE, ctx->iv, s); \ + pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv); \ + BLKC_STORE(PRE, d, ctx->iv); \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + sz -= PRE##_BLKSZ; \ + } \ + \ + /* --- Do the tail-end block and bit-left-over --- * \ + * \ + * This isn't very efficient. That shouldn't matter much. \ + */ \ + \ + if (sz) { \ + octet b[PRE##_BLKSZ]; \ + unsigned i; \ + \ + /* --- Let @sz@ be the size of the partial block --- */ \ + \ + sz -= PRE##_BLKSZ; \ + \ + /* --- First stage --- * \ + * \ + * XOR the complete block with the current IV, and encrypt it. The \ + * first part of the result is the partial ciphertext block. Don't \ + * write that out yet, because I've not read the partial plaintext \ + * block. \ + */ \ + \ + BLKC_XLOAD(PRE, ctx->iv, s); \ + pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv); \ + BLKC_STORE(PRE, b, ctx->iv); \ + \ + /* --- Second stage --- * \ + * \ + * Now XOR in the partial plaintext block, writing out the \ + * ciphertext as I go. Then encrypt, and write the complete \ + * ciphertext block. \ + */ \ + \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + for (i = 0; i < sz; i++) { \ + register octet x = b[i]; \ + b[i] ^= s[i]; \ + d[i] = x; \ + } \ + BLKC_LOAD(PRE, ctx->iv, b); \ + pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv); \ + BLKC_STORE(PRE, d - PRE##_BLKSZ, ctx->iv); \ + } \ + \ + /* --- Done --- */ \ + \ + return; \ +} \ + \ +/* --- @pre_cbcdecrypt@ --- * \ + * \ + * Arguments: @pre_cbcctx *ctx@ = pointer to CBC context block \ + * @const void *src@ = pointer to source data \ + * @void *dest@ = pointer to destination data \ + * @size_t sz@ = size of block to be encrypted \ + * \ + * Returns: --- \ + * \ + * Use: Decrypts a block with a block cipher in CBC mode, with \ + * ciphertext stealing and other clever tricks. \ + * Essentially, data can be encrypted in arbitrary sized \ + * chunks, although decryption must use the same chunks. \ + */ \ + \ +void pre##_cbcdecrypt(pre##_cbcctx *ctx, \ + const void *src, void *dest, \ + size_t sz) \ +{ \ + const octet *s = src; \ + octet *d = dest; \ + \ + /* --- Empty blocks are trivial --- */ \ + \ + if (!sz) \ + return; \ + \ + /* --- Extra magical case for a short block --- * \ + * \ + * Encrypt the IV, then exclusive-or the ciphertext with the octets \ + * of the encrypted IV, shifting ciphertext octets in instead. This \ + * basically switches over to CFB. \ + */ \ + \ + if (sz < PRE##_BLKSZ) { \ + octet b[PRE##_BLKSZ], c[PRE##_BLKSZ]; \ + unsigned i; \ + \ + pre##_eblk(&ctx->ctx, ctx->iv, ctx->iv); \ + BLKC_STORE(PRE, b, ctx->iv); \ + for (i = 0; i < sz; i++) { \ + register octet x = s[i]; \ + d[i] = b[i] ^ x; \ + c[i] = x; \ + } \ + memmove(b, b + sz, PRE##_BLKSZ - sz); \ + memcpy(b + PRE##_BLKSZ - sz, c, sz); \ + BLKC_LOAD(PRE, ctx->iv, b); \ + return; \ + } \ + \ + /* --- Do the main chunk of decryption --- * \ + * \ + * This will do the whole lot if it's a whole number of blocks. For \ + * each block, decrypt, XOR it with the previous ciphertext in @iv@, \ + * and keep a copy of the ciphertext for the next block. \ + */ \ + \ + while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) { \ + uint32 b[PRE##_BLKSZ / 4], niv[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, niv, s); \ + pre##_dblk(&ctx->ctx, niv, b); \ + BLKC_XSTORE(PRE, d, b, ctx->iv); \ + BLKC_MOVE(PRE, ctx->iv, niv); \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + sz -= PRE##_BLKSZ; \ + } \ + \ + /* --- Do the tail-end block and bit-left-over --- * \ + * \ + * This isn't very efficient. That shouldn't matter much. \ + */ \ + \ + if (sz) { \ + octet b[PRE##_BLKSZ]; \ + uint32 bk[PRE##_BLKSZ / 4], niv[PRE##_BLKSZ / 4]; \ + unsigned i; \ + \ + /* --- Let @sz@ be the size of the partial block --- */ \ + \ + sz -= PRE##_BLKSZ; \ + \ + /* --- First stage --- * \ + * \ + * Take the complete ciphertext block, and decrypt it. This block \ + * is carried over for the next encryption operation. \ + */ \ + \ + BLKC_LOAD(PRE, niv, s); \ + pre##_dblk(&ctx->ctx, niv, bk); \ + \ + /* --- Second stage --- * \ + * \ + * XORing the first few bytes of this with the partial ciphertext \ + * block recovers the partial plaintext block. At the same time, \ + * write the partial ciphertext block's contents in ready for stage \ + * three. \ + */ \ + \ + BLKC_STORE(PRE, b, bk); \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + for (i = 0; i < sz; i++) { \ + register octet x = s[i]; \ + d[i] = b[i] ^ x; \ + b[i] = x; \ + } \ + \ + /* --- Third stage --- * \ + * \ + * Decrypt the block we've got left, and XOR with the initial IV to \ + * recover the complete plaintext block. \ + */ \ + \ + BLKC_LOAD(PRE, bk, b); \ + pre##_dblk(&ctx->ctx, bk, bk); \ + BLKC_XSTORE(PRE, d - PRE##_BLKSZ, bk, ctx->iv); \ + BLKC_MOVE(PRE, ctx->iv, niv); \ + } \ + \ + /* --- Done --- */ \ + \ + return; \ +} \ + \ +/* --- Generic cipher interface --- */ \ + \ +static const gcipher_ops gops; \ + \ +typedef struct gctx { \ + gcipher c; \ + pre##_cbcctx k; \ +} gctx; \ + \ +static gcipher *ginit(const void *k, size_t sz) \ +{ \ + gctx *g = CREATE(gctx); \ + g->c.ops = &gops; \ + pre##_cbcinit(&g->k, k, sz, 0); \ + return (&g->c); \ +} \ + \ +static void gencrypt(gcipher *c, const void *s, void *t, size_t sz) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_cbcencrypt(&g->k, s, t, sz); \ +} \ + \ +static void gdecrypt(gcipher *c, const void *s, void *t, size_t sz) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_cbcdecrypt(&g->k, s, t, sz); \ +} \ + \ +static void gdestroy(gcipher *c) \ +{ \ + gctx *g = (gctx *)c; \ + DESTROY(g); \ +} \ + \ +static void gsetiv(gcipher *c, const void *iv) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_cbcsetiv(&g->k, iv); \ +} \ + \ +static const gcipher_ops gops = { \ + &pre##_cbc.b, \ + gencrypt, gdecrypt, gdestroy, gsetiv, 0 \ +}; \ + \ +const gccipher pre##_cbc = { \ + { #pre "-cbc", PRE##_KEYSZ, PRE##_BLKSZ }, \ + ginit \ +}; \ + \ +CBC_TEST(PRE, pre) + +/*----- Test rig ----------------------------------------------------------*/ + +#ifdef TEST_RIG + +#include + +#include "daftstory.h" + +/* --- @CBC_TEST@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions + * + * Use: Standard test rig for CBC functions. + */ + +#define CBC_TEST(PRE, pre) \ + \ +/* --- Initial plaintext for the test --- */ \ + \ +static const octet text[] = TEXT; \ + \ +/* --- Key and IV to use --- */ \ + \ +static const octet key[] = KEY; \ +static const octet iv[] = IV; \ + \ +/* --- Buffers for encryption and decryption output --- */ \ + \ +static octet ct[sizeof(text)]; \ +static octet pt[sizeof(text)]; \ + \ +static void hexdump(const octet *p, size_t sz) \ +{ \ + const octet *q = p + sz; \ + for (sz = 0; p < q; p++, sz++) { \ + printf("%02x", *p); \ + if ((sz + 1) % PRE##_BLKSZ == 0) \ + putchar(':'); \ + } \ +} \ + \ +int main(void) \ +{ \ + size_t sz = 0, rest; \ + pre##_cbcctx ctx; \ + pre##_ctx k; \ + int status = 0; \ + int done = 0; \ + \ + size_t keysz = PRE##_KEYSZ ? \ + PRE##_KEYSZ : strlen((const char *)key); \ + \ + fputs(#pre "-cbc: ", stdout); \ + \ + pre##_init(&k, key, keysz); \ + pre##_cbcsetkey(&ctx, &k); \ + \ + while (sz <= sizeof(text)) { \ + rest = sizeof(text) - sz; \ + memcpy(ct, text, sizeof(text)); \ + pre##_cbcsetiv(&ctx, iv); \ + pre##_cbcencrypt(&ctx, ct, ct, sz); \ + pre##_cbcencrypt(&ctx, ct + sz, ct + sz, rest); \ + memcpy(pt, ct, sizeof(text)); \ + pre##_cbcsetiv(&ctx, iv); \ + pre##_cbcdecrypt(&ctx, pt, pt, sz); \ + pre##_cbcdecrypt(&ctx, pt + sz, pt + sz, rest); \ + if (memcmp(pt, text, sizeof(text)) == 0) { \ + done++; \ + if (sizeof(text) < 40 || done % 8 == 0) \ + fputc('.', stdout); \ + if (done % 480 == 0) \ + fputs("\n\t", stdout); \ + fflush(stdout); \ + } else { \ + printf("\nError (sz = %lu)\n", (unsigned long)sz); \ + status = 1; \ + printf("\tplaintext = "); hexdump(text, sz); \ + printf(", "); hexdump(text + sz, rest); \ + fputc('\n', stdout); \ + printf("\tciphertext = "); hexdump(ct, sz); \ + printf(", "); hexdump(ct + sz, rest); \ + fputc('\n', stdout); \ + printf("\trecovered text = "); hexdump(pt, sz); \ + printf(", "); hexdump(pt + sz, rest); \ + fputc('\n', stdout); \ + fputc('\n', stdout); \ + } \ + if (sz < 63) \ + sz++; \ + else \ + sz += 9; \ + } \ + \ + fputs(status ? " failed\n" : " ok\n", stdout); \ + return (status); \ +} + +#else +# define CBC_TEST(PRE, pre) +#endif + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/cbc.h b/cbc.h index 66979de..40ec575 100644 --- a/cbc.h +++ b/cbc.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: cbc.h,v 1.1 1999/09/03 08:41:11 mdw Exp $ + * $Id: cbc.h,v 1.2 1999/12/10 23:16:39 mdw Exp $ * * Ciphertext block chaining for block ciphers * @@ -30,13 +30,16 @@ /*----- Revision history --------------------------------------------------* * * $Log: cbc.h,v $ + * Revision 1.2 1999/12/10 23:16:39 mdw + * Split mode macros into interface and implementation. + * * Revision 1.1 1999/09/03 08:41:11 mdw * Initial import. * */ -#ifndef CBC_H -#define CBC_H +#ifndef CATACOMB_CBC_H +#define CATACOMB_CBC_H #ifdef __cplusplus extern "C" { @@ -44,12 +47,12 @@ /*----- Header files ------------------------------------------------------*/ -#include +#include #include -#ifndef BLKC_H -# include "blkc.h" +#ifndef CATACOMB_GCIPHER_H +# include "gcipher.h" #endif /*----- Macros ------------------------------------------------------------*/ @@ -63,40 +66,12 @@ #define CBC_DECL(PRE, pre) \ \ -typedef struct pre ## _cbcctx { \ - pre ## _ctx ctx; /* Underlying cipher context */ \ - uint32 iv[PRE ## _BLKSZ / 4]; /* Previous ciphertext or IV */ \ -} pre ## _cbcctx; \ - \ -extern void pre ## _cbcgetiv(const pre ## _cbcctx */*ctx*/, \ - void */*iv*/); \ - \ -extern void pre ## _cbcsetiv(pre ## _cbcctx */*ctx*/, \ - const void */*iv*/); \ - \ -extern void pre ## _cbcsetkey(pre ## _cbcctx */*ctx*/, \ - const pre ## _ctx */*k*/); \ - \ -extern void pre ## _cbcinit(pre ## _cbcctx */*ctx*/, \ - const void */*key*/, size_t /*sz*/, \ - const void */*iv*/); \ +/* --- Cipher block chaining context --- */ \ \ -extern void pre ## _cbcencrypt(pre ## _cbcctx */*ctx*/, \ - const void */*src*/, void */*dest*/, \ - size_t /*sz*/); \ - \ -extern void pre ## _cbcdecrypt(pre ## _cbcctx */*ctx*/, \ - const void */*src*/, void */*dest*/, \ - size_t /*sz*/); \ - -/* --- @CBC_DEF@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher - * - * Use: Creates an implementation for CBC stealing mode. - */ - -#define CBC_DEF(PRE, pre) \ +typedef struct pre##_cbcctx { \ + pre##_ctx ctx; /* Underlying cipher context */ \ + uint32 iv[PRE##_BLKSZ / 4]; /* Previous ciphertext or IV */ \ +} pre##_cbcctx; \ \ /* --- @pre_cbcgetiv@ --- * \ * \ @@ -110,10 +85,8 @@ extern void pre ## _cbcdecrypt(pre ## _cbcctx */*ctx*/, \ * process. \ */ \ \ -void pre ## _cbcgetiv(const pre ## _cbcctx *ctx, void *iv) \ -{ \ - BLKC_STORE(PRE, iv, ctx->iv); \ -} \ +extern void pre##_cbcgetiv(const pre##_cbcctx */*ctx*/, \ + void */*iv*/); \ \ /* --- @pre_cbcsetiv@ --- * \ * \ @@ -125,10 +98,8 @@ void pre ## _cbcgetiv(const pre ## _cbcctx *ctx, void *iv) \ * Use: Sets the IV to use for subsequent encryption. \ */ \ \ -void pre ## _cbcsetiv(pre ## _cbcctx *ctx, const void *iv) \ -{ \ - BLKC_LOAD(PRE, ctx->iv, iv); \ -} \ +extern void pre##_cbcsetiv(pre##_cbcctx */*ctx*/, \ + const void */*iv*/); \ \ /* --- @pre_cbcsetkey@ --- * \ * \ @@ -140,10 +111,8 @@ void pre ## _cbcsetiv(pre ## _cbcctx *ctx, const void *iv) \ * Use: Sets the CBC context to use a different cipher key. \ */ \ \ -void pre ## _cbcsetkey(pre ## _cbcctx *ctx, const pre ## _ctx *k) \ -{ \ - ctx->ctx = *k; \ -} \ +extern void pre##_cbcsetkey(pre##_cbcctx */*ctx*/, \ + const pre##_ctx */*k*/); \ \ /* --- @pre_cbcinit@ --- * \ * \ @@ -160,14 +129,9 @@ void pre ## _cbcsetkey(pre ## _cbcctx *ctx, const pre ## _ctx *k) \ * to @pre_init@, @pre_cbcsetkey@ and @pre_cbcsetiv@. \ */ \ \ -void pre ## _cbcinit(pre ## _cbcctx *ctx, \ - const void *key, size_t sz, \ - const void *iv) \ -{ \ - static octet zero[PRE ## _BLKSZ] = { 0 }; \ - pre ## _init(&ctx->ctx, key, sz); \ - BLKC_LOAD(PRE, ctx->iv, iv ? iv : zero); \ -} \ +extern void pre##_cbcinit(pre##_cbcctx */*ctx*/, \ + const void */*key*/, size_t /*sz*/, \ + const void */*iv*/); \ \ /* --- @pre_cbcencrypt@ --- * \ * \ @@ -184,103 +148,9 @@ void pre ## _cbcinit(pre ## _cbcctx *ctx, \ * chunks, although decryption must use the same chunks. \ */ \ \ -void pre ## _cbcencrypt(pre ## _cbcctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ -{ \ - const octet *s = src; \ - octet *d = dest; \ - \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) \ - return; \ - \ - /* --- Extra magical case for a short block --- * \ - * \ - * Encrypt the IV, then exclusive-or the plaintext with the octets \ - * of the encrypted IV, shifting ciphertext octets in instead. This \ - * basically switches over to CFB. \ - */ \ - \ - if (sz < PRE ## _BLKSZ) { \ - octet b[PRE ## _BLKSZ]; \ - unsigned i; \ - \ - pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \ - BLKC_STORE(PRE, b, ctx->iv); \ - for (i = 0; i < sz; i++) \ - d[i] = b[i] ^ s[i]; \ - memmove(b, b + sz, PRE ## _BLKSZ - sz); \ - memcpy(b + PRE ## _BLKSZ - sz, d, sz); \ - BLKC_LOAD(PRE, ctx->iv, b); \ - return; \ - } \ - \ - /* --- Do the main chunk of encryption --- * \ - * \ - * This will do the whole lot if it's a whole number of blocks. For \ - * each block, XOR it with the previous ciphertext in @iv@, encrypt, \ - * and keep a copy of the ciphertext for the next block. \ - */ \ - \ - while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \ - BLKC_XLOAD(PRE, ctx->iv, s); \ - pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \ - BLKC_STORE(PRE, d, ctx->iv); \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - sz -= PRE ## _BLKSZ; \ - } \ - \ - /* --- Do the tail-end block and bit-left-over --- * \ - * \ - * This isn't very efficient. That shouldn't matter much. \ - */ \ - \ - if (sz) { \ - octet b[PRE ## _BLKSZ]; \ - unsigned i; \ - \ - /* --- Let @sz@ be the size of the partial block --- */ \ - \ - sz -= PRE ## _BLKSZ; \ - \ - /* --- First stage --- * \ - * \ - * XOR the complete block with the current IV, and encrypt it. The \ - * first part of the result is the partial ciphertext block. Don't \ - * write that out yet, because I've not read the partial plaintext \ - * block. \ - */ \ - \ - BLKC_XLOAD(PRE, ctx->iv, s); \ - pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \ - BLKC_STORE(PRE, b, ctx->iv); \ - \ - /* --- Second stage --- * \ - * \ - * Now XOR in the partial plaintext block, writing out the \ - * ciphertext as I go. Then encrypt, and write the complete \ - * ciphertext block. \ - */ \ - \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - for (i = 0; i < sz; i++) { \ - register octet x = b[i]; \ - b[i] ^= s[i]; \ - d[i] = x; \ - } \ - BLKC_LOAD(PRE, ctx->iv, b); \ - pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \ - BLKC_STORE(PRE, d - PRE ## _BLKSZ, ctx->iv); \ - } \ - \ - /* --- Done --- */ \ - \ - return; \ -} \ +extern void pre##_cbcencrypt(pre##_cbcctx */*ctx*/, \ + const void */*src*/, void */*dest*/, \ + size_t /*sz*/); \ \ /* --- @pre_cbcdecrypt@ --- * \ * \ @@ -291,226 +161,19 @@ void pre ## _cbcencrypt(pre ## _cbcctx *ctx, \ * \ * Returns: --- \ * \ - * Use: Encrypts a block with a block cipher in CBC mode, with \ + * Use: Decrypts a block with a block cipher in CBC mode, with \ * ciphertext stealing and other clever tricks. \ * Essentially, data can be encrypted in arbitrary sized \ * chunks, although decryption must use the same chunks. \ */ \ \ -void pre ## _cbcdecrypt(pre ## _cbcctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ -{ \ - const octet *s = src; \ - octet *d = dest; \ - \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) \ - return; \ - \ - /* --- Extra magical case for a short block --- * \ - * \ - * Encrypt the IV, then exclusive-or the ciphertext with the octets \ - * of the encrypted IV, shifting ciphertext octets in instead. This \ - * basically switches over to CFB. \ - */ \ - \ - if (sz < PRE ## _BLKSZ) { \ - octet b[PRE ## _BLKSZ], c[PRE ## _BLKSZ]; \ - unsigned i; \ - \ - pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \ - BLKC_STORE(PRE, b, ctx->iv); \ - for (i = 0; i < sz; i++) { \ - register octet x = s[i]; \ - d[i] = b[i] ^ x; \ - c[i] = x; \ - } \ - memmove(b, b + sz, PRE ## _BLKSZ - sz); \ - memcpy(b + PRE ## _BLKSZ - sz, c, sz); \ - BLKC_LOAD(PRE, ctx->iv, b); \ - return; \ - } \ - \ - /* --- Do the main chunk of decryption --- * \ - * \ - * This will do the whole lot if it's a whole number of blocks. For \ - * each block, decrypt, XOR it with the previous ciphertext in @iv@, \ - * and keep a copy of the ciphertext for the next block. \ - */ \ +extern void pre##_cbcdecrypt(pre##_cbcctx */*ctx*/, \ + const void */*src*/, void */*dest*/, \ + size_t /*sz*/); \ \ - while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \ - uint32 b[PRE ## _BLKSZ / 4], niv[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, niv, s); \ - pre ## _dblk(&ctx->ctx, niv, b); \ - BLKC_XSTORE(PRE, d, b, ctx->iv); \ - BLKC_MOVE(PRE, ctx->iv, niv); \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - sz -= PRE ## _BLKSZ; \ - } \ +/* --- Generic cipher interface --- */ \ \ - /* --- Do the tail-end block and bit-left-over --- * \ - * \ - * This isn't very efficient. That shouldn't matter much. \ - */ \ - \ - if (sz) { \ - octet b[PRE ## _BLKSZ]; \ - uint32 bk[PRE ## _BLKSZ / 4], niv[PRE ## _BLKSZ / 4]; \ - unsigned i; \ - \ - /* --- Let @sz@ be the size of the partial block --- */ \ - \ - sz -= PRE ## _BLKSZ; \ - \ - /* --- First stage --- * \ - * \ - * Take the complete ciphertext block, and decrypt it. This block \ - * is carried over for the next encryption operation. \ - */ \ - \ - BLKC_LOAD(PRE, niv, s); \ - pre ## _dblk(&ctx->ctx, niv, bk); \ - \ - /* --- Second stage --- * \ - * \ - * XORing the first few bytes of this with the partial ciphertext \ - * block recovers the partial plaintext block. At the same time, \ - * write the partial ciphertext block's contents in ready for stage \ - * three. \ - */ \ - \ - BLKC_STORE(PRE, b, bk); \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - for (i = 0; i < sz; i++) { \ - register octet x = s[i]; \ - d[i] = b[i] ^ x; \ - b[i] = x; \ - } \ - \ - /* --- Third stage --- * \ - * \ - * Decrypt the block we've got left, and XOR with the initial IV to \ - * recover the complete plaintext block. \ - */ \ - \ - BLKC_LOAD(PRE, bk, b); \ - pre ## _dblk(&ctx->ctx, bk, bk); \ - BLKC_XSTORE(PRE, d - PRE ## _BLKSZ, bk, ctx->iv); \ - BLKC_MOVE(PRE, ctx->iv, niv); \ - } \ - \ - /* --- Done --- */ \ - \ - return; \ -} \ - \ -CBC_TEST(PRE, pre) - -/*----- Test rig ----------------------------------------------------------*/ - -#ifdef TEST_RIG - -#include - -#include "daftstory.h" - -/* --- @CBC_TEST@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions - * - * Use: Standard test rig for CBC functions. - */ - -#define CBC_TEST(PRE, pre) \ - \ -/* --- Initial plaintext for the test --- */ \ - \ -static const octet text[] = TEXT; \ - \ -/* --- Key and IV to use --- */ \ - \ -static const octet key[] = KEY; \ -static const octet iv[] = IV; \ - \ -/* --- Buffers for encryption and decryption output --- */ \ - \ -static octet ct[sizeof(text)]; \ -static octet pt[sizeof(text)]; \ - \ -static void hexdump(const octet *p, size_t sz) \ -{ \ - const octet *q = p + sz; \ - for (sz = 0; p < q; p++, sz++) { \ - printf("%02x", *p); \ - if ((sz + 1) % PRE ## _BLKSZ == 0) \ - putchar(':'); \ - } \ -} \ - \ -int main(void) \ -{ \ - size_t sz = 0, rest; \ - pre ## _cbcctx ctx; \ - pre ## _ctx k; \ - int status = 0; \ - int done = 0; \ - \ - size_t keysz = PRE ## _KEYSZ ? \ - PRE ## _KEYSZ : strlen((const char *)key); \ - \ - fputs(#pre "-cbc: ", stdout); \ - \ - pre ## _init(&k, key, keysz); \ - pre ## _cbcsetkey(&ctx, &k); \ - \ - while (sz <= sizeof(text)) { \ - rest = sizeof(text) - sz; \ - memcpy(ct, text, sizeof(text)); \ - pre ## _cbcsetiv(&ctx, iv); \ - pre ## _cbcencrypt(&ctx, ct, ct, sz); \ - pre ## _cbcencrypt(&ctx, ct + sz, ct + sz, rest); \ - memcpy(pt, ct, sizeof(text)); \ - pre ## _cbcsetiv(&ctx, iv); \ - pre ## _cbcdecrypt(&ctx, pt, pt, sz); \ - pre ## _cbcdecrypt(&ctx, pt + sz, pt + sz, rest); \ - if (memcmp(pt, text, sizeof(text)) == 0) { \ - done++; \ - if (sizeof(text) < 40 || done % 8 == 0) \ - fputc('.', stdout); \ - if (done % 480 == 0) \ - fputs("\n\t", stdout); \ - fflush(stdout); \ - } else { \ - printf("\nError (sz = %lu)\n", (unsigned long)sz); \ - status = 1; \ - printf("\tplaintext = "); hexdump(text, sz); \ - printf(", "); hexdump(text + sz, rest); \ - fputc('\n', stdout); \ - printf("\tciphertext = "); hexdump(ct, sz); \ - printf(", "); hexdump(ct + sz, rest); \ - fputc('\n', stdout); \ - printf("\trecovered text = "); hexdump(pt, sz); \ - printf(", "); hexdump(pt + sz, rest); \ - fputc('\n', stdout); \ - fputc('\n', stdout); \ - } \ - if (sz < 63) \ - sz++; \ - else \ - sz += 9; \ - } \ - \ - fputs(status ? " failed\n" : " ok\n", stdout); \ - return (status); \ -} - -#else -# define CBC_TEST(PRE, pre) -#endif +extern const gccipher pre##_cbc; /*----- That's all, folks -------------------------------------------------*/ diff --git a/cfb-def.h b/cfb-def.h new file mode 100644 index 0000000..85d95db --- /dev/null +++ b/cfb-def.h @@ -0,0 +1,499 @@ +/* -*-c-*- + * + * $Id: cfb-def.h,v 1.1 1999/12/10 23:16:39 mdw Exp $ + * + * Definitions for ciphertext feedback mode + * + * (c) 1999 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: cfb-def.h,v $ + * Revision 1.1 1999/12/10 23:16:39 mdw + * Split mode macros into interface and implementation. + * + */ + +#ifndef CATACOMB_CFB_DEF_H +#define CATACOMB_CFB_DEF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include + +#include +#include + +#ifndef CATACOMB_BLKC_H +# include "blkc.h" +#endif + +#ifndef CATACOMB_GCIPHER_H +# include "gcipher.h" +#endif + +#ifndef CATACOMB_PARANOIA_H +# include "paranoia.h" +#endif + +/*----- Macros ------------------------------------------------------------*/ + +/* --- @CFB_DEF@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher + * + * Use: Creates an implementation for CFB mode. + */ + +#define CFB_DEF(PRE, pre) \ + \ +/* --- @pre_cfbgetiv@ --- * \ + * \ + * Arguments: @const pre_cfbctx *ctx@ = pointer to CFB context block \ + * @void *iv#@ = pointer to output data block \ + * \ + * Returns: --- \ + * \ + * Use: Reads the currently set IV. Reading and setting an IV \ + * is not transparent to the cipher. It will add a `step' \ + * which must be matched by a similar operation during \ + * decryption. \ + */ \ + \ +void pre##_cfbgetiv(const pre##_cfbctx *ctx, void *iv) \ +{ \ + octet *p = iv; \ + int off = ctx->off; \ + int rest = PRE##_BLKSZ - off; \ + memcpy(p, ctx->iv + off, rest); \ + memcpy(p + rest, ctx->iv, off); \ +} \ + \ +/* --- @pre_cfbsetiv@ --- * \ + * \ + * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \ + * @cnost void *iv@ = pointer to IV to set \ + * \ + * Returns: --- \ + * \ + * Use: Sets the IV to use for subsequent encryption. \ + */ \ + \ +void pre##_cfbsetiv(pre##_cfbctx *ctx, const void *iv) \ +{ \ + uint32 niv[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, niv, iv); \ + pre##_eblk(&ctx->ctx, niv, niv); \ + BLKC_STORE(PRE, ctx->iv, niv); \ + ctx->off = 0; \ +} \ + \ +/* --- @pre_cfbbdry@ --- * \ + * \ + * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \ + * \ + * Returns: --- \ + * \ + * Use: Inserts a boundary during encryption. Successful \ + * decryption must place a similar boundary. \ + */ \ + \ +void pre##_cfbbdry(pre##_cfbctx *ctx) \ +{ \ + octet iv[PRE##_BLKSZ]; \ + pre##_cfbgetiv(ctx, iv); \ + pre##_cfbsetiv(ctx, iv); \ + BURN(iv); \ +} \ + \ +/* --- @pre_cfbsetkey@ --- * \ + * \ + * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \ + * @const pre_ctx *k@ = pointer to cipher context \ + * \ + * Returns: --- \ + * \ + * Use: Sets the CFB context to use a different cipher key. \ + */ \ + \ +void pre##_cfbsetkey(pre##_cfbctx *ctx, const pre##_ctx *k) \ +{ \ + ctx->ctx = *k; \ +} \ + \ +/* --- @pre_cfbinit@ --- * \ + * \ + * Arguments: @pre_cfbctx *ctx@ = pointer to cipher context \ + * @const void *key@ = pointer to the key buffer \ + * @size_t sz@ = size of the key \ + * @const void *iv@ = pointer to initialization vector \ + * \ + * Returns: --- \ + * \ + * Use: Initializes a CFB context ready for use. You should \ + * ensure that the IV chosen is unique: reusing an IV will \ + * compromise the security of at least the first block \ + * encrypted. This is equivalent to calls to @pre_init@, \ + * @pre_cfbsetkey@ and @pre_cfbsetiv@. \ + */ \ + \ +void pre##_cfbinit(pre##_cfbctx *ctx, \ + const void *key, size_t sz, \ + const void *iv) \ +{ \ + static octet zero[PRE##_BLKSZ] = { 0 }; \ + pre##_init(&ctx->ctx, key, sz); \ + pre##_cfbsetiv(ctx, iv ? iv : zero); \ +} \ + \ +/* --- @pre_cfbencrypt@ --- * \ + * \ + * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \ + * @const void *src@ = pointer to source data \ + * @void *dest@ = pointer to destination data \ + * @size_t sz@ = size of block to be encrypted \ + * \ + * Returns: --- \ + * \ + * Use: Encrypts a block with a block cipher in CFB mode. The \ + * input block may be arbitrary in size. CFB mode is not \ + * sensitive to block boundaries. \ + */ \ + \ +void pre##_cfbencrypt(pre##_cfbctx *ctx, \ + const void *src, void *dest, \ + size_t sz) \ +{ \ + const octet *s = src; \ + octet *d = dest; \ + int off = ctx->off; \ + \ + /* --- Empty blocks are trivial --- */ \ + \ + if (!sz) \ + return; \ + \ + /* --- If I can deal with the block from my buffer, do that --- */ \ + \ + if (sz < PRE##_BLKSZ - off) \ + goto small; \ + \ + /* --- Finish off what's left in my buffer --- */ \ + \ + while (off < PRE##_BLKSZ) { \ + register octet x = *s++; \ + *d++ = ctx->iv[off++] ^= x; \ + sz--; \ + } \ + \ + /* --- Main encryption loop --- */ \ + \ + { \ + uint32 iv[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, iv, ctx->iv); \ + \ + for (;;) { \ + pre##_eblk(&ctx->ctx, iv, iv); \ + if (sz < PRE##_BLKSZ) \ + break; \ + BLKC_XLOAD(PRE, iv, s); \ + BLKC_STORE(PRE, d, iv); \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + sz -= PRE##_BLKSZ; \ + } \ + off = 0; \ + BLKC_STORE(PRE, ctx->iv, iv); \ + } \ + \ + /* --- Tidying up the tail end --- */ \ + \ + if (sz) { \ + small: \ + do { \ + register octet x = *s++; \ + *d++ = ctx->iv[off++] ^= x; \ + sz--; \ + } while (sz); \ + } \ + \ + /* --- Done --- */ \ + \ + ctx->off = off; \ + return; \ +} \ + \ +/* --- @pre_cfbencrypt@ --- * \ + * \ + * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \ + * @const void *src@ = pointer to source data \ + * @void *dest@ = pointer to destination data \ + * @size_t sz@ = size of block to be encrypted \ + * \ + * Returns: --- \ + * \ + * Use: Decrypts a block with a block cipher in CFB mode. The \ + * input block may be arbitrary in size. CFB mode is not \ + * sensitive to block boundaries. \ + */ \ + \ +void pre##_cfbdecrypt(pre##_cfbctx *ctx, \ + const void *src, void *dest, \ + size_t sz) \ +{ \ + const octet *s = src; \ + octet *d = dest; \ + int off = ctx->off; \ + \ + /* --- Empty blocks are trivial --- */ \ + \ + if (!sz) \ + return; \ + \ + /* --- If I can deal with the block from my buffer, do that --- */ \ + \ + if (sz < PRE##_BLKSZ - off) \ + goto small; \ + \ + /* --- Finish off what's left in my buffer --- */ \ + \ + while (off < PRE##_BLKSZ) { \ + register octet x = *s++; \ + *d++ = ctx->iv[off] ^ x; \ + ctx->iv[off++] = x; \ + sz--; \ + } \ + \ + /* --- Main encryption loop --- */ \ + \ + { \ + uint32 iv[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, iv, ctx->iv); \ + \ + for (;;) { \ + uint32 x[PRE##_BLKSZ / 4]; \ + pre##_eblk(&ctx->ctx, iv, iv); \ + if (sz < PRE##_BLKSZ) \ + break; \ + BLKC_LOAD(PRE, x, s); \ + BLKC_XSTORE(PRE, d, iv, x); \ + BLKC_MOVE(PRE, iv, x); \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + sz -= PRE##_BLKSZ; \ + } \ + off = 0; \ + BLKC_STORE(PRE, ctx->iv, iv); \ + } \ + \ + /* --- Tidying up the tail end --- */ \ + \ + if (sz) { \ + small: \ + do { \ + register octet x = *s++; \ + *d++ = ctx->iv[off] ^ x; \ + ctx->iv[off++] = x; \ + sz--; \ + } while (sz); \ + } \ + \ + /* --- Done --- */ \ + \ + ctx->off = off; \ + return; \ +} \ + \ +/* --- Generic cipher interface --- */ \ + \ +static const gcipher_ops gops; \ + \ +typedef struct gctx { \ + gcipher c; \ + pre##_cfbctx k; \ +} gctx; \ + \ +static gcipher *ginit(const void *k, size_t sz) \ +{ \ + gctx *g = CREATE(gctx); \ + g->c.ops = &gops; \ + pre##_cfbinit(&g->k, k, sz, 0); \ + return (&g->c); \ +} \ + \ +static void gencrypt(gcipher *c, const void *s, void *t, size_t sz) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_cfbencrypt(&g->k, s, t, sz); \ +} \ + \ +static void gdecrypt(gcipher *c, const void *s, void *t, size_t sz) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_cfbdecrypt(&g->k, s, t, sz); \ +} \ + \ +static void gdestroy(gcipher *c) \ +{ \ + gctx *g = (gctx *)c; \ + DESTROY(g); \ +} \ + \ +static void gsetiv(gcipher *c, const void *iv) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_cfbsetiv(&g->k, iv); \ +} \ + \ +static void gbdry(gcipher *c) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_cfbbdry(&g->k); \ +} \ + \ +static const gcipher_ops gops = { \ + &pre##_cfb.b, \ + gencrypt, gdecrypt, gdestroy, gsetiv, gbdry \ +}; \ + \ +const gccipher pre##_cfb = { \ + { #pre "-cfb", PRE##_KEYSZ, PRE##_BLKSZ }, \ + ginit \ +}; \ + \ +CFB_TEST(PRE, pre) + +/*----- Test rig ----------------------------------------------------------*/ + +#ifdef TEST_RIG + +#include + +#include "daftstory.h" + +/* --- @CFB_TEST@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions + * + * Use: Standard test rig for CFB functions. + */ + +#define CFB_TEST(PRE, pre) \ + \ +/* --- Initial plaintext for the test --- */ \ + \ +static const octet text[] = TEXT; \ + \ +/* --- Key and IV to use --- */ \ + \ +static const octet key[] = KEY; \ +static const octet iv[] = IV; \ + \ +/* --- Buffers for encryption and decryption output --- */ \ + \ +static octet ct[sizeof(text)]; \ +static octet pt[sizeof(text)]; \ + \ +static void hexdump(const octet *p, size_t sz) \ +{ \ + const octet *q = p + sz; \ + for (sz = 0; p < q; p++, sz++) { \ + printf("%02x", *p); \ + if ((sz + 1) % PRE##_BLKSZ == 0) \ + putchar(':'); \ + } \ +} \ + \ +int main(void) \ +{ \ + size_t sz = 0, rest; \ + pre##_cfbctx ctx; \ + int status = 0; \ + int done = 0; \ + pre##_ctx k; \ + \ + size_t keysz = PRE##_KEYSZ ? \ + PRE##_KEYSZ : strlen((const char *)key); \ + \ + fputs(#pre "-cfb: ", stdout); \ + \ + pre##_init(&k, key, keysz); \ + pre##_cfbsetkey(&ctx, &k); \ + \ + while (sz <= sizeof(text)) { \ + rest = sizeof(text) - sz; \ + memcpy(ct, text, sizeof(text)); \ + pre##_cfbsetiv(&ctx, iv); \ + pre##_cfbencrypt(&ctx, ct, ct, sz); \ + pre##_cfbencrypt(&ctx, ct + sz, ct + sz, rest); \ + memcpy(pt, ct, sizeof(text)); \ + pre##_cfbsetiv(&ctx, iv); \ + pre##_cfbdecrypt(&ctx, pt, pt, rest); \ + pre##_cfbdecrypt(&ctx, pt + rest, pt + rest, sz); \ + if (memcmp(pt, text, sizeof(text)) == 0) { \ + done++; \ + if (sizeof(text) < 40 || done % 8 == 0) \ + fputc('.', stdout); \ + if (done % 480 == 0) \ + fputs("\n\t", stdout); \ + fflush(stdout); \ + } else { \ + printf("\nError (sz = %lu)\n", (unsigned long)sz); \ + status = 1; \ + printf("\tplaintext = "); hexdump(text, sz); \ + printf(", "); hexdump(text + sz, rest); \ + fputc('\n', stdout); \ + printf("\tciphertext = "); hexdump(ct, sz); \ + printf(", "); hexdump(ct + sz, rest); \ + fputc('\n', stdout); \ + printf("\trecovered text = "); hexdump(pt, sz); \ + printf(", "); hexdump(pt + sz, rest); \ + fputc('\n', stdout); \ + fputc('\n', stdout); \ + } \ + if (sz < 63) \ + sz++; \ + else \ + sz += 9; \ + } \ + \ + fputs(status ? " failed\n" : " ok\n", stdout); \ + return (status); \ +} + +#else +# define CFB_TEST(PRE, pre) +#endif + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/cfb.h b/cfb.h index 0719934..3f95dc9 100644 --- a/cfb.h +++ b/cfb.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: cfb.h,v 1.1 1999/09/03 08:41:11 mdw Exp $ + * $Id: cfb.h,v 1.2 1999/12/10 23:16:39 mdw Exp $ * * Ciphertext feedback for block ciphers * @@ -30,13 +30,16 @@ /*----- Revision history --------------------------------------------------* * * $Log: cfb.h,v $ + * Revision 1.2 1999/12/10 23:16:39 mdw + * Split mode macros into interface and implementation. + * * Revision 1.1 1999/09/03 08:41:11 mdw * Initial import. * */ -#ifndef CFB_H -#define CFB_H +#ifndef CATACOMB_CFB_H +#define CATACOMB_CFB_H #ifdef __cplusplus extern "C" { @@ -44,16 +47,12 @@ /*----- Header files ------------------------------------------------------*/ -#include +#include #include -#ifndef BLKC_H -# include "blkc.h" -#endif - -#ifndef PARANOIA_H -# include "paranoia.h" +#ifndef CATACOMB_GCIPHER_H +# include "gcipher.h" #endif /*----- Data structures ---------------------------------------------------*/ @@ -67,44 +66,13 @@ #define CFB_DECL(PRE, pre) \ \ -typedef struct pre ## _cfbctx { \ - pre ## _ctx ctx; /* Underlying cipher context */ \ - int off; /* Offset into @iv@ buffer */ \ - octet iv[PRE ## _BLKSZ]; /* Previous ciphertext or IV */ \ -} pre ## _cfbctx; \ - \ -extern void pre ## _cfbgetiv(const pre ## _cfbctx */*ctx*/, \ - void */*iv*/); \ - \ -extern void pre ## _cfbsetiv(pre ## _cfbctx */*ctx*/, \ - const void */*iv*/); \ - \ -extern void pre ## _cfbbdry(pre ## _cfbctx */*ctx*/); \ - \ -extern void pre ## _cfbsetkey(pre ## _cfbctx */*ctx*/, \ - const pre ## _ctx */*k*/); \ - \ -extern void pre ## _cfbinit(pre ## _cfbctx */*ctx*/, \ - const void */*key*/, size_t /*sz*/, \ - const void */*iv*/); \ +/* --- Ciphertext feedback context --- */ \ \ -extern void pre ## _cfbencrypt(pre ## _cfbctx */*ctx*/, \ - const void */*src*/, void */*dest*/, \ - size_t /*sz*/); \ - \ -extern void pre ## _cfbdecrypt(pre ## _cfbctx */*ctx*/, \ - const void */*src*/, void */*dest*/, \ - size_t /*sz*/); \ - - -/* --- @CFB_DEF@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher - * - * Use: Creates an implementation for CFB mode. - */ - -#define CFB_DEF(PRE, pre) \ +typedef struct pre##_cfbctx { \ + pre##_ctx ctx; /* Underlying cipher context */ \ + int off; /* Offset into @iv@ buffer */ \ + octet iv[PRE##_BLKSZ]; /* Previous ciphertext or IV */ \ +} pre##_cfbctx; \ \ /* --- @pre_cfbgetiv@ --- * \ * \ @@ -119,14 +87,8 @@ extern void pre ## _cfbdecrypt(pre ## _cfbctx */*ctx*/, \ * decryption. \ */ \ \ -void pre ## _cfbgetiv(const pre ## _cfbctx *ctx, void *iv) \ -{ \ - octet *p = iv; \ - int off = ctx->off; \ - int rest = PRE ## _BLKSZ - off; \ - memcpy(p, ctx->iv + off, rest); \ - memcpy(p + rest, ctx->iv, off); \ -} \ +extern void pre##_cfbgetiv(const pre##_cfbctx */*ctx*/, \ + void */*iv*/); \ \ /* --- @pre_cfbsetiv@ --- * \ * \ @@ -138,14 +100,8 @@ void pre ## _cfbgetiv(const pre ## _cfbctx *ctx, void *iv) \ * Use: Sets the IV to use for subsequent encryption. \ */ \ \ -void pre ## _cfbsetiv(pre ## _cfbctx *ctx, const void *iv) \ -{ \ - uint32 niv[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, niv, iv); \ - pre ## _eblk(&ctx->ctx, niv, niv); \ - BLKC_STORE(PRE, ctx->iv, niv); \ - ctx->off = 0; \ -} \ +extern void pre##_cfbsetiv(pre##_cfbctx */*ctx*/, \ + const void */*iv*/); \ \ /* --- @pre_cfbbdry@ --- * \ * \ @@ -157,13 +113,7 @@ void pre ## _cfbsetiv(pre ## _cfbctx *ctx, const void *iv) \ * decryption must place a similar boundary. \ */ \ \ -void pre ## _cfbbdry(pre ## _cfbctx *ctx) \ -{ \ - octet iv[PRE ## _BLKSZ]; \ - pre ## _cfbgetiv(ctx, iv); \ - pre ## _cfbsetiv(ctx, iv); \ - BURN(iv); \ -} \ +extern void pre##_cfbbdry(pre##_cfbctx */*ctx*/); \ \ /* --- @pre_cfbsetkey@ --- * \ * \ @@ -175,10 +125,8 @@ void pre ## _cfbbdry(pre ## _cfbctx *ctx) \ * Use: Sets the CFB context to use a different cipher key. \ */ \ \ -void pre ## _cfbsetkey(pre ## _cfbctx *ctx, const pre ## _ctx *k) \ -{ \ - ctx->ctx = *k; \ -} \ +extern void pre##_cfbsetkey(pre##_cfbctx */*ctx*/, \ + const pre##_ctx */*k*/); \ \ /* --- @pre_cfbinit@ --- * \ * \ @@ -196,14 +144,9 @@ void pre ## _cfbsetkey(pre ## _cfbctx *ctx, const pre ## _ctx *k) \ * @pre_cfbsetkey@ and @pre_cfbsetiv@. \ */ \ \ -void pre ## _cfbinit(pre ## _cfbctx *ctx, \ - const void *key, size_t sz, \ - const void *iv) \ -{ \ - static octet zero[PRE ## _BLKSZ] = { 0 }; \ - pre ## _init(&ctx->ctx, key, sz); \ - pre ## _cfbsetiv(ctx, iv ? iv : zero); \ -} \ +extern void pre##_cfbinit(pre##_cfbctx */*ctx*/, \ + const void */*key*/, size_t /*sz*/, \ + const void */*iv*/); \ \ /* --- @pre_cfbencrypt@ --- * \ * \ @@ -219,70 +162,11 @@ void pre ## _cfbinit(pre ## _cfbctx *ctx, \ * sensitive to block boundaries. \ */ \ \ -void pre ## _cfbencrypt(pre ## _cfbctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ -{ \ - const octet *s = src; \ - octet *d = dest; \ - int off = ctx->off; \ +extern void pre##_cfbencrypt(pre##_cfbctx */*ctx*/, \ + const void */*src*/, void */*dest*/, \ + size_t /*sz*/); \ \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) \ - return; \ - \ - /* --- If I can deal with the block from my buffer, do that --- */ \ - \ - if (sz < PRE ## _BLKSZ - off) \ - goto small; \ - \ - /* --- Finish off what's left in my buffer --- */ \ - \ - while (off < PRE ## _BLKSZ) { \ - register octet x = *s++; \ - *d++ = ctx->iv[off++] ^= x; \ - sz--; \ - } \ - \ - /* --- Main encryption loop --- */ \ - \ - { \ - uint32 iv[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, iv, ctx->iv); \ - \ - for (;;) { \ - pre ## _eblk(&ctx->ctx, iv, iv); \ - if (sz < PRE ## _BLKSZ) \ - break; \ - BLKC_XLOAD(PRE, iv, s); \ - BLKC_STORE(PRE, d, iv); \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - sz -= PRE ## _BLKSZ; \ - } \ - off = 0; \ - BLKC_STORE(PRE, ctx->iv, iv); \ - } \ - \ - /* --- Tidying up the tail end --- */ \ - \ - if (sz) { \ - small: \ - do { \ - register octet x = *s++; \ - *d++ = ctx->iv[off++] ^= x; \ - sz--; \ - } while (sz); \ - } \ - \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ -} \ - \ -/* --- @pre_cfbdecrypt@ --- * \ +/* --- @pre_cfbencrypt@ --- * \ * \ * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \ * @const void *src@ = pointer to source data \ @@ -291,182 +175,18 @@ void pre ## _cfbencrypt(pre ## _cfbctx *ctx, \ * \ * Returns: --- \ * \ - * Use: Encrypts a block with a block cipher in CFB mode, with \ - * ciphertext stealing and other clever tricks. \ - * Essentially, data can be encrypted in arbitrary sized \ - * chunks, although decryption must use the same chunks. \ + * Use: Decrypts a block with a block cipher in CFB mode. The \ + * input block may be arbitrary in size. CFB mode is not \ + * sensitive to block boundaries. \ */ \ \ -void pre ## _cfbdecrypt(pre ## _cfbctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ -{ \ - const octet *s = src; \ - octet *d = dest; \ - int off = ctx->off; \ - \ - /* --- Empty blocks are trivial --- */ \ +extern void pre##_cfbdecrypt(pre##_cfbctx */*ctx*/, \ + const void */*src*/, void */*dest*/, \ + size_t /*sz*/); \ \ - if (!sz) \ - return; \ +/* --- Generic cipher interface --- */ \ \ - /* --- If I can deal with the block from my buffer, do that --- */ \ - \ - if (sz < PRE ## _BLKSZ - off) \ - goto small; \ - \ - /* --- Finish off what's left in my buffer --- */ \ - \ - while (off < PRE ## _BLKSZ) { \ - register octet x = *s++; \ - *d++ = ctx->iv[off] ^ x; \ - ctx->iv[off++] = x; \ - sz--; \ - } \ - \ - /* --- Main encryption loop --- */ \ - \ - { \ - uint32 iv[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, iv, ctx->iv); \ - \ - for (;;) { \ - uint32 x[PRE ## _BLKSZ / 4]; \ - pre ## _eblk(&ctx->ctx, iv, iv); \ - if (sz < PRE ## _BLKSZ) \ - break; \ - BLKC_LOAD(PRE, x, s); \ - BLKC_XSTORE(PRE, d, iv, x); \ - BLKC_MOVE(PRE, iv, x); \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - sz -= PRE ## _BLKSZ; \ - } \ - off = 0; \ - BLKC_STORE(PRE, ctx->iv, iv); \ - } \ - \ - /* --- Tidying up the tail end --- */ \ - \ - if (sz) { \ - small: \ - do { \ - register octet x = *s++; \ - *d++ = ctx->iv[off] ^ x; \ - ctx->iv[off++] = x; \ - sz--; \ - } while (sz); \ - } \ - \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ -} \ - \ -CFB_TEST(PRE, pre) - -/*----- Test rig ----------------------------------------------------------*/ - -#ifdef TEST_RIG - -#include - -#include "daftstory.h" - -/* --- @CFB_TEST@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions - * - * Use: Standard test rig for CFB functions. - */ - -#define CFB_TEST(PRE, pre) \ - \ -/* --- Initial plaintext for the test --- */ \ - \ -static const octet text[] = TEXT; \ - \ -/* --- Key and IV to use --- */ \ - \ -static const octet key[] = KEY; \ -static const octet iv[] = IV; \ - \ -/* --- Buffers for encryption and decryption output --- */ \ - \ -static octet ct[sizeof(text)]; \ -static octet pt[sizeof(text)]; \ - \ -static void hexdump(const octet *p, size_t sz) \ -{ \ - const octet *q = p + sz; \ - for (sz = 0; p < q; p++, sz++) { \ - printf("%02x", *p); \ - if ((sz + 1) % PRE ## _BLKSZ == 0) \ - putchar(':'); \ - } \ -} \ - \ -int main(void) \ -{ \ - size_t sz = 0, rest; \ - pre ## _cfbctx ctx; \ - int status = 0; \ - int done = 0; \ - pre ## _ctx k; \ - \ - size_t keysz = PRE ## _KEYSZ ? \ - PRE ## _KEYSZ : strlen((const char *)key); \ - \ - fputs(#pre "-cfb: ", stdout); \ - \ - pre ## _init(&k, key, keysz); \ - pre ## _cfbsetkey(&ctx, &k); \ - \ - while (sz <= sizeof(text)) { \ - rest = sizeof(text) - sz; \ - memcpy(ct, text, sizeof(text)); \ - pre ## _cfbsetiv(&ctx, iv); \ - pre ## _cfbencrypt(&ctx, ct, ct, sz); \ - pre ## _cfbencrypt(&ctx, ct + sz, ct + sz, rest); \ - memcpy(pt, ct, sizeof(text)); \ - pre ## _cfbsetiv(&ctx, iv); \ - pre ## _cfbdecrypt(&ctx, pt, pt, rest); \ - pre ## _cfbdecrypt(&ctx, pt + rest, pt + rest, sz); \ - if (memcmp(pt, text, sizeof(text)) == 0) { \ - done++; \ - if (sizeof(text) < 40 || done % 8 == 0) \ - fputc('.', stdout); \ - if (done % 480 == 0) \ - fputs("\n\t", stdout); \ - fflush(stdout); \ - } else { \ - printf("\nError (sz = %lu)\n", (unsigned long)sz); \ - status = 1; \ - printf("\tplaintext = "); hexdump(text, sz); \ - printf(", "); hexdump(text + sz, rest); \ - fputc('\n', stdout); \ - printf("\tciphertext = "); hexdump(ct, sz); \ - printf(", "); hexdump(ct + sz, rest); \ - fputc('\n', stdout); \ - printf("\trecovered text = "); hexdump(pt, sz); \ - printf(", "); hexdump(pt + sz, rest); \ - fputc('\n', stdout); \ - fputc('\n', stdout); \ - } \ - if (sz < 63) \ - sz++; \ - else \ - sz += 9; \ - } \ - \ - fputs(status ? " failed\n" : " ok\n", stdout); \ - return (status); \ -} - -#else -# define CFB_TEST(PRE, pre) -#endif +extern const gccipher pre##_cfb; /*----- That's all, folks -------------------------------------------------*/ diff --git a/ecb-def.h b/ecb-def.h new file mode 100644 index 0000000..0f49763 --- /dev/null +++ b/ecb-def.h @@ -0,0 +1,462 @@ +/* -*-c-*- + * + * $Id: ecb-def.h,v 1.1 1999/12/10 23:16:39 mdw Exp $ + * + * Definitions electronic code book mode + * + * (c) 1999 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: ecb-def.h,v $ + * Revision 1.1 1999/12/10 23:16:39 mdw + * Split mode macros into interface and implementation. + * + */ + +#ifndef CATACOMB_ECB_DEF_H +#define CATACOMB_ECB_DEF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include +#include + +#include +#include + +#ifndef CATACOMB_BLKC_H +# include "blkc.h" +#endif + +#ifndef CATACOMB_GCIPHER_H +# include "gcipher.h" +#endif + +/*----- Macros ------------------------------------------------------------*/ + +/* --- @ECB_DEF@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher + * + * Use: Creates an implementation for ECB stealing mode. + */ + +#define ECB_DEF(PRE, pre) \ + \ +/* --- @pre_ecbsetkey@ --- * \ + * \ + * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \ + * @const pre_ctx *k@ = pointer to cipher context \ + * \ + * Returns: --- \ + * \ + * Use: Sets the ECB context to use a different cipher key. \ + */ \ + \ +void pre##_ecbsetkey(pre##_ecbctx *ctx, const pre##_ctx *k) \ +{ \ + ctx->ctx = *k; \ +} \ + \ +/* --- @pre_ecbinit@ --- * \ + * \ + * Arguments: @pre_ecbctx *ctx@ = pointer to cipher context \ + * @const void *key@ = pointer to the key buffer \ + * @size_t sz@ = size of the key \ + * @const void *iv@ = pointer to initialization vector \ + * \ + * Returns: --- \ + * \ + * Use: Initializes an ECB context ready for use. This is \ + * equivalent to calls to @pre_init@ and @pre_setkey@. \ + */ \ + \ +void pre##_ecbinit(pre##_ecbctx *ctx, \ + const void *key, size_t sz, \ + const void *iv) \ +{ \ + pre##_init(&ctx->ctx, key, sz); \ +} \ + \ +/* --- @pre_ecbencrypt@ --- * \ + * \ + * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \ + * @const void *src@ = pointer to source data \ + * @void *dest@ = pointer to destination data \ + * @size_t sz@ = size of block to be encrypted \ + * \ + * Returns: --- \ + * \ + * Use: Encrypts a block with a block cipher in ECB mode, with \ + * ciphertext stealing and other clever tricks. \ + * Essentially, data can be encrypted in arbitrary sized \ + * chunks, although decryption must use the same chunks. \ + */ \ + \ +void pre##_ecbencrypt(pre##_ecbctx *ctx, \ + const void *src, void *dest, \ + size_t sz) \ +{ \ + const octet *s = src; \ + octet *d = dest; \ + \ + /* --- Empty blocks are trivial --- */ \ + \ + if (!sz) \ + return; \ + \ + /* --- Short blocks aren't allowed in ECB --- * \ + * \ + * There's absolutely nothing secure I can do with them. \ + */ \ + \ + assert(((void)"ECB must have at least one whole block to work with", \ + sz >= PRE##_BLKSZ)); \ + \ + /* --- Do the main chunk of encryption --- * \ + * \ + * This will do the whole lot if it's a whole number of blocks. Just \ + * give each block to the cipher in turn. This is trivial. \ + * Hopefully... \ + */ \ + \ + while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) { \ + uint32 x[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, x, s); \ + pre##_eblk(&ctx->ctx, x, x); \ + BLKC_STORE(PRE, d, x); \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + sz -= PRE##_BLKSZ; \ + } \ + \ + /* --- Do the tail-end block and bit-left-over --- * \ + * \ + * This isn't very efficient. That shouldn't matter much. \ + */ \ + \ + if (sz) { \ + uint32 x[PRE##_BLKSZ / 4]; \ + octet b[PRE##_BLKSZ]; \ + unsigned i; \ + \ + /* --- Let @sz@ be the size of the partial block --- */ \ + \ + sz -= PRE##_BLKSZ; \ + \ + /* --- First stage --- * \ + * \ + * Read in the current block, and encrypt it. The first part of \ + * the result is the partial ciphertext block. Don't write that \ + * out yet, because I've not read the partial plaintext block. \ + */ \ + \ + BLKC_LOAD(PRE, x, s); \ + pre##_eblk(&ctx->ctx, x, x); \ + BLKC_STORE(PRE, b, x); \ + \ + /* --- Second stage --- * \ + * \ + * Now move in the partial plaintext block, writing out the \ + * ciphertext as I go. Then encrypt, and write the complete \ + * ciphertext block. \ + */ \ + \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + for (i = 0; i < sz; i++) { \ + register octet y = b[i]; \ + b[i] = s[i]; \ + d[i] = y; \ + } \ + BLKC_LOAD(PRE, x, b); \ + pre##_eblk(&ctx->ctx, x, x); \ + BLKC_STORE(PRE, d - PRE##_BLKSZ, x); \ + } \ + \ + /* --- Done --- */ \ + \ + return; \ +} \ + \ +/* --- @pre_ecbdecrypt@ --- * \ + * \ + * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \ + * @const void *src@ = pointer to source data \ + * @void *dest@ = pointer to destination data \ + * @size_t sz@ = size of block to be encrypted \ + * \ + * Returns: --- \ + * \ + * Use: Decrypts a block with a block cipher in ECB mode, with \ + * ciphertext stealing and other clever tricks. \ + * Essentially, data can be encrypted in arbitrary sized \ + * chunks, although decryption must use the same chunks. \ + */ \ + \ +void pre##_ecbdecrypt(pre##_ecbctx *ctx, \ + const void *src, void *dest, \ + size_t sz) \ +{ \ + const octet *s = src; \ + octet *d = dest; \ + \ + /* --- Empty blocks are trivial --- */ \ + \ + if (!sz) \ + return; \ + \ + /* --- Short blocks aren't allowed in ECB --- * \ + * \ + * There's absolutely nothing secure I can do with them. \ + */ \ + \ + assert(((void)"ECB must have at least one whole block to work with", \ + sz >= PRE##_BLKSZ)); \ + \ + /* --- Do the main chunk of decryption --- * \ + * \ + * This will do the whole lot if it's a whole number of blocks. \ + * Each block is just handed to the block cipher in turn. \ + */ \ + \ + while (sz >= 2 * PRE##_BLKSZ || sz == PRE##_BLKSZ) { \ + uint32 x[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, x, s); \ + pre##_dblk(&ctx->ctx, x, x); \ + BLKC_STORE(PRE, d, x); \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + sz -= PRE##_BLKSZ; \ + } \ + \ + /* --- Do the tail-end block and bit-left-over --- * \ + * \ + * This isn't very efficient. That shouldn't matter much. \ + */ \ + \ + if (sz) { \ + uint32 x[PRE##_BLKSZ / 4]; \ + octet b[PRE##_BLKSZ]; \ + unsigned i; \ + \ + /* --- Let @sz@ be the size of the partial block --- */ \ + \ + sz -= PRE##_BLKSZ; \ + \ + /* --- First stage --- * \ + * \ + * Take the complete ciphertext block, and decrypt it. This block \ + * is carried over for the next encryption operation. \ + */ \ + \ + BLKC_LOAD(PRE, x, s); \ + pre##_dblk(&ctx->ctx, x, x); \ + BLKC_STORE(PRE, b, x); \ + \ + /* --- Second stage --- * \ + * \ + * The first few bytes are the partial plaintext block. Write that \ + * and replace with the partial ciphertext block. Then decrypt \ + * what's left as the complete plaintext. \ + */ \ + \ + s += PRE##_BLKSZ; \ + d += PRE##_BLKSZ; \ + for (i = 0; i < sz; i++) { \ + register octet y = s[i]; \ + d[i] = b[i]; \ + b[i] = y; \ + } \ + BLKC_LOAD(PRE, x, b); \ + pre##_dblk(&ctx->ctx, x, x); \ + BLKC_STORE(PRE, d - PRE##_BLKSZ, x); \ + } \ + \ + /* --- Done --- */ \ + \ + return; \ +} \ + \ +/* --- Generic cipher interface --- */ \ + \ +static const gcipher_ops gops; \ + \ +typedef struct gctx { \ + gcipher c; \ + pre##_ecbctx k; \ +} gctx; \ + \ +static gcipher *ginit(const void *k, size_t sz) \ +{ \ + gctx *g = CREATE(gctx); \ + g->c.ops = &gops; \ + pre##_ecbinit(&g->k, k, sz, 0); \ + return (&g->c); \ +} \ + \ +static void gencrypt(gcipher *c, const void *s, void *t, size_t sz) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_ecbencrypt(&g->k, s, t, sz); \ +} \ + \ +static void gdecrypt(gcipher *c, const void *s, void *t, size_t sz) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_ecbdecrypt(&g->k, s, t, sz); \ +} \ + \ +static void gdestroy(gcipher *c) \ +{ \ + gctx *g = (gctx *)c; \ + DESTROY(g); \ +} \ + \ +static const gcipher_ops gops = { \ + &pre##_ecb.b, \ + gencrypt, gdecrypt, gdestroy, 0, 0 \ +}; \ + \ +const gccipher pre##_ecb = { \ + { #pre "-ecb", PRE##_KEYSZ, PRE##_BLKSZ }, \ + ginit \ +}; \ + \ +ECB_TEST(PRE, pre) + +/*----- Test rig ----------------------------------------------------------*/ + +#ifdef TEST_RIG + +#include + +#include "daftstory.h" + +/* --- @ECB_TEST@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions + * + * Use: Standard test rig for ECB functions. + */ + +#define ECB_TEST(PRE, pre) \ + \ +/* --- Initial plaintext for the test --- */ \ + \ +static const octet text[] = TEXT; \ + \ +/* --- Key and IV to use --- */ \ + \ +static const octet key[] = KEY; \ +static const octet iv[] = IV; \ + \ +/* --- Buffers for encryption and decryption output --- */ \ + \ +static octet ct[sizeof(text)]; \ +static octet pt[sizeof(text)]; \ + \ +static void hexdump(const octet *p, size_t sz) \ +{ \ + const octet *q = p + sz; \ + for (sz = 0; p < q; p++, sz++) { \ + printf("%02x", *p); \ + if ((sz + 1) % PRE##_BLKSZ == 0) \ + putchar(':'); \ + } \ +} \ + \ +int main(void) \ +{ \ + size_t sz = 0, rest; \ + pre##_ecbctx ctx; \ + int status = 0; \ + int done = 0; \ + \ + size_t keysz = PRE##_KEYSZ ? \ + PRE##_KEYSZ : strlen((const char *)key); \ + \ + fputs(#pre "-ecb: ", stdout); \ + \ + pre##_ecbinit(&ctx, key, keysz, iv); \ + \ + while (sz <= sizeof(text)) { \ + rest = sizeof(text) - sz; \ + if ((sz != 0 && sz < PRE##_BLKSZ) || \ + (rest != 0 && rest < PRE##_BLKSZ)) \ + goto next; \ + memcpy(ct, text, sizeof(text)); \ + pre##_ecbencrypt(&ctx, ct, ct, sz); \ + pre##_ecbencrypt(&ctx, ct + sz, ct + sz, rest); \ + memcpy(pt, ct, sizeof(text)); \ + pre##_ecbdecrypt(&ctx, pt, pt, sz); \ + pre##_ecbdecrypt(&ctx, pt + sz, pt + sz, rest); \ + if (memcmp(pt, text, sizeof(text)) == 0) { \ + done++; \ + if (sizeof(text) < 40 || done % 8 == 0) \ + fputc('.', stdout); \ + if (done % 480 == 0) \ + fputs("\n\t", stdout); \ + fflush(stdout); \ + } else { \ + printf("\nError (sz = %lu)\n", (unsigned long)sz); \ + status = 1; \ + printf("\tplaintext = "); hexdump(text, sz); \ + printf(", "); hexdump(text + sz, rest); \ + fputc('\n', stdout); \ + printf("\tciphertext = "); hexdump(ct, sz); \ + printf(", "); hexdump(ct + sz, rest); \ + fputc('\n', stdout); \ + printf("\trecovered text = "); hexdump(pt, sz); \ + printf(", "); hexdump(pt + sz, rest); \ + fputc('\n', stdout); \ + fputc('\n', stdout); \ + } \ + next: \ + if (sz < 63) \ + sz++; \ + else \ + sz += 9; \ + } \ + \ + fputs(status ? " failed\n" : " ok\n", stdout); \ + return (status); \ +} + +#else +# define ECB_TEST(PRE, pre) +#endif + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ecb.h b/ecb.h index 1027591..f5ce880 100644 --- a/ecb.h +++ b/ecb.h @@ -1,8 +1,8 @@ /* -*-c-*- * - * $Id: ecb.h,v 1.1 1999/09/03 08:41:12 mdw Exp $ + * $Id: ecb.h,v 1.2 1999/12/10 23:16:40 mdw Exp $ * - * Ciphertext block chaining for block ciphers + * Electronic code book for block ciphers * * (c) 1999 Straylight/Edgeware */ @@ -30,13 +30,16 @@ /*----- Revision history --------------------------------------------------* * * $Log: ecb.h,v $ + * Revision 1.2 1999/12/10 23:16:40 mdw + * Split mode macros into interface and implementation. + * * Revision 1.1 1999/09/03 08:41:12 mdw * Initial import. * */ -#ifndef ECB_H -#define ECB_H +#ifndef CATACOMB_ECB_H +#define CATACOMB_ECB_H #ifdef __cplusplus extern "C" { @@ -44,13 +47,10 @@ /*----- Header files ------------------------------------------------------*/ -#include -#include - -#include +#include -#ifndef BLKC_H -# include "blkc.h" +#ifndef CATACOMB_GCIPHER_H +# include "gcipher.h" #endif /*----- Macros ------------------------------------------------------------*/ @@ -64,33 +64,11 @@ #define ECB_DECL(PRE, pre) \ \ -typedef struct pre ## _ecbctx { \ - pre ## _ctx ctx; /* Underlying cipher context */ \ -} pre ## _ecbctx; \ - \ -extern void pre ## _ecbsetkey(pre ## _ecbctx */*ctx*/, \ - const pre ## _ctx */*k*/); \ +/* --- Electronic codebook context --- */ \ \ -extern void pre ## _ecbinit(pre ## _ecbctx */*ctx*/, \ - const void */*key*/, size_t /*sz*/, \ - const void */*iv*/); \ - \ -extern void pre ## _ecbencrypt(pre ## _ecbctx */*ctx*/, \ - const void */*src*/, void */*dest*/, \ - size_t /*sz*/); \ - \ -extern void pre ## _ecbdecrypt(pre ## _ecbctx */*ctx*/, \ - const void */*src*/, void */*dest*/, \ - size_t /*sz*/); \ - -/* --- @ECB_DEF@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher - * - * Use: Creates an implementation for ECB stealing mode. - */ - -#define ECB_DEF(PRE, pre) \ +typedef struct pre##_ecbctx { \ + pre##_ctx ctx; /* Underlying cipher context */ \ +} pre##_ecbctx; \ \ /* --- @pre_ecbsetkey@ --- * \ * \ @@ -102,10 +80,8 @@ extern void pre ## _ecbdecrypt(pre ## _ecbctx */*ctx*/, \ * Use: Sets the ECB context to use a different cipher key. \ */ \ \ -void pre ## _ecbsetkey(pre ## _ecbctx *ctx, const pre ## _ctx *k) \ -{ \ - ctx->ctx = *k; \ -} \ +extern void pre##_ecbsetkey(pre##_ecbctx */*ctx*/, \ + const pre##_ctx */*k*/); \ \ /* --- @pre_ecbinit@ --- * \ * \ @@ -120,12 +96,9 @@ void pre ## _ecbsetkey(pre ## _ecbctx *ctx, const pre ## _ctx *k) \ * equivalent to calls to @pre_init@ and @pre_setkey@. \ */ \ \ -void pre ## _ecbinit(pre ## _ecbctx *ctx, \ - const void *key, size_t sz, \ - const void *iv) \ -{ \ - pre ## _init(&ctx->ctx, key, sz); \ -} \ +extern void pre##_ecbinit(pre##_ecbctx */*ctx*/, \ + const void */*key*/, size_t /*sz*/, \ + const void */*iv*/); \ \ /* --- @pre_ecbencrypt@ --- * \ * \ @@ -142,91 +115,9 @@ void pre ## _ecbinit(pre ## _ecbctx *ctx, \ * chunks, although decryption must use the same chunks. \ */ \ \ -void pre ## _ecbencrypt(pre ## _ecbctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ -{ \ - const octet *s = src; \ - octet *d = dest; \ - \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) \ - return; \ - \ - /* --- Short blocks aren't allowed in ECB --- * \ - * \ - * There's absolutely nothing secure I can do with them. \ - */ \ - \ - assert(((void)"ECB must have at least one whole block to work with", \ - sz >= PRE ## _BLKSZ)); \ - \ - /* --- Do the main chunk of encryption --- * \ - * \ - * This will do the whole lot if it's a whole number of blocks. Just \ - * give each block to the cipher in turn. This is trivial. \ - * Hopefully... \ - */ \ - \ - while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \ - uint32 x[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, x, s); \ - pre ## _eblk(&ctx->ctx, x, x); \ - BLKC_STORE(PRE, d, x); \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - sz -= PRE ## _BLKSZ; \ - } \ - \ - /* --- Do the tail-end block and bit-left-over --- * \ - * \ - * This isn't very efficient. That shouldn't matter much. \ - */ \ - \ - if (sz) { \ - uint32 x[PRE ## _BLKSZ / 4]; \ - octet b[PRE ## _BLKSZ]; \ - unsigned i; \ - \ - /* --- Let @sz@ be the size of the partial block --- */ \ - \ - sz -= PRE ## _BLKSZ; \ - \ - /* --- First stage --- * \ - * \ - * Read in the current block, and encrypt it. The first part of \ - * the result is the partial ciphertext block. Don't write that \ - * out yet, because I've not read the partial plaintext block. \ - */ \ - \ - BLKC_LOAD(PRE, x, s); \ - pre ## _eblk(&ctx->ctx, x, x); \ - BLKC_STORE(PRE, b, x); \ - \ - /* --- Second stage --- * \ - * \ - * Now move in the partial plaintext block, writing out the \ - * ciphertext as I go. Then encrypt, and write the complete \ - * ciphertext block. \ - */ \ - \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - for (i = 0; i < sz; i++) { \ - register octet y = b[i]; \ - b[i] = s[i]; \ - d[i] = y; \ - } \ - BLKC_LOAD(PRE, x, b); \ - pre ## _eblk(&ctx->ctx, x, x); \ - BLKC_STORE(PRE, d - PRE ## _BLKSZ, x); \ - } \ - \ - /* --- Done --- */ \ - \ - return; \ -} \ +extern void pre##_ecbencrypt(pre##_ecbctx */*ctx*/, \ + const void */*src*/, void */*dest*/, \ + size_t /*sz*/); \ \ /* --- @pre_ecbdecrypt@ --- * \ * \ @@ -237,199 +128,19 @@ void pre ## _ecbencrypt(pre ## _ecbctx *ctx, \ * \ * Returns: --- \ * \ - * Use: Encrypts a block with a block cipher in ECB mode, with \ + * Use: Decrypts a block with a block cipher in ECB mode, with \ * ciphertext stealing and other clever tricks. \ * Essentially, data can be encrypted in arbitrary sized \ * chunks, although decryption must use the same chunks. \ */ \ \ -void pre ## _ecbdecrypt(pre ## _ecbctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ -{ \ - const octet *s = src; \ - octet *d = dest; \ - \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) \ - return; \ - \ - /* --- Short blocks aren't allowed in ECB --- * \ - * \ - * There's absolutely nothing secure I can do with them. \ - */ \ - \ - assert(((void)"ECB must have at least one whole block to work with", \ - sz >= PRE ## _BLKSZ)); \ - \ - /* --- Do the main chunk of decryption --- * \ - * \ - * This will do the whole lot if it's a whole number of blocks. \ - * Each block is just handed to the block cipher in turn. \ - */ \ - \ - while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \ - uint32 x[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, x, s); \ - pre ## _dblk(&ctx->ctx, x, x); \ - BLKC_STORE(PRE, d, x); \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - sz -= PRE ## _BLKSZ; \ - } \ +extern void pre##_ecbdecrypt(pre##_ecbctx */*ctx*/, \ + const void */*src*/, void */*dest*/, \ + size_t /*sz*/); \ \ - /* --- Do the tail-end block and bit-left-over --- * \ - * \ - * This isn't very efficient. That shouldn't matter much. \ - */ \ +/* --- Generic cipher interface --- */ \ \ - if (sz) { \ - uint32 x[PRE ## _BLKSZ / 4]; \ - octet b[PRE ## _BLKSZ]; \ - unsigned i; \ - \ - /* --- Let @sz@ be the size of the partial block --- */ \ - \ - sz -= PRE ## _BLKSZ; \ - \ - /* --- First stage --- * \ - * \ - * Take the complete ciphertext block, and decrypt it. This block \ - * is carried over for the next encryption operation. \ - */ \ - \ - BLKC_LOAD(PRE, x, s); \ - pre ## _dblk(&ctx->ctx, x, x); \ - BLKC_STORE(PRE, b, x); \ - \ - /* --- Second stage --- * \ - * \ - * The first few bytes are the partial plaintext block. Write that \ - * and replace with the partial ciphertext block. Then decrypt \ - * what's left as the complete plaintext. \ - */ \ - \ - s += PRE ## _BLKSZ; \ - d += PRE ## _BLKSZ; \ - for (i = 0; i < sz; i++) { \ - register octet y = s[i]; \ - d[i] = b[i]; \ - b[i] = y; \ - } \ - BLKC_LOAD(PRE, x, b); \ - pre ## _dblk(&ctx->ctx, x, x); \ - BLKC_STORE(PRE, d - PRE ## _BLKSZ, x); \ - } \ - \ - /* --- Done --- */ \ - \ - return; \ -} \ - \ -ECB_TEST(PRE, pre) - -/*----- Test rig ----------------------------------------------------------*/ - -#ifdef TEST_RIG - -#include - -#include "daftstory.h" - -/* --- @ECB_TEST@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions - * - * Use: Standard test rig for ECB functions. - */ - -#define ECB_TEST(PRE, pre) \ - \ -/* --- Initial plaintext for the test --- */ \ - \ -static const octet text[] = TEXT; \ - \ -/* --- Key and IV to use --- */ \ - \ -static const octet key[] = KEY; \ -static const octet iv[] = IV; \ - \ -/* --- Buffers for encryption and decryption output --- */ \ - \ -static octet ct[sizeof(text)]; \ -static octet pt[sizeof(text)]; \ - \ -static void hexdump(const octet *p, size_t sz) \ -{ \ - const octet *q = p + sz; \ - for (sz = 0; p < q; p++, sz++) { \ - printf("%02x", *p); \ - if ((sz + 1) % PRE ## _BLKSZ == 0) \ - putchar(':'); \ - } \ -} \ - \ -int main(void) \ -{ \ - size_t sz = 0, rest; \ - pre ## _ecbctx ctx; \ - int status = 0; \ - int done = 0; \ - \ - size_t keysz = PRE ## _KEYSZ ? \ - PRE ## _KEYSZ : strlen((const char *)key); \ - \ - fputs(#pre "-ecb: ", stdout); \ - \ - pre ## _ecbinit(&ctx, key, keysz, iv); \ - \ - while (sz <= sizeof(text)) { \ - rest = sizeof(text) - sz; \ - if ((sz != 0 && sz < PRE ## _BLKSZ) || \ - (rest != 0 && rest < PRE ## _BLKSZ)) \ - goto next; \ - memcpy(ct, text, sizeof(text)); \ - pre ## _ecbencrypt(&ctx, ct, ct, sz); \ - pre ## _ecbencrypt(&ctx, ct + sz, ct + sz, rest); \ - memcpy(pt, ct, sizeof(text)); \ - pre ## _ecbdecrypt(&ctx, pt, pt, sz); \ - pre ## _ecbdecrypt(&ctx, pt + sz, pt + sz, rest); \ - if (memcmp(pt, text, sizeof(text)) == 0) { \ - done++; \ - if (sizeof(text) < 40 || done % 8 == 0) \ - fputc('.', stdout); \ - if (done % 480 == 0) \ - fputs("\n\t", stdout); \ - fflush(stdout); \ - } else { \ - printf("\nError (sz = %lu)\n", (unsigned long)sz); \ - status = 1; \ - printf("\tplaintext = "); hexdump(text, sz); \ - printf(", "); hexdump(text + sz, rest); \ - fputc('\n', stdout); \ - printf("\tciphertext = "); hexdump(ct, sz); \ - printf(", "); hexdump(ct + sz, rest); \ - fputc('\n', stdout); \ - printf("\trecovered text = "); hexdump(pt, sz); \ - printf(", "); hexdump(pt + sz, rest); \ - fputc('\n', stdout); \ - fputc('\n', stdout); \ - } \ - next: \ - if (sz < 63) \ - sz++; \ - else \ - sz += 9; \ - } \ - \ - fputs(status ? " failed\n" : " ok\n", stdout); \ - return (status); \ -} - -#else -# define ECB_TEST(PRE, pre) -#endif +extern const gccipher pre##_ecb; /*----- That's all, folks -------------------------------------------------*/ diff --git a/genmodes b/genmodes index 48175ce..a69229a 100755 --- a/genmodes +++ b/genmodes @@ -7,7 +7,7 @@ for i in $baselist; do I=`echo "$i" | tr -d '\n' | tr a-z A-Z | tr -c a-zA-Z0-9 _` for j in $extlist; do J=`echo "$j" | tr -d '\n' | tr a-z A-Z | tr -c a-zA-Z0-9 _` - guard="${I}_${J}_H" + guard="CATACOMB_${I}_${J}_H" cat >$i-$j.h <$i-$j.c <count += _bsz; \ + /* --- Add on the size done so far --- * \ + * \ + * Messy, because trapping overflow is difficult when you don't know \ + * how many bits you've actually got. \ + */ \ + \ + { \ + uint32 _l = U32(_bsz), _h = (_bsz >> 16) >> 16; \ + _bctx->nh += _h; \ + _bctx->nl += _l; \ + if (_bctx->nl < _l || _bctx->nl & ~MASK32) \ + _bctx->nh++; \ + } \ \ /* --- Handle very small contributions --- */ \ \ @@ -144,8 +157,9 @@ #define HASH_MD5STRENGTH(PRE, pre, ictx) do { \ pre##_ctx *_mctx = (ictx); \ HASH_PAD(PRE, pre, _mctx, 0x80u, 0, 8); \ - STORE32_L(_mctx->buf + PRE##_BUFSZ - 8, _mctx->count << 3); \ - STORE32_L(_mctx->buf + PRE##_BUFSZ - 4, _mctx->count >> 29); \ + STORE32_L(_mctx->buf + PRE##_BUFSZ - 8, _mctx->nl << 3); \ + STORE32_L(_mctx->buf + PRE##_BUFSZ - 4, \ + (_mctx->nl >> 29) | (_mctx->nh << 3)); \ pre##_compress(_mctx, _mctx->buf); \ } while (0) diff --git a/hmac-def.h b/hmac-def.h new file mode 100644 index 0000000..3f96649 --- /dev/null +++ b/hmac-def.h @@ -0,0 +1,343 @@ +/* -*-c-*- + * + * $Id: hmac-def.h,v 1.1 1999/12/10 23:16:40 mdw Exp $ + * + * Definitions for HMAC and NMAC + * + * (c) 1999 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: hmac-def.h,v $ + * Revision 1.1 1999/12/10 23:16:40 mdw + * Split mode macros into interface and implementation. + * + */ + +#ifndef CATACOMB_HMAC_DEF_H +#define CATACOMB_HMAC_DEF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include +#include + +#include +#include + +#ifndef CATACOMB_GMAC_H +# include "gmac.h" +#endif + +#ifndef CATACOMB_PARANOIA_H +# include "paranoia.h" +#endif + +/*----- Macros ------------------------------------------------------------*/ + +/* --- @HMAC_DEF@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for the underlying hash function + * + * Use: Creates implementations for the HMAC and NMAC functions. + */ + +#define HMAC_DEF(PRE, pre) \ + \ +/* --- @pre_nmacinit@ --- * \ + * \ + * Arguments: @pre_macctx *key@ = pointer to a MAC key object \ + * @const void *ok@ = pointer to outer hash init vector \ + * @const void *ik@ = pointer to inner hash init vector \ + * \ + * Returns: --- \ + * \ + * Use: Initializes a MAC key for doing NMAC hashing. \ + */ \ + \ +void pre##_nmacinit(pre##_mackey *key, const void *ok, const void *ik) \ +{ \ + memcpy(key->ochain, ok, PRE##_HASHSZ); \ + memcpy(key->ichain, ik, PRE##_HASHSZ); \ + key->ocount = key->icount = 0; \ +} \ + \ +/* --- @pre_hmacinit@ --- * \ + * \ + * Arguments: @pre_mackey *key@ = pointer to MAC key object \ + * @const void *k@ = pointer to key to use \ + * @size_t sz@ = size of key data \ + * \ + * Returns: --- \ + * \ + * Use: Initializes a MAC key for doing HMAC hashing. Keys \ + * longer than the hash function's output size aren't very \ + * useful, but are accepted. Keys longer than the hash's \ + * block size are also accepted; they are hashed before \ + * use, as specified in RFC2104. \ + */ \ + \ +void pre##_hmacinit(pre##_mackey *key, const void *k, size_t sz) \ +{ \ + int i; \ + const octet *kbuf = k; \ + pre##_ctx ctx; \ + octet buf[PRE##_HASHSZ]; \ + \ + if (sz > PRE##_BUFSZ) { \ + pre##_init(&ctx); \ + pre##_hash(&ctx, k, sz); \ + pre##_done(&ctx, buf); \ + kbuf = buf; \ + sz = PRE##_HASHSZ; \ + } \ + \ + pre##_init(&ctx); \ + memset(ctx.buf, 0x5c, PRE##_BUFSZ); \ + for (i = 0; i < sz; i++) \ + ctx.buf[i] ^= kbuf[i]; \ + pre##_compress(&ctx, ctx.buf); \ + pre##_state(&ctx, key->ochain); \ + \ + pre##_init(&ctx); \ + memset(ctx.buf, 0x36, PRE##_BUFSZ); \ + for (i = 0; i < sz; i++) \ + ctx.buf[i] ^= kbuf[i]; \ + pre##_compress(&ctx, ctx.buf); \ + pre##_state(&ctx, key->ichain); \ + \ + key->ocount = key->icount = PRE##_BUFSZ; \ + BURN(ctx); \ +} \ + \ +/* --- @pre_macinit@ --- * \ + * \ + * Arguments: @pre_macctx *ctx@ = pointer to MAC context block \ + * @const pre_mackey *key@ = pointer to MAC key block \ + * \ + * Returns: --- \ + * \ + * Use: Instantiates a MAC context from a key block. \ + */ \ + \ +void pre##_macinit(pre##_macctx *ctx, const pre##_mackey *key) \ +{ \ + memcpy(ctx->chain, key->ochain, PRE##_HASHSZ); \ + ctx->count = key->ocount; \ + pre##_set(&ctx->ctx, key->ichain, key->icount); \ +} \ + \ +/* --- @pre_machash@ --- * \ + * \ + * Arguments: @pre_macctx *ctx@ = pointer to MAC context block \ + * @const void *buf@ = pointer to buffer \ + * @size_t sz@ = size of the buffer \ + * \ + * Returns: --- \ + * \ + * Use: Hashes a buffer. \ + */ \ + \ +void pre##_machash(pre##_macctx *ctx, const void *buf, size_t sz) \ +{ \ + pre##_hash(&ctx->ctx, buf, sz); \ +} \ + \ +/* --- @pre_macdone@ --- * \ + * \ + * Arguments: @pre_macctx *ctx@ = pointer to MAC context block \ + * @void *mac@ = pointer to buffer to receive MAC \ + * \ + * Returns: --- \ + * \ + * Use: Returns the result of a MAC computation. \ + */ \ + \ +void pre##_macdone(pre##_macctx *ctx, void *mac) \ +{ \ + pre##_done(&ctx->ctx, mac); \ + pre##_set(&ctx->ctx, ctx->chain, ctx->count); \ + pre##_hash(&ctx->ctx, mac, PRE##_HASHSZ); \ + pre##_done(&ctx->ctx, mac); \ +} \ + \ +/* --- Generic MAC interface --- */ \ + \ +static const gmac_ops gkops; \ +static const ghash_ops gops; \ + \ +typedef struct gkctx { \ + gmac m; \ + pre##_mackey k; \ +} gkctx; \ + \ +typedef struct gctx { \ + ghash h; \ + pre##_macctx c; \ +} gctx; \ + \ +static ghash *gkinit(gmac *m) \ +{ \ + gkctx *gk = (gkctx *)m; \ + gctx *g = CREATE(gctx); \ + g->h.ops = &gops; \ + pre##_macinit(&g->c, &gk->k); \ + return (&g->h); \ +} \ + \ +static gmac *gkey(const void *k, size_t sz) \ +{ \ + gkctx *gk = CREATE(gkctx); \ + gk->m.ops = &gkops; \ + pre##_hmacinit(&gk->k, k, sz); \ + return (&gk->m); \ +} \ + \ +static void ghhash(ghash *h, const void *p, size_t sz) \ +{ \ + gctx *g = (gctx *)h; \ + pre##_machash(&g->c, p, sz); \ +} \ + \ +static void ghdone(ghash *h, void *buf) \ +{ \ + gctx *g = (gctx *)h; \ + pre##_macdone(&g->c, buf); \ +} \ + \ +static void ghdestroy(ghash *h) \ +{ \ + gctx *g = (gctx *)h; \ + DESTROY(g); \ +} \ + \ +static void gkdestroy(gmac *m) \ +{ \ + gkctx *gk = (gkctx *)m; \ + DESTROY(gk); \ +} \ + \ +const gcmac pre##_hmac = { { #pre "-hmac", PRE##_HASHSZ }, gkey }; \ +static const gmac_ops gkops = { &pre##_hmac.b, gkinit, gkdestroy }; \ +static const ghash_ops gops = \ + { &pre##_hmac.b, ghhash, ghdone, ghdestroy }; \ + \ +HMAC_TEST(PRE, pre) + +/* --- @HMAC_TEST@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for hash-specfic definitions + * + * Use: Standard test rig for MAC functions. + */ + +#ifdef TEST_RIG + +#include + +#include +#include +#include + +#define HMAC_TEST(PRE, pre) \ + \ +static int macverify(dstr *v) \ +{ \ + pre##_macctx cctx; \ + pre##_mackey ckey; \ + int ok = 1; \ + int i; \ + octet *p; \ + int szs[] = { 1, 7, 192, -1, 0 }, *ip; \ + size_t csz; \ + dstr d; \ + \ + dstr_create(&d); \ + dstr_ensure(&d, PRE##_HASHSZ); \ + d.len = PRE##_HASHSZ; \ + \ + pre##_hmacinit(&ckey, v[1].buf, v[1].len); \ + \ + for (ip = szs; *ip; ip++) { \ + i = *ip; \ + csz = v[0].len; \ + if (i == -1) \ + i = csz; \ + if (i > csz) \ + continue; \ + p = (octet *)v[0].buf; \ + pre##_macinit(&cctx, &ckey); \ + while (csz) { \ + if (i > csz) \ + i = csz; \ + pre##_machash(&cctx, p, i); \ + p += i; \ + csz -= i; \ + } \ + pre##_macdone(&cctx, d.buf); \ + if (memcmp(d.buf, v[2].buf, PRE##_HASHSZ) != 0) { \ + printf("\nfail:\n\tstep = %i\n\tinput = `%s'\n\tkey = ", \ + *ip, v[0].buf); \ + type_hex.dump(&v[1], stdout); \ + fputs("\n\texpected = ", stdout); \ + type_hex.dump(&v[2], stdout); \ + fputs("\n\tcomputed = ", stdout); \ + type_hex.dump(&d, stdout); \ + putchar('\n'); \ + ok = 0; \ + } \ + } \ + \ + dstr_destroy(&d); \ + return (ok); \ +} \ + \ +static test_chunk macdefs[] = { \ + { #pre "-hmac", macverify, \ + { &type_string, &type_hex, &type_hex, 0 } }, \ + { 0, 0, { 0 } } \ +}; \ + \ +int main(int argc, char *argv[]) \ +{ \ + ego(argv[0]); \ + test_run(argc, argv, macdefs, SRCDIR"/tests/" #pre); \ + return (0); \ +} + +#else +# define HMAC_TEST(PRE, pre) +#endif + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/hmac.h b/hmac.h index 8849258..d64003f 100644 --- a/hmac.h +++ b/hmac.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: hmac.h,v 1.1 1999/09/03 08:41:12 mdw Exp $ + * $Id: hmac.h,v 1.2 1999/12/10 23:17:39 mdw Exp $ * * Generic code for HMAC and NMAC * @@ -30,6 +30,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: hmac.h,v $ + * Revision 1.2 1999/12/10 23:17:39 mdw + * Split mode macros into interface and implementation. + * * Revision 1.1 1999/09/03 08:41:12 mdw * Initial import. * @@ -37,16 +40,18 @@ /*----- Notes on the HMAC and NMAC constructions --------------------------* * - * Designed by Mihir Bellare, Ran Canetti and Hugo Krawczyk, NMAC is a - * method for constructing keyed message authentication algorithms from - * unkeyed hash functions. HMAC is an alternative formulation which doesn't - * require low-level access to the hash function's implementation. NMAC was - * designed to allow MD5 has a suitable underlying hash function, even though - * doubts were already being raised about its collision resistance. + * Designed by Mihir Bellare, Ran Canetti and Hugo Krawczyk, NMAC is a method + * for constructing keyed message authentication algorithms from unkeyed hash + * functions. It has been proven to provide useful security given reasonable + * assumptions about the underlying hash function. HMAC is an alternative + * formulation which doesn't require low-level access to the hash function's + * implementation. NMAC was designed to allow MD5 has a suitable underlying + * hash function, even though doubts were already being raised about its + * collision resistance. */ -#ifndef HMAC_H -#define HMAC_H +#ifndef CATACOMB_HMAC_H +#define CATACOMB_HMAC_H #ifdef __cplusplus extern "C" { @@ -54,13 +59,12 @@ /*----- Header files ------------------------------------------------------*/ -#include -#include +#include #include -#ifndef PARANOIA_H -# include "paranoia.h" +#ifndef CATACOMB_GMAC_H +# include "gmac.h" #endif /*----- Macros ------------------------------------------------------------*/ @@ -74,43 +78,24 @@ #define HMAC_DECL(PRE, pre) \ \ +/* --- An HMAC or NMAC key --- */ \ + \ typedef struct pre##_mackey { \ octet ochain[PRE##_HASHSZ]; /* Chaining for outer hash */ \ - unsigned long ocount; /* Byte count for outer hash */ \ + unsigned ocount; /* Byte count for outer hash */ \ octet ichain[PRE##_HASHSZ]; /* Chaining for inner hash */ \ - unsigned long icount; /* Byte count for inner hash */ \ + unsigned icount; /* Byte count for inner hash */ \ } pre##_mackey; \ \ +/* --- An HMAC or NMAC hashing context --- */ \ + \ typedef struct pre##_macctx { \ pre##_ctx ctx; /* Context for main hashing */ \ octet chain[PRE##_HASHSZ]; /* Chaining for outer hash */ \ - unsigned long count; /* Byte count for outer hash */ \ + unsigned count; /* Byte count for outer hash */ \ } pre##_macctx; \ \ -extern void pre##_nmac(pre##_mackey */*key*/, \ - const void */*ok*/, const void */*ik*/); \ - \ -extern void pre##_hmac(pre##_mackey */*key*/, \ - const void */*k*/, size_t /*sz*/); \ - \ -extern void pre##_macinit(pre##_macctx */*ctx*/, \ - const pre##_mackey */*key*/); \ - \ -extern void pre##_mac(pre##_macctx */*ctx*/, \ - const void */*buf*/, size_t /*sz*/); \ - \ -extern void pre##_macdone(pre##_macctx */*ctx*/, void */*mac*/); - -/* --- @HMAC_DEF@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for the underlying hash function - * - * Use: Creates implementations for the HMAC and NMAC functions. - */ - -#define HMAC_DEF(PRE, pre) \ - \ -/* --- @pre_nmac@ --- * \ +/* --- @pre_nmacinit@ --- * \ * \ * Arguments: @pre_macctx *key@ = pointer to a MAC key object \ * @const void *ok@ = pointer to outer hash init vector \ @@ -121,14 +106,10 @@ extern void pre##_macdone(pre##_macctx */*ctx*/, void */*mac*/); * Use: Initializes a MAC key for doing NMAC hashing. \ */ \ \ -void pre##_nmac(pre##_mackey *key, const void *ok, const void *ik) \ -{ \ - memcpy(key->ochain, ok, PRE##_HASHSZ); \ - memcpy(key->ichain, ik, PRE##_HASHSZ); \ - key->ocount = key->icount = 0; \ -} \ +extern void pre##_nmacinit(pre##_mackey */*key*/, \ + const void */*ok*/, const void */*ik*/); \ \ -/* --- @pre_hmac@ --- * \ +/* --- @pre_hmacinit@ --- * \ * \ * Arguments: @pre_mackey *key@ = pointer to MAC key object \ * @const void *k@ = pointer to key to use \ @@ -143,38 +124,8 @@ void pre##_nmac(pre##_mackey *key, const void *ok, const void *ik) \ * use, as specified in RFC2104. \ */ \ \ -void pre##_hmac(pre##_mackey *key, const void *k, size_t sz) \ -{ \ - int i; \ - const octet *kbuf = k; \ - pre##_ctx ctx; \ - octet buf[PRE##_HASHSZ]; \ - \ - if (sz > PRE##_BUFSZ) { \ - pre##_init(&ctx); \ - pre##_hash(&ctx, k, sz); \ - pre##_done(&ctx, buf); \ - kbuf = buf; \ - sz = PRE##_HASHSZ; \ - } \ - \ - pre##_init(&ctx); \ - memset(ctx.buf, 0x5c, PRE##_BUFSZ); \ - for (i = 0; i < sz; i++) \ - ctx.buf[i] ^= kbuf[i]; \ - pre##_compress(&ctx, ctx.buf); \ - pre##_state(&ctx, key->ochain); \ - \ - pre##_init(&ctx); \ - memset(ctx.buf, 0x36, PRE##_BUFSZ); \ - for (i = 0; i < sz; i++) \ - ctx.buf[i] ^= kbuf[i]; \ - pre##_compress(&ctx, ctx.buf); \ - pre##_state(&ctx, key->ichain); \ - \ - key->ocount = key->icount = PRE##_BUFSZ; \ - BURN(ctx); \ -} \ +extern void pre##_hmacinit(pre##_mackey */*key*/, \ + const void */*k*/, size_t /*sz*/); \ \ /* --- @pre_macinit@ --- * \ * \ @@ -186,14 +137,10 @@ void pre##_hmac(pre##_mackey *key, const void *k, size_t sz) \ * Use: Instantiates a MAC context from a key block. \ */ \ \ -void pre##_macinit(pre##_macctx *ctx, const pre##_mackey *key) \ -{ \ - memcpy(ctx->chain, key->ochain, PRE##_HASHSZ); \ - ctx->count = key->ocount; \ - pre##_set(&ctx->ctx, key->ichain, key->icount); \ -} \ +extern void pre##_macinit(pre##_macctx */*ctx*/, \ + const pre##_mackey */*key*/); \ \ -/* --- @pre_mac@ --- * \ +/* --- @pre_machash@ --- * \ * \ * Arguments: @pre_macctx *ctx@ = pointer to MAC context block \ * @const void *buf@ = pointer to buffer \ @@ -204,10 +151,8 @@ void pre##_macinit(pre##_macctx *ctx, const pre##_mackey *key) \ * Use: Hashes a buffer. \ */ \ \ -void pre##_mac(pre##_macctx *ctx, const void *buf, size_t sz) \ -{ \ - pre##_hash(&ctx->ctx, buf, sz); \ -} \ +extern void pre##_machash(pre##_macctx */*ctx*/, \ + const void */*buf*/, size_t /*sz*/); \ \ /* --- @pre_macdone@ --- * \ * \ @@ -219,98 +164,11 @@ void pre##_mac(pre##_macctx *ctx, const void *buf, size_t sz) \ * Use: Returns the result of a MAC computation. \ */ \ \ -void pre##_macdone(pre##_macctx *ctx, void *mac) \ -{ \ - pre##_done(&ctx->ctx, mac); \ - pre##_set(&ctx->ctx, ctx->chain, ctx->count); \ - pre##_hash(&ctx->ctx, mac, PRE##_HASHSZ); \ - pre##_done(&ctx->ctx, mac); \ -} \ - \ -HMAC_TEST(PRE, pre) \ - -/* --- @HMAC_TEST@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for hash-specfic definitions - * - * Use: Standard test rig for MAC functions. - */ - -#ifdef TEST_RIG - -#include -#include -#include - -#define HMAC_TEST(PRE, pre) \ - \ -static int macverify(dstr *v) \ -{ \ - pre##_macctx cctx; \ - pre##_mackey ckey; \ - int ok = 1; \ - int i; \ - octet *p; \ - int szs[] = { 1, 7, 192, -1, 0 }, *ip; \ - size_t csz; \ - dstr d; \ - \ - dstr_create(&d); \ - dstr_ensure(&d, PRE##_HASHSZ); \ - d.len = PRE##_HASHSZ; \ - \ - pre##_hmac(&ckey, v[1].buf, v[1].len); \ +extern void pre##_macdone(pre##_macctx */*ctx*/, void */*mac*/); \ \ - for (ip = szs; *ip; ip++) { \ - i = *ip; \ - csz = v[0].len; \ - if (i == -1) \ - i = csz; \ - if (i > csz) \ - continue; \ - p = (octet *)v[0].buf; \ - pre##_macinit(&cctx, &ckey); \ - while (csz) { \ - if (i > csz) \ - i = csz; \ - pre##_mac(&cctx, p, i); \ - p += i; \ - csz -= i; \ - } \ - pre##_macdone(&cctx, d.buf); \ - if (memcmp(d.buf, v[2].buf, PRE##_HASHSZ) != 0) { \ - printf("\nfail:\n\tstep = %i\n\tinput = `%s'\n\tkey = ", \ - *ip, v[0].buf); \ - type_hex.dump(&v[1], stdout); \ - fputs("\n\texpected = ", stdout); \ - type_hex.dump(&v[2], stdout); \ - fputs("\n\tcomputed = ", stdout); \ - type_hex.dump(&d, stdout); \ - putchar('\n'); \ - ok = 0; \ - } \ - } \ +/* --- Generic MAC interface --- */ \ \ - dstr_destroy(&d); \ - return (ok); \ -} \ - \ -static test_chunk macdefs[] = { \ - { #pre "-hmac", macverify, \ - { &type_string, &type_hex, &type_hex, 0 } }, \ - { 0, 0, { 0 } } \ -}; \ - \ -int main(int argc, char *argv[]) \ -{ \ - ego(argv[0]); \ - test_run(argc, argv, macdefs, SRCDIR"/tests/" #pre); \ - return (0); \ -} - -#else -# define HMAC_TEST(PRE, pre) -#endif +extern const gcmac pre##_hmac; /*----- That's all, folks -------------------------------------------------*/ diff --git a/ofb-def.h b/ofb-def.h new file mode 100644 index 0000000..2d0fc94 --- /dev/null +++ b/ofb-def.h @@ -0,0 +1,538 @@ +/* -*-c-*- + * + * $Id: ofb-def.h,v 1.1 1999/12/10 23:16:40 mdw Exp $ + * + * Definitions for output feedback mode + * + * (c) 1999 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: ofb-def.h,v $ + * Revision 1.1 1999/12/10 23:16:40 mdw + * Split mode macros into interface and implementation. + * + */ + +#ifndef CATACOMB_OFB_DEF_H +#define CATACOMB_OFB_DEF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#include +#include + +#include +#include + +#ifndef CATACOMB_BLKC_H +# include "blkc.h" +#endif + +#ifndef CATACOMB_GCIPHER_H +# include "gcipher.h" +#endif + +#ifndef CATACOMB_PARANOIA_H +# include "paranoia.h" +#endif + +/*----- Macros ------------------------------------------------------------*/ + +/* --- @OFB_DEF@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher + * + * Use: Creates definitions for output feedback mode. + */ + +#define OFB_DEF(PRE, pre) \ + \ +/* --- @pre_ofbgetiv@ --- * \ + * \ + * Arguments: @const pre_ofbctx *ctx@ = pointer to OFB context block \ + * @void *iv#@ = pointer to output data block \ + * \ + * Returns: --- \ + * \ + * Use: Reads the currently set IV. Reading and setting an IV \ + * is not transparent to the cipher. It will add a `step' \ + * which must be matched by a similar operation during \ + * decryption. \ + */ \ + \ +void pre##_ofbgetiv(const pre##_ofbctx *ctx, void *iv) \ +{ \ + octet *p = iv; \ + int off = ctx->off; \ + int rest = PRE##_BLKSZ - off; \ + memcpy(p, ctx->iv + off, rest); \ + memcpy(p + rest, ctx->iv, off); \ +} \ + \ +/* --- @pre_ofbsetiv@ --- * \ + * \ + * Arguments: @pre_ofbctx *ctx@ = pointer to OFB context block \ + * @cnost void *iv@ = pointer to IV to set \ + * \ + * Returns: --- \ + * \ + * Use: Sets the IV to use for subsequent encryption. \ + */ \ + \ +void pre##_ofbsetiv(pre##_ofbctx *ctx, const void *iv) \ +{ \ + uint32 niv[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, niv, iv); \ + pre##_eblk(&ctx->ctx, niv, niv); \ + BLKC_STORE(PRE, ctx->iv, niv); \ + ctx->off = 0; \ +} \ + \ +/* --- @pre_ofbbdry@ --- * \ + * \ + * Arguments: @pre_ofbctx *ctx@ = pointer to OFB context block \ + * \ + * Returns: --- \ + * \ + * Use: Inserts a boundary during encryption. Successful \ + * decryption must place a similar boundary. \ + */ \ + \ +void pre##_ofbbdry(pre##_ofbctx *ctx) \ +{ \ + octet iv[PRE##_BLKSZ]; \ + pre##_ofbgetiv(ctx, iv); \ + pre##_ofbsetiv(ctx, iv); \ + BURN(iv); \ +} \ + \ +/* --- @pre_ofbsetkey@ --- * \ + * \ + * Arguments: @pre_ofbctx *ctx@ = pointer to OFB context block \ + * @const pre_ctx *k@ = pointer to cipher context \ + * \ + * Returns: --- \ + * \ + * Use: Sets the OFB context to use a different cipher key. \ + */ \ + \ +void pre##_ofbsetkey(pre##_ofbctx *ctx, const pre##_ctx *k) \ +{ \ + ctx->ctx = *k; \ +} \ + \ +/* --- @pre_ofbinit@ --- * \ + * \ + * Arguments: @pre_ofbctx *ctx@ = pointer to cipher context \ + * @const void *key@ = pointer to the key buffer \ + * @size_t sz@ = size of the key \ + * @const void *iv@ = pointer to initialization vector \ + * \ + * Returns: --- \ + * \ + * Use: Initializes a OFB context ready for use. You should \ + * ensure that the IV chosen is unique: reusing an IV will \ + * compromise the security of the entire plaintext. This \ + * is equivalent to calls to @pre_init@, @pre_ofbsetkey@ \ + * and @pre_ofbsetiv@. \ + */ \ + \ +void pre##_ofbinit(pre##_ofbctx *ctx, \ + const void *key, size_t sz, \ + const void *iv) \ +{ \ + static octet zero[PRE##_BLKSZ] = { 0 }; \ + pre##_init(&ctx->ctx, key, sz); \ + pre##_ofbsetiv(ctx, iv ? iv : zero); \ +} \ + \ +/* --- @pre_ofbencrypt@ --- * \ + * \ + * Arguments: @pre_ofbctx *ctx@ = pointer to OFB context block \ + * @const void *src@ = pointer to source data \ + * @void *dest@ = pointer to destination data \ + * @size_t sz@ = size of block to be encrypted \ + * \ + * Returns: --- \ + * \ + * Use: Encrypts or decrypts a block with a block cipher in OFB \ + * mode: encryption and decryption are the same in OFB. \ + * The destination may be null to just churn the feedback \ + * round for a bit. The source may be null to use the \ + * cipher as a random data generator. \ + */ \ + \ +void pre##_ofbencrypt(pre##_ofbctx *ctx, \ + const void *src, void *dest, \ + size_t sz) \ +{ \ + const octet *s = src; \ + octet *d = dest; \ + int off = ctx->off; \ + \ + /* --- Empty blocks are trivial --- */ \ + \ + if (!sz) \ + return; \ + \ + /* --- If I can deal with the block from my buffer, do that --- */ \ + \ + if (sz < PRE##_BLKSZ - off) \ + goto small; \ + \ + /* --- Finish off what's left in my buffer --- */ \ + \ + if (!d) \ + sz -= off; \ + else { \ + while (off < PRE##_BLKSZ) { \ + register octet x = s ? *s++ : 0; \ + *d++ = ctx->iv[off++] ^ x; \ + sz--; \ + } \ + } \ + \ + /* --- Main encryption loop --- */ \ + \ + { \ + uint32 iv[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, iv, ctx->iv); \ + \ + for (;;) { \ + pre##_eblk(&ctx->ctx, iv, iv); \ + if (sz < PRE##_BLKSZ) \ + break; \ + if (d) { \ + if (!s) \ + BLKC_STORE(PRE, d, iv); \ + else { \ + uint32 x[PRE##_BLKSZ / 4]; \ + BLKC_LOAD(PRE, x, s); \ + BLKC_XSTORE(PRE, d, iv, x); \ + s += PRE##_BLKSZ; \ + } \ + d += PRE##_BLKSZ; \ + } \ + sz -= PRE##_BLKSZ; \ + } \ + \ + BLKC_STORE(PRE, ctx->iv, iv); \ + off = 0; \ + } \ + \ + /* --- Tidying up the tail end --- */ \ + \ + if (sz) { \ + small: \ + if (!d) \ + off += sz; \ + else do { \ + register octet x = s ? *s++ : 0; \ + *d++ = ctx->iv[off++] ^ x; \ + sz--; \ + } while (sz); \ + } \ + \ + /* --- Done --- */ \ + \ + ctx->off = off; \ + return; \ +} \ + \ +/* --- Generic cipher interface --- */ \ + \ +static const gcipher_ops gops; \ + \ +typedef struct gctx { \ + gcipher c; \ + pre##_ofbctx k; \ +} gctx; \ + \ +static gcipher *ginit(const void *k, size_t sz) \ +{ \ + gctx *g = CREATE(gctx); \ + g->c.ops = &gops; \ + pre##_ofbinit(&g->k, k, sz, 0); \ + return (&g->c); \ +} \ + \ +static void gencrypt(gcipher *c, const void *s, void *t, size_t sz) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_ofbencrypt(&g->k, s, t, sz); \ +} \ + \ +static void gdestroy(gcipher *c) \ +{ \ + gctx *g = (gctx *)c; \ + DESTROY(g); \ +} \ + \ +static void gsetiv(gcipher *c, const void *iv) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_ofbsetiv(&g->k, iv); \ +} \ + \ +static void gbdry(gcipher *c) \ +{ \ + gctx *g = (gctx *)c; \ + pre##_ofbbdry(&g->k); \ +} \ + \ +static const gcipher_ops gops = { \ + &pre##_ofb.b, \ + gencrypt, gencrypt, gdestroy, gsetiv, gbdry \ +}; \ + \ +const gccipher pre##_ofb = { \ + { #pre "-ofb", PRE##_KEYSZ, PRE##_BLKSZ }, \ + ginit \ +}; \ + \ +/* --- Generic random number generator interface --- */ \ + \ +typedef struct grctx { \ + grand r; \ + pre##_ofbctx k; \ +} grctx; \ + \ +static void grdestroy(grand *r) \ +{ \ + grctx *g = (grctx *)r; \ + DESTROY(g); \ +} \ + \ +static int grmisc(grand *r, unsigned op, ...) \ +{ \ + grctx *g = (grctx *)r; \ + va_list ap; \ + int rc = 0; \ + octet buf[PRE##_BLKSZ]; \ + va_start(ap, op); \ + \ + switch (op) { \ + case GRAND_CHECK: \ + switch (va_arg(ap, unsigned)) { \ + case GRAND_CHECK: \ + case GRAND_SEEDINT: \ + case GRAND_SEEDUINT32: \ + case GRAND_SEEDBLOCK: \ + rc = 1; \ + break; \ + default: \ + rc = 0; \ + break; \ + } \ + break; \ + case GRAND_SEEDINT: \ + memset(buf, 0, sizeof(buf)); \ + STORE32(buf, va_arg(ap, unsigned)); \ + pre##_ofbsetiv(&g->k, buf); \ + break; \ + case GRAND_SEEDUINT32: \ + memset(buf, 0, sizeof(buf)); \ + STORE32(buf, va_arg(ap, uint32)); \ + pre##_ofbsetiv(&g->k, buf); \ + break; \ + case GRAND_SEEDBLOCK: { \ + const void *p = va_arg(ap, const void *); \ + size_t sz = va_arg(ap, size_t); \ + if (sz < sizeof(buf)) { \ + memset(buf, 0, sizeof(buf)); \ + memcpy(buf, p, sz); \ + p = buf; \ + } \ + pre##_ofbsetiv(&g->k, p); \ + } break; \ + } \ + \ + va_end(ap); \ + return (rc); \ +} \ + \ +static octet grbyte(grand *r) \ +{ \ + grctx *g = (grctx *)r; \ + octet o; \ + pre##_ofbencrypt(&g->k, 0, &o, 1); \ + return (o); \ +} \ + \ +static uint32 grword(grand *r) \ +{ \ + grctx *g = (grctx *)r; \ + octet b[4]; \ + pre##_ofbencrypt(&g->k, 0, b, sizeof(b)); \ + return (LOAD32(b)); \ +} \ + \ +static void grfill(grand *r, void *p, size_t sz) \ +{ \ + grctx *g = (grctx *)r; \ + pre##_ofbencrypt(&g->k, 0, p, sz); \ +} \ + \ +static const grand_ops grops = { \ + #pre "-ofb", \ + 0, \ + grmisc, grdestroy, \ + grword, grbyte, grword, grand_range, grfill \ +}; \ + \ +/* --- @pre_ofbrand@ --- * \ + * \ + * Arguments: @const void *k@ = pointer to key material \ + * @size_t sz@ = size of key material \ + * \ + * Returns: Pointer to generic random number generator interface. \ + * \ + * Use: Creates a random number interface wrapper around an \ + * OFB-mode block cipher. \ + */ \ + \ +grand *pre##_ofbrand(const void *k, size_t sz) \ +{ \ + grctx *g = CREATE(grctx); \ + g->r.ops = &grops; \ + pre##_ofbinit(&g->k, k, sz, 0); \ + return (&g->r); \ +} \ + \ +OFB_TEST(PRE, pre) + +/*----- Test rig ----------------------------------------------------------*/ + +#ifdef TEST_RIG + +#include + +#include "daftstory.h" + +/* --- @OFB_TEST@ --- * + * + * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions + * + * Use: Standard test rig for OFB functions. + */ + +#define OFB_TEST(PRE, pre) \ + \ +/* --- Initial plaintext for the test --- */ \ + \ +static const octet text[] = TEXT; \ + \ +/* --- Key and IV to use --- */ \ + \ +static const octet key[] = KEY; \ +static const octet iv[] = IV; \ + \ +/* --- Buffers for encryption and decryption output --- */ \ + \ +static octet ct[sizeof(text)]; \ +static octet pt[sizeof(text)]; \ + \ +static void hexdump(const octet *p, size_t sz) \ +{ \ + const octet *q = p + sz; \ + for (sz = 0; p < q; p++, sz++) { \ + printf("%02x", *p); \ + if ((sz + 1) % PRE##_BLKSZ == 0) \ + putchar(':'); \ + } \ +} \ + \ +int main(void) \ +{ \ + size_t sz = 0, rest; \ + pre##_ofbctx ctx; \ + int status = 0; \ + int done = 0; \ + pre##_ctx k; \ + \ + size_t keysz = PRE##_KEYSZ ? \ + PRE##_KEYSZ : strlen((const char *)key); \ + \ + fputs(#pre "-ofb: ", stdout); \ + \ + pre##_init(&k, key, keysz); \ + pre##_ofbsetkey(&ctx, &k); \ + \ + while (sz <= sizeof(text)) { \ + rest = sizeof(text) - sz; \ + memcpy(ct, text, sizeof(text)); \ + pre##_ofbsetiv(&ctx, iv); \ + pre##_ofbencrypt(&ctx, ct, ct, sz); \ + pre##_ofbencrypt(&ctx, ct + sz, ct + sz, rest); \ + memcpy(pt, ct, sizeof(text)); \ + pre##_ofbsetiv(&ctx, iv); \ + pre##_ofbencrypt(&ctx, pt, pt, rest); \ + pre##_ofbencrypt(&ctx, pt + rest, pt + rest, sz); \ + if (memcmp(pt, text, sizeof(text)) == 0) { \ + done++; \ + if (sizeof(text) < 40 || done % 8 == 0) \ + fputc('.', stdout); \ + if (done % 480 == 0) \ + fputs("\n\t", stdout); \ + fflush(stdout); \ + } else { \ + printf("\nError (sz = %lu)\n", (unsigned long)sz); \ + status = 1; \ + printf("\tplaintext = "); hexdump(text, sz); \ + printf(", "); hexdump(text + sz, rest); \ + fputc('\n', stdout); \ + printf("\tciphertext = "); hexdump(ct, sz); \ + printf(", "); hexdump(ct + sz, rest); \ + fputc('\n', stdout); \ + printf("\trecovered text = "); hexdump(pt, sz); \ + printf(", "); hexdump(pt + sz, rest); \ + fputc('\n', stdout); \ + fputc('\n', stdout); \ + } \ + if (sz < 63) \ + sz++; \ + else \ + sz += 9; \ + } \ + \ + fputs(status ? " failed\n" : " ok\n", stdout); \ + return (status); \ +} + +#else +# define OFB_TEST(PRE, pre) +#endif + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ofb.h b/ofb.h index 85ff08c..189b65d 100644 --- a/ofb.h +++ b/ofb.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: ofb.h,v 1.1 1999/09/03 08:41:12 mdw Exp $ + * $Id: ofb.h,v 1.2 1999/12/10 23:16:40 mdw Exp $ * * Output feedback for block ciphers * @@ -30,13 +30,16 @@ /*----- Revision history --------------------------------------------------* * * $Log: ofb.h,v $ + * Revision 1.2 1999/12/10 23:16:40 mdw + * Split mode macros into interface and implementation. + * * Revision 1.1 1999/09/03 08:41:12 mdw * Initial import. * */ -#ifndef OFB_H -#define OFB_H +#ifndef CATACOMB_OFB_H +#define CATACOMB_OFB_H #ifdef __cplusplus extern "C" { @@ -44,16 +47,16 @@ /*----- Header files ------------------------------------------------------*/ -#include +#include #include -#ifndef BLKC_H -# include "blkc.h" +#ifndef CATACOMB_GCIPHER_H +# include "gcipher.h" #endif -#ifndef PARANOIA_H -# include "paranoia.h" +#ifndef CATACOMB_GRAND_H +# include "grand.h" #endif /*----- Macros ------------------------------------------------------------*/ @@ -67,39 +70,13 @@ #define OFB_DECL(PRE, pre) \ \ -typedef struct pre ## _ofbctx { \ - pre ## _ctx ctx; /* Underlying cipher context */ \ - int off; /* Current offset in buffer */ \ - octet iv[PRE ## _BLKSZ]; /* Output buffer and IV */ \ -} pre ## _ofbctx; \ - \ -extern void pre ## _ofbgetiv(const pre ## _ofbctx */*ctx*/, \ - void */*iv*/); \ - \ -extern void pre ## _ofbsetiv(pre ## _ofbctx */*ctx*/, \ - const void */*iv*/); \ - \ -extern void pre ## _ofbbdry(pre ## _ofbctx */*ctx*/); \ - \ -extern void pre ## _ofbsetkey(pre ## _ofbctx */*ctx*/, \ - const pre ## _ctx */*k*/); \ - \ -extern void pre ## _ofbinit(pre ## _ofbctx */*ctx*/, \ - const void */*key*/, size_t /*sz*/, \ - const void */*iv*/); \ +/* --- Output feedback context --- */ \ \ -extern void pre ## _ofbencrypt(pre ## _ofbctx */*ctx*/, \ - const void */*src*/, void */*dest*/, \ - size_t /*sz*/); - -/* --- @OFB_DEF@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher - * - * Use: Creates definitions for output feedback mode. - */ - -#define OFB_DEF(PRE, pre) \ +typedef struct pre##_ofbctx { \ + pre##_ctx ctx; /* Underlying cipher context */ \ + int off; /* Current offset in buffer */ \ + octet iv[PRE##_BLKSZ]; /* Output buffer and IV */ \ +} pre##_ofbctx; \ \ /* --- @pre_ofbgetiv@ --- * \ * \ @@ -114,14 +91,8 @@ extern void pre ## _ofbencrypt(pre ## _ofbctx */*ctx*/, \ * decryption. \ */ \ \ -void pre ## _ofbgetiv(const pre ## _ofbctx *ctx, void *iv) \ -{ \ - octet *p = iv; \ - int off = ctx->off; \ - int rest = PRE ## _BLKSZ - off; \ - memcpy(p, ctx->iv + off, rest); \ - memcpy(p + rest, ctx->iv, off); \ -} \ +extern void pre##_ofbgetiv(const pre##_ofbctx */*ctx*/, \ + void */*iv*/); \ \ /* --- @pre_ofbsetiv@ --- * \ * \ @@ -133,14 +104,8 @@ void pre ## _ofbgetiv(const pre ## _ofbctx *ctx, void *iv) \ * Use: Sets the IV to use for subsequent encryption. \ */ \ \ -void pre ## _ofbsetiv(pre ## _ofbctx *ctx, const void *iv) \ -{ \ - uint32 niv[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, niv, iv); \ - pre ## _eblk(&ctx->ctx, niv, niv); \ - BLKC_STORE(PRE, ctx->iv, niv); \ - ctx->off = 0; \ -} \ +extern void pre##_ofbsetiv(pre##_ofbctx */*ctx*/, \ + const void */*iv*/); \ \ /* --- @pre_ofbbdry@ --- * \ * \ @@ -152,13 +117,7 @@ void pre ## _ofbsetiv(pre ## _ofbctx *ctx, const void *iv) \ * decryption must place a similar boundary. \ */ \ \ -void pre ## _ofbbdry(pre ## _ofbctx *ctx) \ -{ \ - octet iv[PRE ## _BLKSZ]; \ - pre ## _ofbgetiv(ctx, iv); \ - pre ## _ofbsetiv(ctx, iv); \ - BURN(iv); \ -} \ +extern void pre##_ofbbdry(pre##_ofbctx */*ctx*/); \ \ /* --- @pre_ofbsetkey@ --- * \ * \ @@ -170,10 +129,8 @@ void pre ## _ofbbdry(pre ## _ofbctx *ctx) \ * Use: Sets the OFB context to use a different cipher key. \ */ \ \ -void pre ## _ofbsetkey(pre ## _ofbctx *ctx, const pre ## _ctx *k) \ -{ \ - ctx->ctx = *k; \ -} \ +extern void pre##_ofbsetkey(pre##_ofbctx */*ctx*/, \ + const pre##_ctx */*k*/); \ \ /* --- @pre_ofbinit@ --- * \ * \ @@ -191,14 +148,9 @@ void pre ## _ofbsetkey(pre ## _ofbctx *ctx, const pre ## _ctx *k) \ * and @pre_ofbsetiv@. \ */ \ \ -void pre ## _ofbinit(pre ## _ofbctx *ctx, \ - const void *key, size_t sz, \ - const void *iv) \ -{ \ - static octet zero[PRE ## _BLKSZ] = { 0 }; \ - pre ## _init(&ctx->ctx, key, sz); \ - pre ## _ofbsetiv(ctx, iv ? iv : zero); \ -} \ +extern void pre##_ofbinit(pre##_ofbctx */*ctx*/, \ + const void */*key*/, size_t /*sz*/, \ + const void */*iv*/); \ \ /* --- @pre_ofbencrypt@ --- * \ * \ @@ -216,186 +168,26 @@ void pre ## _ofbinit(pre ## _ofbctx *ctx, \ * cipher as a random data generator. \ */ \ \ -void pre ## _ofbencrypt(pre ## _ofbctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ -{ \ - const octet *s = src; \ - octet *d = dest; \ - int off = ctx->off; \ - \ - /* --- Empty blocks are trivial --- */ \ - \ - if (!sz) \ - return; \ - \ - /* --- If I can deal with the block from my buffer, do that --- */ \ - \ - if (sz < PRE ## _BLKSZ - off) \ - goto small; \ - \ - /* --- Finish off what's left in my buffer --- */ \ - \ - if (!d) \ - sz -= off; \ - else { \ - while (off < PRE ## _BLKSZ) { \ - register octet x = s ? *s++ : 0; \ - *d++ = ctx->iv[off++] ^ x; \ - sz--; \ - } \ - } \ - \ - /* --- Main encryption loop --- */ \ - \ - { \ - uint32 iv[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, iv, ctx->iv); \ - \ - for (;;) { \ - pre ## _eblk(&ctx->ctx, iv, iv); \ - if (sz < PRE ## _BLKSZ) \ - break; \ - if (d) { \ - if (!s) \ - BLKC_STORE(PRE, d, iv); \ - else { \ - uint32 x[PRE ## _BLKSZ / 4]; \ - BLKC_LOAD(PRE, x, s); \ - BLKC_XSTORE(PRE, d, iv, x); \ - s += PRE ## _BLKSZ; \ - } \ - d += PRE ## _BLKSZ; \ - } \ - sz -= PRE ## _BLKSZ; \ - } \ - \ - BLKC_STORE(PRE, ctx->iv, iv); \ - off = 0; \ - } \ - \ - /* --- Tidying up the tail end --- */ \ - \ - if (sz) { \ - small: \ - if (!d) \ - off += sz; \ - else do { \ - register octet x = s ? *s++ : 0; \ - *d++ = ctx->iv[off++] ^ x; \ - sz--; \ - } while (sz); \ - } \ - \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ -} \ +extern void pre##_ofbencrypt(pre##_ofbctx */*ctx*/, \ + const void */*src*/, void */*dest*/, \ + size_t /*sz*/); \ \ -OFB_TEST(PRE, pre) - -/*----- Test rig ----------------------------------------------------------*/ - -#ifdef TEST_RIG - -#include - -#include "daftstory.h" - -/* --- @OFB_TEST@ --- * - * - * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions - * - * Use: Standard test rig for OFB functions. - */ - -#define OFB_TEST(PRE, pre) \ - \ -/* --- Initial plaintext for the test --- */ \ - \ -static const octet text[] = TEXT; \ - \ -/* --- Key and IV to use --- */ \ - \ -static const octet key[] = KEY; \ -static const octet iv[] = IV; \ - \ -/* --- Buffers for encryption and decryption output --- */ \ - \ -static octet ct[sizeof(text)]; \ -static octet pt[sizeof(text)]; \ - \ -static void hexdump(const octet *p, size_t sz) \ -{ \ - const octet *q = p + sz; \ - for (sz = 0; p < q; p++, sz++) { \ - printf("%02x", *p); \ - if ((sz + 1) % PRE ## _BLKSZ == 0) \ - putchar(':'); \ - } \ -} \ - \ -int main(void) \ -{ \ - size_t sz = 0, rest; \ - pre ## _ofbctx ctx; \ - int status = 0; \ - int done = 0; \ - pre ## _ctx k; \ - \ - size_t keysz = PRE ## _KEYSZ ? \ - PRE ## _KEYSZ : strlen((const char *)key); \ - \ - fputs(#pre "-ofb: ", stdout); \ +/* --- @pre_ofbrand@ --- * \ + * \ + * Arguments: @const void *k@ = pointer to key material \ + * @size_t sz@ = size of key material \ + * \ + * Returns: Pointer to generic random number generator interface. \ + * \ + * Use: Creates a random number interface wrapper around an \ + * OFB-mode block cipher. \ + */ \ \ - pre ## _init(&k, key, keysz); \ - pre ## _ofbsetkey(&ctx, &k); \ +extern grand *pre##_ofbrand(const void */*k*/, size_t /*sz*/); \ \ - while (sz <= sizeof(text)) { \ - rest = sizeof(text) - sz; \ - memcpy(ct, text, sizeof(text)); \ - pre ## _ofbsetiv(&ctx, iv); \ - pre ## _ofbencrypt(&ctx, ct, ct, sz); \ - pre ## _ofbencrypt(&ctx, ct + sz, ct + sz, rest); \ - memcpy(pt, ct, sizeof(text)); \ - pre ## _ofbsetiv(&ctx, iv); \ - pre ## _ofbencrypt(&ctx, pt, pt, rest); \ - pre ## _ofbencrypt(&ctx, pt + rest, pt + rest, sz); \ - if (memcmp(pt, text, sizeof(text)) == 0) { \ - done++; \ - if (sizeof(text) < 40 || done % 8 == 0) \ - fputc('.', stdout); \ - if (done % 480 == 0) \ - fputs("\n\t", stdout); \ - fflush(stdout); \ - } else { \ - printf("\nError (sz = %lu)\n", (unsigned long)sz); \ - status = 1; \ - printf("\tplaintext = "); hexdump(text, sz); \ - printf(", "); hexdump(text + sz, rest); \ - fputc('\n', stdout); \ - printf("\tciphertext = "); hexdump(ct, sz); \ - printf(", "); hexdump(ct + sz, rest); \ - fputc('\n', stdout); \ - printf("\trecovered text = "); hexdump(pt, sz); \ - printf(", "); hexdump(pt + sz, rest); \ - fputc('\n', stdout); \ - fputc('\n', stdout); \ - } \ - if (sz < 63) \ - sz++; \ - else \ - sz += 9; \ - } \ +/* --- Generic cipher interface --- */ \ \ - fputs(status ? " failed\n" : " ok\n", stdout); \ - return (status); \ -} - -#else -# define OFB_TEST(PRE, pre) -#endif +extern const gccipher pre##_ofb; /*----- That's all, folks -------------------------------------------------*/ -- 2.11.0