X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/1da1ed6a5815deef6c33d74f1eb3c856793df3e5..HEAD:/symm/cfb-def.h diff --git a/symm/cfb-def.h b/symm/cfb-def.h index 4f0f38f4..303bc9fd 100644 --- a/symm/cfb-def.h +++ b/symm/cfb-def.h @@ -59,6 +59,10 @@ # include "paranoia.h" #endif +#ifndef CATACOMB_RSVR_H +# include "rsvr.h" +#endif + /*----- Macros ------------------------------------------------------------*/ /* --- @CFB_DEF@ --- * @@ -68,7 +72,9 @@ * Use: Creates an implementation for CFB mode. */ -#define CFB_DEF(PRE, pre) \ +#define CFB_DEF(PRE, pre) CFB_DEFX(PRE, pre, #pre, #pre) + +#define CFB_DEFX(PRE, pre, name, fname) \ \ /* --- @pre_cfbgetiv@ --- * \ * \ @@ -88,8 +94,9 @@ void pre##_cfbgetiv(const pre##_cfbctx *ctx, void *iv) \ octet *p = iv; \ unsigned off = ctx->off; \ unsigned rest = PRE##_BLKSZ - off; \ - memcpy(p, ctx->iv + off, rest); \ - memcpy(p + rest, ctx->iv, off); \ + \ + memcpy(p, ctx->b + off, rest); \ + memcpy(p + rest, ctx->b, off); \ } \ \ /* --- @pre_cfbsetiv@ --- * \ @@ -103,10 +110,7 @@ void pre##_cfbgetiv(const pre##_cfbctx *ctx, void *iv) \ */ \ \ void pre##_cfbsetiv(pre##_cfbctx *ctx, const void *iv) \ -{ \ - memcpy(ctx->iv, iv, PRE##_BLKSZ); \ - ctx->off = PRE##_BLKSZ; \ -} \ + { memcpy(ctx->b, iv, PRE##_BLKSZ); ctx->off = 0; } \ \ /* --- @pre_cfbbdry@ --- * \ * \ @@ -120,12 +124,13 @@ void pre##_cfbsetiv(pre##_cfbctx *ctx, const void *iv) \ \ void pre##_cfbbdry(pre##_cfbctx *ctx) \ { \ - uint32 niv[PRE##_BLKSZ / 4]; \ - BLKC_LOAD(PRE, niv, ctx->iv); \ - pre##_eblk(&ctx->ctx, niv, niv); \ - BLKC_STORE(PRE, ctx->iv, niv); \ - ctx->off = PRE##_BLKSZ; \ - BURN(niv); \ + uint32 t[PRE##_BLKSZ/4]; \ + \ + BLKC_LOAD(PRE, t, ctx->b); \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + ctx->off = 0; \ + BURN(t); \ } \ \ /* --- @pre_cfbsetkey@ --- * \ @@ -139,10 +144,7 @@ void pre##_cfbbdry(pre##_cfbctx *ctx) \ */ \ \ void pre##_cfbsetkey(pre##_cfbctx *ctx, const pre##_ctx *k) \ -{ \ - ctx->ctx = *k; \ - ctx->off = PRE##_BLKSZ; \ -} \ + { ctx->ctx = *k; ctx->off = 0; } \ \ /* --- @pre_cfbinit@ --- * \ * \ @@ -161,10 +163,11 @@ void pre##_cfbsetkey(pre##_cfbctx *ctx, const pre##_ctx *k) \ */ \ \ void pre##_cfbinit(pre##_cfbctx *ctx, \ - const void *key, size_t sz, \ - const void *iv) \ + const void *key, size_t sz, \ + const void *iv) \ { \ static const octet zero[PRE##_BLKSZ] = { 0 }; \ + \ pre##_init(&ctx->ctx, key, sz); \ pre##_cfbsetiv(ctx, iv ? iv : zero); \ } \ @@ -183,75 +186,75 @@ void pre##_cfbinit(pre##_cfbctx *ctx, \ * sensitive to block boundaries. \ */ \ \ +static const rsvr_policy pre##_cfbpolicy = { 0, PRE##_BLKSZ, PRE##_BLKSZ }; \ + \ void pre##_cfbencrypt(pre##_cfbctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ + const void *src, void *dest, \ + size_t sz) \ { \ + rsvr_plan plan; \ const octet *s = src; \ - octet *d = dest; \ - unsigned 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++; \ - ctx->iv[off] ^= x; \ - if (d) *d++ = ctx->iv[off]; \ - off++; \ - sz--; \ + octet *d = dest, *p; \ + uint32 t[PRE##_BLKSZ/4]; \ + octet y; \ + \ + /* Construct a plan and prepare to follow through. */ \ + rsvr_mkplan(&plan, &pre##_cfbpolicy, ctx->off, sz); \ + BLKC_LOAD(PRE, t, ctx->b); \ + \ + /* Initial portion, fulfilled from the buffer. If the chunk is small \ + * enough, then this will be the only portion. If the buffer is \ + * currently empty, then we must prepare it. \ + */ \ + if (plan.head) { \ + if (!ctx->off) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + } \ + p = ctx->b + ctx->off; ctx->off += plan.head; \ + if (s) while (plan.head--) { y = *s++ ^ *p; *p++ = y; if (d) *d++ = y; } \ + else if (d) { memcpy(d, p, plan.head); d += plan.head; } \ + BLKC_LOAD(PRE, t, ctx->b); \ } \ \ - /* --- 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 (s) { \ - BLKC_XLOAD(PRE, iv, s); \ - s += PRE##_BLKSZ; \ - } \ - if (d) { \ - BLKC_STORE(PRE, d, iv); \ - d += PRE##_BLKSZ; \ - } \ - sz -= PRE##_BLKSZ; \ + /* If the buffer is all used, then reset it ready for next time. */ \ + ctx->off -= plan.from_rsvr; \ + \ + /* Handle multiple whole blocks. */ \ + if (!d) { \ + if (!s) while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + plan.from_input -= PRE##_BLKSZ; \ + } else while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ + } \ + } else { \ + if (!s) while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ + } else while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_XLOAD(PRE, t, s); s += PRE##_BLKSZ; \ + BLKC_STORE(PRE, d, t); d += PRE##_BLKSZ; \ + plan.from_input -= PRE##_BLKSZ; \ } \ - off = 0; \ - BLKC_STORE(PRE, ctx->iv, iv); \ } \ \ - /* --- Tidying up the tail end --- */ \ - \ - if (sz) { \ - small: \ - do { \ - register octet x = *s++; \ - ctx->iv[off] ^= x; \ - if (d) *d++ = ctx->iv[off]; \ - off++; \ - sz--; \ - } while (sz); \ + /* Final portion. Note that the buffer must be empty if there is a \ + * tail, since otherwise the input data would have been part of the \ + * head portion instad. */ \ + if (!plan.tail) \ + BLKC_STORE(PRE, ctx->b, t); \ + else { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + p = ctx->b; ctx->off += plan.tail; \ + if (s) while (plan.tail--) { y = *s++ ^ *p; *p++ = y; if (d) *d++ = y; } \ + else if (d) { memcpy(d, p, plan.tail); d += plan.tail; } \ } \ - \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ } \ \ /* --- @pre_cfbdecrypt@ --- * \ @@ -269,70 +272,58 @@ void pre##_cfbencrypt(pre##_cfbctx *ctx, \ */ \ \ void pre##_cfbdecrypt(pre##_cfbctx *ctx, \ - const void *src, void *dest, \ - size_t sz) \ + const void *src, void *dest, \ + size_t sz) \ { \ + rsvr_plan plan; \ const octet *s = src; \ - octet *d = dest; \ - unsigned 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; \ + octet *d = dest, *p; \ + uint32 t[PRE##_BLKSZ/4], u[PRE##_BLKSZ/4]; \ + octet y; \ + \ + /* Construct a plan and prepare to follow through. */ \ + rsvr_mkplan(&plan, &pre##_cfbpolicy, ctx->off, sz); \ + BLKC_LOAD(PRE, t, ctx->b); \ + \ + /* Initial portion, fulfilled from the buffer. If the chunk is small \ + * enough, then this will be the only portion. If the buffer is \ + * currently empty, then we must prepare it. \ + */ \ + if (plan.head) { \ + if (!ctx->off) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ } \ - off = 0; \ - BLKC_STORE(PRE, ctx->iv, iv); \ + p = ctx->b + ctx->off; \ + ctx->off += plan.head; \ + while (plan.head--) { y = *s++; *d++ = y ^ *p; *p++ = y; } \ + BLKC_LOAD(PRE, t, ctx->b); \ } \ \ - /* --- Tidying up the tail end --- */ \ + /* If the buffer is all used, then reset it ready for next time. */ \ + ctx->off -= plan.from_rsvr; \ \ - if (sz) { \ - small: \ - do { \ - register octet x = *s++; \ - *d++ = ctx->iv[off] ^ x; \ - ctx->iv[off++] = x; \ - sz--; \ - } while (sz); \ + /* Handle multiple whole blocks. */ \ + while (plan.from_input) { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_LOAD(PRE, u, s); s += PRE##_BLKSZ; \ + BLKC_XSTORE(PRE, d, t, u); d += PRE##_BLKSZ; \ + BLKC_MOVE(PRE, t, u); \ + plan.from_input -= PRE##_BLKSZ; \ } \ \ - /* --- Done --- */ \ - \ - ctx->off = off; \ - return; \ + /* Final portion. Note that the buffer must be empty if there is a \ + * tail, since otherwise the input data would have been part of the \ + * head portion instad. */ \ + if (!plan.tail) \ + BLKC_STORE(PRE, ctx->b, t); \ + else { \ + pre##_eblk(&ctx->ctx, t, t); \ + BLKC_STORE(PRE, ctx->b, t); \ + p = ctx->b; \ + ctx->off += plan.tail; \ + while (plan.tail--) { y = *s++; *d++ = y ^ *p; *p++ = y; } \ + } \ } \ \ /* --- Generic cipher interface --- */ \ @@ -353,35 +344,19 @@ static gcipher *ginit(const void *k, size_t sz) \ } \ \ static void gencrypt(gcipher *c, const void *s, void *t, size_t sz) \ -{ \ - gctx *g = (gctx *)c; \ - pre##_cfbencrypt(&g->k, s, 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); \ -} \ + { gctx *g = (gctx *)c; pre##_cfbdecrypt(&g->k, s, t, sz); } \ \ static void gdestroy(gcipher *c) \ -{ \ - gctx *g = (gctx *)c; \ - BURN(*g); \ - S_DESTROY(g); \ -} \ + { gctx *g = (gctx *)c; BURN(*g); S_DESTROY(g); } \ \ static void gsetiv(gcipher *c, const void *iv) \ -{ \ - gctx *g = (gctx *)c; \ - pre##_cfbsetiv(&g->k, iv); \ -} \ + { gctx *g = (gctx *)c; pre##_cfbsetiv(&g->k, iv); } \ \ static void gbdry(gcipher *c) \ -{ \ - gctx *g = (gctx *)c; \ - pre##_cfbbdry(&g->k); \ -} \ + { gctx *g = (gctx *)c; pre##_cfbbdry(&g->k); } \ \ static const gcipher_ops gops = { \ &pre##_cfb, \ @@ -389,19 +364,19 @@ static const gcipher_ops gops = { \ }; \ \ const gccipher pre##_cfb = { \ - #pre "-cfb", pre##_keysz, PRE##_BLKSZ, \ + name "-cfb", pre##_keysz, PRE##_BLKSZ, \ ginit \ }; \ \ -CFB_TEST(PRE, pre) +CFB_TESTX(PRE, pre, name, fname) /*----- Test rig ----------------------------------------------------------*/ -#ifdef TEST_RIG +#define CFB_TEST(PRE, pre) CFB_TESTX(PRE, pre, #pre, #pre) -#include +#ifdef TEST_RIG -#include "daftstory.h" +#include "modes-test.h" /* --- @CFB_TEST@ --- * * @@ -410,91 +385,33 @@ CFB_TEST(PRE, pre) * Use: Standard test rig for CFB functions. */ -#define CFB_TEST(PRE, pre) \ - \ -/* --- Initial plaintext for the test --- */ \ +#define CFB_TESTX(PRE, pre, name, fname) \ \ -static const octet text[] = TEXT; \ +static pre##_ctx key; \ +static pre##_cfbctx ctx; \ \ -/* --- Key and IV to use --- */ \ +static void pre##_cfb_test_setup(const octet *k, size_t ksz) \ + { pre##_init(&key, k, ksz); pre##_cfbsetkey(&ctx, &key); } \ \ -static const octet key[] = KEY; \ -static const octet iv[] = IV; \ +static void pre##_cfb_test_reset(const octet *iv) \ + { pre##_cfbsetiv(&ctx, iv); } \ \ -/* --- Buffers for encryption and decryption output --- */ \ +static void pre##_cfb_test_enc(const octet *s, octet *d, size_t sz) \ + { pre##_cfbencrypt(&ctx, s, d, sz); } \ \ -static octet ct[sizeof(text)]; \ -static octet pt[sizeof(text)]; \ +static void pre##_cfb_test_dec(const octet *s, octet *d, size_t sz) \ + { pre##_cfbdecrypt(&ctx, s, d, sz); } \ \ -static void hexdump(const octet *p, size_t sz, size_t off) \ +int main(int argc, char *argv[]) \ { \ - const octet *q = p + sz; \ - for (sz = 0; p < q; p++, sz++) { \ - printf("%02x", *p); \ - if ((off + 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, 0); \ - printf(", "); hexdump(text + sz, rest, sz); \ - fputc('\n', stdout); \ - printf("\tciphertext = "); hexdump(ct, sz, 0); \ - printf(", "); hexdump(ct + sz, rest, sz); \ - fputc('\n', stdout); \ - printf("\trecovered text = "); hexdump(pt, sz, 0); \ - printf(", "); hexdump(pt + sz, rest, sz); \ - fputc('\n', stdout); \ - fputc('\n', stdout); \ - } \ - if (sz < 63) \ - sz++; \ - else \ - sz += 9; \ - } \ - \ - fputs(status ? " failed\n" : " ok\n", stdout); \ - return (status); \ + return test_encmode(fname "-cfb", PRE##_KEYSZ, PRE##_BLKSZ, 1, 0, \ + pre##_cfb_test_setup, pre##_cfb_test_reset, \ + pre##_cfb_test_enc, pre##_cfb_test_dec, \ + argc, argv); \ } #else -# define CFB_TEST(PRE, pre) +# define CFB_TESTX(PRE, pre, name, fname) #endif /*----- That's all, folks -------------------------------------------------*/