Generic interface.
[u/mdw/catacomb] / ecb.h
1 /* -*-c-*-
2 *
3 * $Id: ecb.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
4 *
5 * Ciphertext block chaining for block ciphers
6 *
7 * (c) 1999 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: ecb.h,v $
33 * Revision 1.1 1999/09/03 08:41:12 mdw
34 * Initial import.
35 *
36 */
37
38 #ifndef ECB_H
39 #define ECB_H
40
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44
45 /*----- Header files ------------------------------------------------------*/
46
47 #include <assert.h>
48 #include <string.h>
49
50 #include <mLib/bits.h>
51
52 #ifndef BLKC_H
53 # include "blkc.h"
54 #endif
55
56 /*----- Macros ------------------------------------------------------------*/
57
58 /* --- @ECB_DECL@ --- *
59 *
60 * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
61 *
62 * Use: Creates declarations for ECB stealing mode.
63 */
64
65 #define ECB_DECL(PRE, pre) \
66 \
67 typedef struct pre ## _ecbctx { \
68 pre ## _ctx ctx; /* Underlying cipher context */ \
69 } pre ## _ecbctx; \
70 \
71 extern void pre ## _ecbsetkey(pre ## _ecbctx */*ctx*/, \
72 const pre ## _ctx */*k*/); \
73 \
74 extern void pre ## _ecbinit(pre ## _ecbctx */*ctx*/, \
75 const void */*key*/, size_t /*sz*/, \
76 const void */*iv*/); \
77 \
78 extern void pre ## _ecbencrypt(pre ## _ecbctx */*ctx*/, \
79 const void */*src*/, void */*dest*/, \
80 size_t /*sz*/); \
81 \
82 extern void pre ## _ecbdecrypt(pre ## _ecbctx */*ctx*/, \
83 const void */*src*/, void */*dest*/, \
84 size_t /*sz*/); \
85
86 /* --- @ECB_DEF@ --- *
87 *
88 * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
89 *
90 * Use: Creates an implementation for ECB stealing mode.
91 */
92
93 #define ECB_DEF(PRE, pre) \
94 \
95 /* --- @pre_ecbsetkey@ --- * \
96 * \
97 * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \
98 * @const pre_ctx *k@ = pointer to cipher context \
99 * \
100 * Returns: --- \
101 * \
102 * Use: Sets the ECB context to use a different cipher key. \
103 */ \
104 \
105 void pre ## _ecbsetkey(pre ## _ecbctx *ctx, const pre ## _ctx *k) \
106 { \
107 ctx->ctx = *k; \
108 } \
109 \
110 /* --- @pre_ecbinit@ --- * \
111 * \
112 * Arguments: @pre_ecbctx *ctx@ = pointer to cipher context \
113 * @const void *key@ = pointer to the key buffer \
114 * @size_t sz@ = size of the key \
115 * @const void *iv@ = pointer to initialization vector \
116 * \
117 * Returns: --- \
118 * \
119 * Use: Initializes an ECB context ready for use. This is \
120 * equivalent to calls to @pre_init@ and @pre_setkey@. \
121 */ \
122 \
123 void pre ## _ecbinit(pre ## _ecbctx *ctx, \
124 const void *key, size_t sz, \
125 const void *iv) \
126 { \
127 pre ## _init(&ctx->ctx, key, sz); \
128 } \
129 \
130 /* --- @pre_ecbencrypt@ --- * \
131 * \
132 * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \
133 * @const void *src@ = pointer to source data \
134 * @void *dest@ = pointer to destination data \
135 * @size_t sz@ = size of block to be encrypted \
136 * \
137 * Returns: --- \
138 * \
139 * Use: Encrypts a block with a block cipher in ECB mode, with \
140 * ciphertext stealing and other clever tricks. \
141 * Essentially, data can be encrypted in arbitrary sized \
142 * chunks, although decryption must use the same chunks. \
143 */ \
144 \
145 void pre ## _ecbencrypt(pre ## _ecbctx *ctx, \
146 const void *src, void *dest, \
147 size_t sz) \
148 { \
149 const octet *s = src; \
150 octet *d = dest; \
151 \
152 /* --- Empty blocks are trivial --- */ \
153 \
154 if (!sz) \
155 return; \
156 \
157 /* --- Short blocks aren't allowed in ECB --- * \
158 * \
159 * There's absolutely nothing secure I can do with them. \
160 */ \
161 \
162 assert(((void)"ECB must have at least one whole block to work with", \
163 sz >= PRE ## _BLKSZ)); \
164 \
165 /* --- Do the main chunk of encryption --- * \
166 * \
167 * This will do the whole lot if it's a whole number of blocks. Just \
168 * give each block to the cipher in turn. This is trivial. \
169 * Hopefully... \
170 */ \
171 \
172 while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \
173 uint32 x[PRE ## _BLKSZ / 4]; \
174 BLKC_LOAD(PRE, x, s); \
175 pre ## _eblk(&ctx->ctx, x, x); \
176 BLKC_STORE(PRE, d, x); \
177 s += PRE ## _BLKSZ; \
178 d += PRE ## _BLKSZ; \
179 sz -= PRE ## _BLKSZ; \
180 } \
181 \
182 /* --- Do the tail-end block and bit-left-over --- * \
183 * \
184 * This isn't very efficient. That shouldn't matter much. \
185 */ \
186 \
187 if (sz) { \
188 uint32 x[PRE ## _BLKSZ / 4]; \
189 octet b[PRE ## _BLKSZ]; \
190 unsigned i; \
191 \
192 /* --- Let @sz@ be the size of the partial block --- */ \
193 \
194 sz -= PRE ## _BLKSZ; \
195 \
196 /* --- First stage --- * \
197 * \
198 * Read in the current block, and encrypt it. The first part of \
199 * the result is the partial ciphertext block. Don't write that \
200 * out yet, because I've not read the partial plaintext block. \
201 */ \
202 \
203 BLKC_LOAD(PRE, x, s); \
204 pre ## _eblk(&ctx->ctx, x, x); \
205 BLKC_STORE(PRE, b, x); \
206 \
207 /* --- Second stage --- * \
208 * \
209 * Now move in the partial plaintext block, writing out the \
210 * ciphertext as I go. Then encrypt, and write the complete \
211 * ciphertext block. \
212 */ \
213 \
214 s += PRE ## _BLKSZ; \
215 d += PRE ## _BLKSZ; \
216 for (i = 0; i < sz; i++) { \
217 register octet y = b[i]; \
218 b[i] = s[i]; \
219 d[i] = y; \
220 } \
221 BLKC_LOAD(PRE, x, b); \
222 pre ## _eblk(&ctx->ctx, x, x); \
223 BLKC_STORE(PRE, d - PRE ## _BLKSZ, x); \
224 } \
225 \
226 /* --- Done --- */ \
227 \
228 return; \
229 } \
230 \
231 /* --- @pre_ecbdecrypt@ --- * \
232 * \
233 * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \
234 * @const void *src@ = pointer to source data \
235 * @void *dest@ = pointer to destination data \
236 * @size_t sz@ = size of block to be encrypted \
237 * \
238 * Returns: --- \
239 * \
240 * Use: Encrypts a block with a block cipher in ECB mode, with \
241 * ciphertext stealing and other clever tricks. \
242 * Essentially, data can be encrypted in arbitrary sized \
243 * chunks, although decryption must use the same chunks. \
244 */ \
245 \
246 void pre ## _ecbdecrypt(pre ## _ecbctx *ctx, \
247 const void *src, void *dest, \
248 size_t sz) \
249 { \
250 const octet *s = src; \
251 octet *d = dest; \
252 \
253 /* --- Empty blocks are trivial --- */ \
254 \
255 if (!sz) \
256 return; \
257 \
258 /* --- Short blocks aren't allowed in ECB --- * \
259 * \
260 * There's absolutely nothing secure I can do with them. \
261 */ \
262 \
263 assert(((void)"ECB must have at least one whole block to work with", \
264 sz >= PRE ## _BLKSZ)); \
265 \
266 /* --- Do the main chunk of decryption --- * \
267 * \
268 * This will do the whole lot if it's a whole number of blocks. \
269 * Each block is just handed to the block cipher in turn. \
270 */ \
271 \
272 while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \
273 uint32 x[PRE ## _BLKSZ / 4]; \
274 BLKC_LOAD(PRE, x, s); \
275 pre ## _dblk(&ctx->ctx, x, x); \
276 BLKC_STORE(PRE, d, x); \
277 s += PRE ## _BLKSZ; \
278 d += PRE ## _BLKSZ; \
279 sz -= PRE ## _BLKSZ; \
280 } \
281 \
282 /* --- Do the tail-end block and bit-left-over --- * \
283 * \
284 * This isn't very efficient. That shouldn't matter much. \
285 */ \
286 \
287 if (sz) { \
288 uint32 x[PRE ## _BLKSZ / 4]; \
289 octet b[PRE ## _BLKSZ]; \
290 unsigned i; \
291 \
292 /* --- Let @sz@ be the size of the partial block --- */ \
293 \
294 sz -= PRE ## _BLKSZ; \
295 \
296 /* --- First stage --- * \
297 * \
298 * Take the complete ciphertext block, and decrypt it. This block \
299 * is carried over for the next encryption operation. \
300 */ \
301 \
302 BLKC_LOAD(PRE, x, s); \
303 pre ## _dblk(&ctx->ctx, x, x); \
304 BLKC_STORE(PRE, b, x); \
305 \
306 /* --- Second stage --- * \
307 * \
308 * The first few bytes are the partial plaintext block. Write that \
309 * and replace with the partial ciphertext block. Then decrypt \
310 * what's left as the complete plaintext. \
311 */ \
312 \
313 s += PRE ## _BLKSZ; \
314 d += PRE ## _BLKSZ; \
315 for (i = 0; i < sz; i++) { \
316 register octet y = s[i]; \
317 d[i] = b[i]; \
318 b[i] = y; \
319 } \
320 BLKC_LOAD(PRE, x, b); \
321 pre ## _dblk(&ctx->ctx, x, x); \
322 BLKC_STORE(PRE, d - PRE ## _BLKSZ, x); \
323 } \
324 \
325 /* --- Done --- */ \
326 \
327 return; \
328 } \
329 \
330 ECB_TEST(PRE, pre)
331
332 /*----- Test rig ----------------------------------------------------------*/
333
334 #ifdef TEST_RIG
335
336 #include <stdio.h>
337
338 #include "daftstory.h"
339
340 /* --- @ECB_TEST@ --- *
341 *
342 * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions
343 *
344 * Use: Standard test rig for ECB functions.
345 */
346
347 #define ECB_TEST(PRE, pre) \
348 \
349 /* --- Initial plaintext for the test --- */ \
350 \
351 static const octet text[] = TEXT; \
352 \
353 /* --- Key and IV to use --- */ \
354 \
355 static const octet key[] = KEY; \
356 static const octet iv[] = IV; \
357 \
358 /* --- Buffers for encryption and decryption output --- */ \
359 \
360 static octet ct[sizeof(text)]; \
361 static octet pt[sizeof(text)]; \
362 \
363 static void hexdump(const octet *p, size_t sz) \
364 { \
365 const octet *q = p + sz; \
366 for (sz = 0; p < q; p++, sz++) { \
367 printf("%02x", *p); \
368 if ((sz + 1) % PRE ## _BLKSZ == 0) \
369 putchar(':'); \
370 } \
371 } \
372 \
373 int main(void) \
374 { \
375 size_t sz = 0, rest; \
376 pre ## _ecbctx ctx; \
377 int status = 0; \
378 int done = 0; \
379 \
380 size_t keysz = PRE ## _KEYSZ ? \
381 PRE ## _KEYSZ : strlen((const char *)key); \
382 \
383 fputs(#pre "-ecb: ", stdout); \
384 \
385 pre ## _ecbinit(&ctx, key, keysz, iv); \
386 \
387 while (sz <= sizeof(text)) { \
388 rest = sizeof(text) - sz; \
389 if ((sz != 0 && sz < PRE ## _BLKSZ) || \
390 (rest != 0 && rest < PRE ## _BLKSZ)) \
391 goto next; \
392 memcpy(ct, text, sizeof(text)); \
393 pre ## _ecbencrypt(&ctx, ct, ct, sz); \
394 pre ## _ecbencrypt(&ctx, ct + sz, ct + sz, rest); \
395 memcpy(pt, ct, sizeof(text)); \
396 pre ## _ecbdecrypt(&ctx, pt, pt, sz); \
397 pre ## _ecbdecrypt(&ctx, pt + sz, pt + sz, rest); \
398 if (memcmp(pt, text, sizeof(text)) == 0) { \
399 done++; \
400 if (sizeof(text) < 40 || done % 8 == 0) \
401 fputc('.', stdout); \
402 if (done % 480 == 0) \
403 fputs("\n\t", stdout); \
404 fflush(stdout); \
405 } else { \
406 printf("\nError (sz = %lu)\n", (unsigned long)sz); \
407 status = 1; \
408 printf("\tplaintext = "); hexdump(text, sz); \
409 printf(", "); hexdump(text + sz, rest); \
410 fputc('\n', stdout); \
411 printf("\tciphertext = "); hexdump(ct, sz); \
412 printf(", "); hexdump(ct + sz, rest); \
413 fputc('\n', stdout); \
414 printf("\trecovered text = "); hexdump(pt, sz); \
415 printf(", "); hexdump(pt + sz, rest); \
416 fputc('\n', stdout); \
417 fputc('\n', stdout); \
418 } \
419 next: \
420 if (sz < 63) \
421 sz++; \
422 else \
423 sz += 9; \
424 } \
425 \
426 fputs(status ? " failed\n" : " ok\n", stdout); \
427 return (status); \
428 }
429
430 #else
431 # define ECB_TEST(PRE, pre)
432 #endif
433
434 /*----- That's all, folks -------------------------------------------------*/
435
436 #ifdef __cplusplus
437 }
438 #endif
439
440 #endif