e1bacfe55eab8bca2a7e97d2e1d92d5c79631c8a
[become] / src / idea.c
1 /* -*-c-*-
2 *
3 * $Id: idea.c,v 1.1 1997/07/21 13:47:49 mdw Exp $
4 *
5 * IDEA encryption routines
6 * Based on Straylight ARM assembler routines
7 *
8 * (c) 1996, 1997 Mark Wooding
9 */
10
11 /*----- Licencing notice --------------------------------------------------*
12 *
13 * This file is part of `become'
14 *
15 * `Become' is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * `Become' is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with `become'; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29
30 /*----- Revision history --------------------------------------------------*
31 *
32 * $Log: idea.c,v $
33 * Revision 1.1 1997/07/21 13:47:49 mdw
34 * Initial revision
35 *
36 */
37
38 /*----- Notes -------------------------------------------------------------*
39 *
40 * This code is optimised for 32-bit processors with reasonable numbers of
41 * registers. Hopefully it should still work on a Spectrum, although rather
42 * slowly. I do assume two's complement arithmetic.
43 *
44 * Since this is actually /decompiled/, by hand, from some existing assembler
45 * code, you can expect some parts to be a little strange.
46 */
47
48 /*----- Header files ------------------------------------------------------*/
49
50 #include <stdio.h>
51
52 #include "config.h"
53 #include "idea.h"
54 #include "utils.h"
55
56 /*----- Low-level support functions ---------------------------------------*/
57
58 /* --- @idea__inv@ --- *
59 *
60 * Arguments: @int n@ = number to invert
61 *
62 * Returns: Multiplicative inverse of n, mod 2^{16} + 1
63 */
64
65 static int idea__inv(int n)
66 {
67 long m, a, b, q, r, t;
68
69 /* --- Check the easy case --- */
70
71 if (!n)
72 return (0);
73
74 /* --- Start off the loop --- */
75
76 m = 0x10001L;
77 a = 1;
78 b = 0;
79 for (;;) {
80 q = m / n, r = m % n;
81 if (!r)
82 break;
83 m = n, n = r;
84 t = a, a = b - q * a, b = t;
85 }
86
87 /* --- Get return value in range --- */
88
89 if (a < 0)
90 a += 1;
91 return ((int) a & 0xFFFF);
92 }
93
94 /* --- @_mul@ --- *
95 *
96 * An evil macro to do multiplication. Satan lives here.
97 */
98
99 #define _mul(x, y) \
100 (void)( \
101 x &= ffff, x ? \
102 ( y &= ffff, y ? \
103 ((y = x * y), x = y & ffff, y = y >> 16, x < y ? \
104 (x = x - y + 1) : (x = x - y)) : \
105 (x = 1 - x)) : \
106 (x = 1 - y) \
107 )
108
109 /*----- Key unpacking functions -------------------------------------------*/
110
111 /* --- @idea_ekeys@ --- *
112 *
113 * Arguments: @idea_key *k@ = the expanded key buffer
114 * @const unsigned char *key@ = the user's key encryption key
115 *
116 * Returns: ---
117 *
118 * Use: Unpacks an encryption key.
119 */
120
121 void idea_ekeys(idea_key *k, const unsigned char *key)
122 {
123 /* --- Convince compiler to do this properly --- */
124
125 register const int ffff = 0xFFFF;
126
127 uint_32 ka, kb, kc, kd;
128 int count;
129 int *p = k->k;
130
131 /* --- Load the 4 words from the block --- *
132 *
133 * Don't ask.
134 */
135
136 ka = load32(key + 0);
137 kb = load32(key + 4);
138 kc = load32(key + 8);
139 kd = load32(key + 12);
140
141 for (count = 48; count > 0; count -= 8) {
142
143 /* --- Unpack halfwords into the block --- */
144
145 *p++ = (ka >> 16) & ffff;
146 *p++ = ka & ffff;
147 *p++ = (kb >> 16) & ffff;
148 *p++ = kb & ffff;
149 *p++ = (kc >> 16) & ffff;
150 *p++ = kc & ffff;
151 *p++ = (kd >> 16) & ffff;
152 *p++ = kd & ffff;
153
154 /* --- Now rotate the 128-bit key --- */
155
156 {
157 uint_32 kx = ka;
158 ka = ((ka << 25) | (kb >> 7)) & 0xffffffffu;
159 kb = ((kb << 25) | (kc >> 7)) & 0xffffffffu;
160 kc = ((kc << 25) | (kd >> 7)) & 0xffffffffu;
161 kd = ((kd << 25) | (kx >> 7)) & 0xffffffffu;
162 }
163 }
164
165 /* --- Write the tail-enders over --- */
166
167 *p++ = (ka >> 16) & ffff;
168 *p++ = ka & ffff;
169 *p++ = (kb >> 16) & ffff;
170 *p++ = kb & ffff;
171 }
172
173 /* --- @idea_invertKey@ --- *
174 *
175 * Arguments: @const idea_key *in@ = pointer to input expanded key buffer
176 * @idea_key *out@ = pointer to output expanded key buffer
177 *
178 * Returns: ---
179 *
180 * Use: Computes the inverse (decryption) key given an expanded
181 * IDEA encryption key.
182 */
183
184 void idea_invertKey(const idea_key *in, idea_key *out)
185 {
186 int i;
187 unsigned a, b, c, d, e, f;
188 int *ibuf = in->k, *obuf = out->k;
189
190 /* --- Deal with identical input and output buffers --- */
191
192 if (in == out) {
193 idea_key t;
194 memcpy(&t, in, sizeof(t));
195 idea_invertKey(&t, out);
196 return;
197 }
198
199 /* --- Do the real work --- */
200
201 ibuf += IDEA_EXPKEYSIZE;
202 for (i = 8; i; i--) {
203 ibuf -= 6;
204 a = ibuf[0];
205 b = ibuf[1];
206 c = ibuf[2];
207 d = ibuf[3];
208 e = ibuf[4];
209 f = ibuf[5];
210
211 c = idea__inv(c);
212 f = idea__inv(f);
213 d = 0x10000 - d;
214 e = 0x10000 - e;
215
216 if (i < 8)
217 d ^= e, e ^= d, d ^= e;
218
219 obuf[0] = c;
220 obuf[1] = d;
221 obuf[2] = e;
222 obuf[3] = f;
223 obuf[4] = a;
224 obuf[5] = b;
225 obuf += 6;
226 }
227
228 /* --- Deal with the tail-enders --- */
229
230 ibuf -= 4;
231 c = ibuf[0];
232 d = ibuf[1];
233 e = ibuf[2];
234 f = ibuf[3];
235
236 c = idea__inv(c);
237 f = idea__inv(f);
238 d = 0x10000 - d;
239 e = 0x10000 - e;
240
241 obuf[0] = c;
242 obuf[1] = d;
243 obuf[2] = e;
244 obuf[3] = f;
245 }
246
247 /* --- @idea_dkeys@ --- *
248 *
249 * Arguments: @idea_key *k@ = the expanded key buffer
250 * @const unsigned char *key@ = the user's key encryption key
251 *
252 * Returns: ---
253 *
254 * Use: Unpacks a decryption key.
255 */
256
257 void idea_dkeys(idea_key *k, const unsigned char *key)
258 {
259 idea_key t;
260 idea_ekeys(&t, key);
261 idea_invertKey(&t, k);
262 }
263
264 /*----- Main IDEA cipher --------------------------------------------------*/
265
266 /* --- @idea_encrypt@ --- *
267 *
268 * Arguments: @const idea_key *k@ = key to use
269 * @const void *src@ = block to encrypt
270 * @void *dest@ = where to store the result
271 *
272 * Returns: ---
273 *
274 * Use: Encrypts (or decrypts) a block, using the IDEA cryptosystem.
275 * Since the decryption operation is the same as encryption
276 * except that a different key buffer is used, this is all we
277 * need to complete the simple bits.
278 *
279 * For people following this at home: I've been very sloppy
280 * about chopping off excess bits from the ints here. Most of
281 * the time it doesn't matter, and when it does, in the
282 * multiplication stage, the macro does this for us.
283 *
284 * Our @register const int ffff@ makes another appearance. This
285 * might suggest to compilers that having this constant
286 * available would be beneficial.
287 *
288 * Registers are in short supply here. So is legibility.
289 */
290
291 #if defined(TEST_RIG) && defined(DUMPROUNDS)
292 # define _dump(a,b,c,d) \
293 printf(" %5lu %5lu %5lu %5lu\n", \
294 a & ffff, b & ffff, c & ffff, d & ffff)
295 #else
296 # define _dump(a,b,c,d) ((void)0)
297 #endif
298
299 #define _round(a, b, c, d) do { \
300 _dump(a, b, c, d); \
301 u = kp[0]; v = kp[1]; w = kp[2]; x = kp[3]; y = kp[4]; z = kp[5]; \
302 kp += 6; \
303 _mul(a, u); b += v; c += w; _mul(d, x); \
304 u = a ^ c; v = b ^ d; _mul(u, y); v += u; _mul(v, z); u += v; \
305 a ^= v; b ^= u; c ^= v; d ^= u; \
306 _dump(a, b, c, d); \
307 } while (0) \
308
309 void idea_encrypt(const idea_key *k, const void *src, void *dest)
310 {
311 register const int ffff = 0xFFFF;
312 const unsigned char *usrc = src;
313 unsigned char *udest = dest;
314 int *kp = k->k;
315
316 uint_32 a, b, c, d;
317 uint_32 u, v, w, x, y, z;
318
319 /* --- Unpack next block into registers --- */
320
321 a = (usrc[0] << 8) | usrc[1];
322 b = (usrc[2] << 8) | usrc[3];
323 c = (usrc[4] << 8) | usrc[5];
324 d = (usrc[6] << 8) | usrc[7];
325
326 /* --- Now run the block through the eight rounds --- *
327 *
328 * Notice how the arguments swap around so as I don't have to move the
329 * values about.
330 */
331
332 _round(a, b, c, d);
333 _round(a, c, b, d);
334 _round(a, b, c, d);
335 _round(a, c, b, d);
336
337 _round(a, b, c, d);
338 _round(a, c, b, d);
339 _round(a, b, c, d);
340 _round(a, c, b, d);
341
342 /* --- Do the output transformation --- */
343
344 u = kp[0];
345 v = kp[1];
346 w = kp[2];
347 x = kp[3];
348 _mul(a, u);
349 b += w;
350 c += v;
351 _mul(d, x);
352
353 /* --- Repack and store the block --- */
354
355 udest[0] = (a >> 8) & 0xFF; udest[1] = a & 0xFF;
356 udest[2] = (c >> 8) & 0xFF; udest[3] = c & 0xFF;
357 udest[4] = (b >> 8) & 0xFF; udest[5] = b & 0xFF;
358 udest[6] = (d >> 8) & 0xFF; udest[7] = d & 0xFF;
359 }
360
361 /*----- Debugging driver --------------------------------------------------*/
362
363 #ifdef TEST_RIG
364
365 #define TESTENCRYPTION
366
367 void dumpbuf(int *k)
368 {
369 int i;
370 printf("Round ");
371 for (i = 1; i <= 6; i++)
372 printf("%5i ", i);
373 for (i = 0; i < 52; i++) {
374 if (i % 6 == 0)
375 printf("\n %i ", i / 6 + 1);
376 printf("%5i ", *k++);
377 }
378 printf("\n\n");
379 }
380
381 void dumpblk(char *bb)
382 {
383 unsigned char *b = (unsigned char *)bb;
384 printf("++ %5u %5u %5u %5u\n",
385 (b[0]<<8)|b[1],
386 (b[2]<<8)|b[3],
387 (b[4]<<8)|b[5],
388 (b[6]<<8)|b[7]);
389 }
390
391 int main(void)
392 {
393
394 #ifdef TESTMULTIPLY
395 {
396 unsigned int i, j;
397 char buf[256];
398 int ffff = 0xFFFF;
399 for (;;) {
400 gets(buf);
401 if (!buf[0])
402 break;
403 sscanf(buf, "%u%u", &i, &j);
404 _mul(i, j);
405 printf("%u\n", i);
406 }
407 }
408 #endif
409
410 #ifdef TESTENCRYPTION
411 {
412 int i;
413 int f;
414
415 unsigned char k[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8 };
416 idea_key e, d;
417 unsigned char b[] = { 0, 0, 0, 1, 0, 2, 0, 3 };
418
419 static idea_key correct_e = { {
420 1, 2, 3, 4, 5, 6,
421 7, 8, 1024, 1536, 2048, 2560,
422 3072, 3584, 4096, 512, 16, 20,
423 24, 28, 32, 4, 8, 12,
424 10240, 12288, 14336, 16384, 2048, 4096,
425 6144, 8192, 112, 128, 16, 32,
426 48, 64, 80, 96, 0, 8192,
427 16384, 24576, 32768, 40960, 49152, 57345,
428 128, 192, 256, 320
429 } };
430
431 static idea_key correct_d = { {
432 65025, 65344, 65280, 26010, 49152, 57345,
433 65533, 32768, 40960, 52428, 0, 8192,
434 42326, 65456, 65472, 21163, 16, 32,
435 21835, 65424, 57344, 65025, 2048, 4096,
436 13101, 51200, 53248, 65533, 8, 12,
437 19115, 65504, 65508, 49153, 16, 20,
438 43670, 61440, 61952, 65409, 2048, 2560,
439 18725, 64512, 65528, 21803, 5, 6,
440 1, 65534, 65533, 49153
441 } };
442
443 static unsigned char correct_encrypt[] = {
444 4603 / 256, 4603 % 256,
445 60715 / 256, 60715 % 256,
446 408 / 256, 408 % 256,
447 28133 / 256, 28133 % 256
448 };
449
450 static unsigned char correct_decrypt[] = {
451 0, 0, 0, 1, 0, 2, 0, 3
452 };
453
454 idea_ekeys(&e, k);
455 dumpbuf(e.k);
456
457 f = 1;
458 for (i = 0; i < IDEA_EXPKEYSIZE; i++) {
459 if (e.k[i] != correct_e.k[i]) {
460 f = 0;
461 printf("!!! bad encryption key values!\n\n");
462 }
463 }
464 if (f)
465 printf("*** expanded encryption key correct\n\n");
466
467 idea_dkeys(&d, k);
468 dumpbuf(d.k);
469
470 f = 1;
471 for (i = 0; i < IDEA_EXPKEYSIZE; i++) {
472 if (d.k[i] != correct_d.k[i]) {
473 f = 0;
474 printf("!!! bad decryption key values!\n\n");
475 }
476 }
477 if (f)
478 printf("*** expanded decryption key correct\n\n");
479
480 idea_encrypt(&e, b, b);
481 dumpblk(b);
482 if (memcmp(b, correct_encrypt, 8) == 0)
483 printf("*** correct encipherment\n\n");
484 else
485 printf("!!! bad encipherment\n\n");
486
487 idea_encrypt(&d, b, b);
488 dumpblk(b);
489 if (memcmp(b, correct_decrypt, 8) == 0)
490 printf("*** correct decipherment\n");
491 else
492 printf("!!! bad decipherment\n");
493 }
494 #endif
495
496 return (0);
497 }
498
499 #endif
500
501 /*----- That's all, folks -------------------------------------------------*/