chiark / gitweb /
Counter mode ciphers and pseudo-random generator.
[catacomb] / counter-def.h
1 /* -*-c-*-
2  *
3  * $Id: counter-def.h,v 1.1 2000/06/17 10:51:42 mdw Exp $
4  *
5  * Block cipher counter mode (or long cycle mode)
6  *
7  * (c) 2000 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of Catacomb.
13  *
14  * Catacomb is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * Catacomb is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with Catacomb; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Revision history --------------------------------------------------* 
31  *
32  * $Log: counter-def.h,v $
33  * Revision 1.1  2000/06/17 10:51:42  mdw
34  * Counter mode ciphers and pseudo-random generator.
35  *
36  */
37
38 #ifndef CATACOMB_COUNTER_DEF_H
39 #define CATACOMB_COUNTER_DEF_H
40
41 #ifdef __cplusplus
42   extern "C" {
43 #endif
44
45 /*----- Header files ------------------------------------------------------*/
46
47 #include <stdarg.h>
48 #include <string.h>
49
50 #include <mLib/bits.h>
51 #include <mLib/sub.h>
52
53 #ifndef CATACOMB_ARENA_H
54 #  include "arena.h"
55 #endif
56
57 #ifndef CATACOMB_BLKC_H
58 #  include "blkc.h"
59 #endif
60
61 #ifndef CATACOMB_GCIPHER_H
62 #  include "gcipher.h"
63 #endif
64
65 #ifndef CATACOMB_PARANOIA_H
66 #  include "paranoia.h"
67 #endif
68
69 /*----- Macros ------------------------------------------------------------*/
70
71 /* --- @COUNTER_DEF@ --- *
72  *
73  * Arguments:   @PRE@, @pre@ = prefixes for the underlying block cipher
74  *
75  * Use:         Creates definitions for counter mode.
76  */
77
78 #define COUNTER_DEF(PRE, pre)                                           \
79                                                                         \
80 /* --- @pre_countergetiv@ --- *                                         \
81  *                                                                      \
82  * Arguments:   @const pre_counterctx *ctx@ = pointer to counter        \
83  *                      context                                         \
84  *              @void *iv#@ = pointer to output data block              \
85  *                                                                      \
86  * Returns:     ---                                                     \
87  *                                                                      \
88  * Use:         Reads the currently set IV.  Reading and setting an IV  \
89  *              is not transparent to the cipher.  It will add a `step' \
90  *              which must be matched by a similar operation during     \
91  *              decryption.                                             \
92  */                                                                     \
93                                                                         \
94 void pre##_countergetiv(const pre##_counterctx *ctx, void *iv)          \
95 {                                                                       \
96   BLKC_STORE(PRE, iv, ctx->n);                                          \
97 }                                                                       \
98                                                                         \
99 /* --- @pre_countersetiv@ --- *                                         \
100  *                                                                      \
101  * Arguments:   @pre_counterctx *ctx@ = pointer to counter context      \
102  *              @cnost void *iv@ = pointer to IV to set                 \
103  *                                                                      \
104  * Returns:     ---                                                     \
105  *                                                                      \
106  * Use:         Sets the IV to use for subsequent encryption.           \
107  */                                                                     \
108                                                                         \
109 void pre##_countersetiv(pre##_counterctx *ctx, const void *iv)          \
110 {                                                                       \
111   BLKC_LOAD(PRE, ctx->n, iv);                                           \
112   ctx->off = PRE##_BLKSZ;                                               \
113 }                                                                       \
114                                                                         \
115 /* --- @pre_counterbdry@ --- *                                          \
116  *                                                                      \
117  * Arguments:   @pre_counterctx *ctx@ = pointer to counter context      \
118  *                                                                      \
119  * Returns:     ---                                                     \
120  *                                                                      \
121  * Use:         Inserts a boundary during encryption.  Successful       \
122  *              decryption must place a similar boundary.               \
123  */                                                                     \
124                                                                         \
125 void pre##_counterbdry(pre##_counterctx *ctx)                           \
126 {                                                                       \
127   BLKC_STEP(PRE, ctx->n);                                               \
128   ctx->off = PRE##_BLKSZ;                                               \
129 }                                                                       \
130                                                                         \
131 /* --- @pre_countersetkey@ --- *                                        \
132  *                                                                      \
133  * Arguments:   @pre_counterctx *ctx@ = pointer to counter context      \
134  *              @const pre_ctx *k@ = pointer to cipher context          \
135  *                                                                      \
136  * Returns:     ---                                                     \
137  *                                                                      \
138  * Use:         Sets the counter context to use a different cipher key. \
139  */                                                                     \
140                                                                         \
141 void pre##_countersetkey(pre##_counterctx *ctx, const pre##_ctx *k)     \
142 {                                                                       \
143   ctx->ctx = *k;                                                        \
144 }                                                                       \
145                                                                         \
146 /* --- @pre_counterinit@ --- *                                          \
147  *                                                                      \
148  * Arguments:   @pre_counterctx *ctx@ = pointer to cipher context       \
149  *              @const void *key@ = pointer to the key buffer           \
150  *              @size_t sz@ = size of the key                           \
151  *              @const void *iv@ = pointer to initialization vector     \
152  *                                                                      \
153  * Returns:     ---                                                     \
154  *                                                                      \
155  * Use:         Initializes a counter context ready for use.  You       \
156  *              should ensure that the IV chosen is unique: reusing an  \
157  *              IV will compromise the security of the entire           \
158  *              plaintext.  This is equivalent to calls to @pre_init@,  \
159  *              @pre_countersetkey@ and @pre_countersetiv@.             \
160  */                                                                     \
161                                                                         \
162 void pre##_counterinit(pre##_counterctx *ctx,                           \
163                        const void *key, size_t sz,                      \
164                        const void *iv)                                  \
165 {                                                                       \
166   static octet zero[PRE##_BLKSZ] = { 0 };                               \
167   pre##_init(&ctx->ctx, key, sz);                                       \
168   pre##_countersetiv(ctx, iv ? iv : zero);                              \
169 }                                                                       \
170                                                                         \
171 /* --- @pre_counterencrypt@ --- *                                       \
172  *                                                                      \
173  * Arguments:   @pre_counterctx *ctx@ = pointer to counter context      \
174  *              @const void *src@ = pointer to source data              \
175  *              @void *dest@ = pointer to destination data              \
176  *              @size_t sz@ = size of block to be encrypted             \
177  *                                                                      \
178  * Returns:     ---                                                     \
179  *                                                                      \
180  * Use:         Encrypts or decrypts a block with a block cipher in     \
181  *              counter mode: encryption and decryption are the same in \
182  *              counter.  The destination may be null to just churn the \
183  *              feedback round for a bit.  The source may be null to    \
184  *              use the cipher as a random data generator.              \
185  */                                                                     \
186                                                                         \
187 void pre##_counterencrypt(pre##_counterctx *ctx,                        \
188                           const void *src, void *dest,                  \
189                           size_t sz)                                    \
190 {                                                                       \
191   const octet *s = src;                                                 \
192   octet *d = dest;                                                      \
193   unsigned off = ctx->off;                                              \
194                                                                         \
195   /* --- Empty blocks are trivial --- */                                \
196                                                                         \
197   if (!sz)                                                              \
198     return;                                                             \
199                                                                         \
200   /* --- If I can deal with the block from my buffer, do that --- */    \
201                                                                         \
202   if (sz < PRE##_BLKSZ - off)                                           \
203     goto small;                                                         \
204                                                                         \
205   /* --- Finish off what's left in my buffer --- */                     \
206                                                                         \
207   if (!d)                                                               \
208     sz -= PRE##_BLKSZ - off;                                            \
209   else {                                                                \
210     while (off < PRE##_BLKSZ) {                                         \
211       register octet x = s ? *s++ : 0;                                  \
212       *d++ = ctx->buf[off++] ^ x;                                       \
213       sz--;                                                             \
214     }                                                                   \
215   }                                                                     \
216                                                                         \
217   /* --- Main encryption loop --- */                                    \
218                                                                         \
219   {                                                                     \
220     uint32 n[PRE##_BLKSZ / 4];                                          \
221                                                                         \
222     for (;;) {                                                          \
223       pre##_eblk(&ctx->ctx, ctx->n, n);                                 \
224       BLKC_STEP(PRE, ctx->n);                                           \
225       if (sz < PRE##_BLKSZ)                                             \
226         break;                                                          \
227       if (d) {                                                          \
228         if (!s)                                                         \
229           BLKC_STORE(PRE, d, n);                                        \
230         else {                                                          \
231           uint32 x[PRE##_BLKSZ / 4];                                    \
232           BLKC_LOAD(PRE, x, s);                                         \
233           BLKC_XSTORE(PRE, d, n, x);                                    \
234           s += PRE##_BLKSZ;                                             \
235         }                                                               \
236         d += PRE##_BLKSZ;                                               \
237       }                                                                 \
238       sz -= PRE##_BLKSZ;                                                \
239     }                                                                   \
240                                                                         \
241     BLKC_STORE(PRE, ctx->buf, n);                                       \
242     off = 0;                                                            \
243   }                                                                     \
244                                                                         \
245   /* --- Tidying up the tail end --- */                                 \
246                                                                         \
247   if (sz) {                                                             \
248   small:                                                                \
249     if (!d)                                                             \
250       off += sz;                                                        \
251     else do {                                                           \
252       register octet x = s ? *s++ : 0;                                  \
253       *d++ = ctx->buf[off++] ^ x;                                       \
254       sz--;                                                             \
255     } while (sz);                                                       \
256   }                                                                     \
257                                                                         \
258   /* --- Done --- */                                                    \
259                                                                         \
260   ctx->off = off;                                                       \
261   return;                                                               \
262 }                                                                       \
263                                                                         \
264 /* --- Generic cipher interface --- */                                  \
265                                                                         \
266 static const gcipher_ops gops;                                          \
267                                                                         \
268 typedef struct gctx {                                                   \
269   gcipher c;                                                            \
270   pre##_counterctx k;                                                   \
271 } gctx;                                                                 \
272                                                                         \
273 static gcipher *ginit(const void *k, size_t sz)                         \
274 {                                                                       \
275   gctx *g = S_CREATE(gctx);                                             \
276   g->c.ops = &gops;                                                     \
277   pre##_counterinit(&g->k, k, sz, 0);                                   \
278   return (&g->c);                                                       \
279 }                                                                       \
280                                                                         \
281 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)     \
282 {                                                                       \
283   gctx *g = (gctx *)c;                                                  \
284   pre##_counterencrypt(&g->k, s, t, sz);                                \
285 }                                                                       \
286                                                                         \
287 static void gdestroy(gcipher *c)                                        \
288 {                                                                       \
289   gctx *g = (gctx *)c;                                                  \
290   BURN(*g);                                                             \
291   S_DESTROY(g);                                                         \
292 }                                                                       \
293                                                                         \
294 static void gsetiv(gcipher *c, const void *iv)                          \
295 {                                                                       \
296   gctx *g = (gctx *)c;                                                  \
297   pre##_countersetiv(&g->k, iv);                                        \
298 }                                                                       \
299                                                                         \
300 static void gbdry(gcipher *c)                                           \
301 {                                                                       \
302   gctx *g = (gctx *)c;                                                  \
303   pre##_counterbdry(&g->k);                                             \
304 }                                                                       \
305                                                                         \
306 static const gcipher_ops gops = {                                       \
307   &pre##_counter,                                                       \
308   gencrypt, gencrypt, gdestroy, gsetiv, gbdry                           \
309 };                                                                      \
310                                                                         \
311 const gccipher pre##_counter = {                                        \
312   #pre "-counter", pre##_keysz, PRE##_BLKSZ,                            \
313   ginit                                                                 \
314 };                                                                      \
315                                                                         \
316 /* --- Generic random number generator interface --- */                 \
317                                                                         \
318 typedef struct grctx {                                                  \
319   grand r;                                                              \
320   pre##_counterctx k;                                                   \
321 } grctx;                                                                \
322                                                                         \
323 static void grdestroy(grand *r)                                         \
324 {                                                                       \
325   grctx *g = (grctx *)r;                                                \
326   BURN(*g);                                                             \
327   S_DESTROY(g);                                                         \
328 }                                                                       \
329                                                                         \
330 static int grmisc(grand *r, unsigned op, ...)                           \
331 {                                                                       \
332   grctx *g = (grctx *)r;                                                \
333   va_list ap;                                                           \
334   int rc = 0;                                                           \
335   octet buf[PRE##_BLKSZ];                                               \
336   va_start(ap, op);                                                     \
337                                                                         \
338   switch (op) {                                                         \
339     case GRAND_CHECK:                                                   \
340       switch (va_arg(ap, unsigned)) {                                   \
341         case GRAND_CHECK:                                               \
342         case GRAND_SEEDINT:                                             \
343         case GRAND_SEEDUINT32:                                          \
344         case GRAND_SEEDBLOCK:                                           \
345         case GRAND_SEEDRAND:                                            \
346           rc = 1;                                                       \
347           break;                                                        \
348         default:                                                        \
349           rc = 0;                                                       \
350           break;                                                        \
351       }                                                                 \
352       break;                                                            \
353     case GRAND_SEEDINT:                                                 \
354       BLKC_SET(PRE, g->k.n, va_arg(ap, unsigned));                      \
355       g->k.off = PRE##_BLKSZ;                                           \
356       break;                                                            \
357     case GRAND_SEEDUINT32:                                              \
358       BLKC_SET(PRE, g->k.n, va_arg(ap, uint32));                        \
359       g->k.off = PRE##_BLKSZ;                                           \
360       break;                                                            \
361     case GRAND_SEEDBLOCK: {                                             \
362       const void *p = va_arg(ap, const void *);                         \
363       size_t sz = va_arg(ap, size_t);                                   \
364       if (sz < sizeof(buf)) {                                           \
365         memset(buf, 0, sizeof(buf));                                    \
366         memcpy(buf, p, sz);                                             \
367         p = buf;                                                        \
368       }                                                                 \
369       pre##_countersetiv(&g->k, p);                                     \
370     } break;                                                            \
371     case GRAND_SEEDRAND: {                                              \
372       grand *rr = va_arg(ap, grand *);                                  \
373       rr->ops->fill(rr, buf, sizeof(buf));                              \
374       pre##_countersetiv(&g->k, buf);                                   \
375     } break;                                                            \
376     default:                                                            \
377       GRAND_BADOP;                                                      \
378       break;                                                            \
379   }                                                                     \
380                                                                         \
381   va_end(ap);                                                           \
382   return (rc);                                                          \
383 }                                                                       \
384                                                                         \
385 static octet grbyte(grand *r)                                           \
386 {                                                                       \
387   grctx *g = (grctx *)r;                                                \
388   octet o;                                                              \
389   pre##_counterencrypt(&g->k, 0, &o, 1);                                \
390   return (o);                                                           \
391 }                                                                       \
392                                                                         \
393 static uint32 grword(grand *r)                                          \
394 {                                                                       \
395   grctx *g = (grctx *)r;                                                \
396   octet b[4];                                                           \
397   pre##_counterencrypt(&g->k, 0, b, sizeof(b));                         \
398   return (LOAD32(b));                                                   \
399 }                                                                       \
400                                                                         \
401 static void grfill(grand *r, void *p, size_t sz)                        \
402 {                                                                       \
403   grctx *g = (grctx *)r;                                                \
404   pre##_counterencrypt(&g->k, 0, p, sz);                                \
405 }                                                                       \
406                                                                         \
407 static const grand_ops grops = {                                        \
408   #pre "-counter",                                                      \
409   GRAND_CRYPTO, 0,                                                      \
410   grmisc, grdestroy,                                                    \
411   grword, grbyte, grword, grand_range, grfill                           \
412 };                                                                      \
413                                                                         \
414 /* --- @pre_counterrand@ --- *                                          \
415  *                                                                      \
416  * Arguments:   @const void *k@ = pointer to key material               \
417  *              @size_t sz@ = size of key material                      \
418  *                                                                      \
419  * Returns:     Pointer to generic random number generator interface.   \
420  *                                                                      \
421  * Use:         Creates a random number interface wrapper around an     \
422  *              counter-mode block cipher.                              \
423  */                                                                     \
424                                                                         \
425 grand *pre##_counterrand(const void *k, size_t sz)                      \
426 {                                                                       \
427   grctx *g = S_CREATE(grctx);                                           \
428   g->r.ops = &grops;                                                    \
429   pre##_counterinit(&g->k, k, sz, 0);                                   \
430   return (&g->r);                                                       \
431 }                                                                       \
432                                                                         \
433 COUNTER_TEST(PRE, pre)
434
435 /*----- Test rig ----------------------------------------------------------*/
436
437 #ifdef TEST_RIG
438
439 #include <stdio.h>
440
441 #include "daftstory.h"
442
443 /* --- @COUNTER_TEST@ --- *
444  *
445  * Arguments:   @PRE@, @pre@ = prefixes for block cipher definitions
446  *
447  * Use:         Standard test rig for counter functions.
448  */
449
450 #define COUNTER_TEST(PRE, pre)                                          \
451                                                                         \
452 /* --- Initial plaintext for the test --- */                            \
453                                                                         \
454 static const octet text[] = TEXT;                                       \
455                                                                         \
456 /* --- Key and IV to use --- */                                         \
457                                                                         \
458 static const octet key[] = KEY;                                         \
459 static const octet iv[] = IV;                                           \
460                                                                         \
461 /* --- Buffers for encryption and decryption output --- */              \
462                                                                         \
463 static octet ct[sizeof(text)];                                          \
464 static octet pt[sizeof(text)];                                          \
465                                                                         \
466 static void hexdump(const octet *p, size_t sz)                          \
467 {                                                                       \
468   const octet *q = p + sz;                                              \
469   for (sz = 0; p < q; p++, sz++) {                                      \
470     printf("%02x", *p);                                                 \
471     if ((sz + 1) % PRE##_BLKSZ == 0)                                    \
472       putchar(':');                                                     \
473   }                                                                     \
474 }                                                                       \
475                                                                         \
476 int main(void)                                                          \
477 {                                                                       \
478   size_t sz = 0, rest;                                                  \
479   pre##_counterctx ctx;                                                 \
480   int status = 0;                                                       \
481   int done = 0;                                                         \
482   pre##_ctx k;                                                          \
483                                                                         \
484   size_t keysz = PRE##_KEYSZ ?                                          \
485     PRE##_KEYSZ : strlen((const char *)key);                            \
486                                                                         \
487   fputs(#pre "-counter: ", stdout);                                     \
488                                                                         \
489   pre##_init(&k, key, keysz);                                           \
490   pre##_countersetkey(&ctx, &k);                                        \
491                                                                         \
492   while (sz <= sizeof(text)) {                                          \
493     rest = sizeof(text) - sz;                                           \
494     memcpy(ct, text, sizeof(text));                                     \
495     pre##_countersetiv(&ctx, iv);                                       \
496     pre##_counterencrypt(&ctx, ct, ct, sz);                             \
497     pre##_counterencrypt(&ctx, ct + sz, ct + sz, rest);                 \
498     memcpy(pt, ct, sizeof(text));                                       \
499     pre##_countersetiv(&ctx, iv);                                       \
500     pre##_counterencrypt(&ctx, pt, pt, rest);                           \
501     pre##_counterencrypt(&ctx, pt + rest, pt + rest, sz);               \
502     if (memcmp(pt, text, sizeof(text)) == 0) {                          \
503       done++;                                                           \
504       if (sizeof(text) < 40 || done % 8 == 0)                           \
505         fputc('.', stdout);                                             \
506       if (done % 480 == 0)                                              \
507         fputs("\n\t", stdout);                                          \
508       fflush(stdout);                                                   \
509     } else {                                                            \
510       printf("\nError (sz = %lu)\n", (unsigned long)sz);                \
511       status = 1;                                                       \
512       printf("\tplaintext      = "); hexdump(text, sz);                 \
513         printf(", "); hexdump(text + sz, rest);                         \
514         fputc('\n', stdout);                                            \
515       printf("\tciphertext     = "); hexdump(ct, sz);                   \
516         printf(", "); hexdump(ct + sz, rest);                           \
517         fputc('\n', stdout);                                            \
518       printf("\trecovered text = "); hexdump(pt, sz);                   \
519         printf(", "); hexdump(pt + sz, rest);                           \
520         fputc('\n', stdout);                                            \
521       fputc('\n', stdout);                                              \
522     }                                                                   \
523     if (sz < 63)                                                        \
524       sz++;                                                             \
525     else                                                                \
526       sz += 9;                                                          \
527   }                                                                     \
528                                                                         \
529   fputs(status ? " failed\n" : " ok\n", stdout);                        \
530   return (status);                                                      \
531 }
532
533 #else
534 #  define COUNTER_TEST(PRE, pre)
535 #endif
536
537 /*----- That's all, folks -------------------------------------------------*/
538
539 #ifdef __cplusplus
540   }
541 #endif
542
543 #endif