chiark / gitweb /
math/gfx-sqr.c: Use bithacking rather than a table for squaring.
[catacomb] / symm / safer.c
1 /* -*-c-*-
2  *
3  * The SAFER block cipher
4  *
5  * (c) 2001 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
12  * Catacomb is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * Catacomb is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with Catacomb; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <assert.h>
31 #include <stdio.h>
32
33 #include <mLib/bits.h>
34
35 #include "blkc.h"
36 #include "gcipher.h"
37 #include "paranoia.h"
38 #include "safer.h"
39
40 /*----- Global variables --------------------------------------------------*/
41
42 const octet safer_keysz[] = { KSZ_SET, 8, 16, 0 };
43
44 /*----- Important tables --------------------------------------------------*/
45
46 extern const octet safer_s[256], safer_si[256];
47 #define S safer_s
48 #define SI safer_si
49
50 /*----- Main code ---------------------------------------------------------*/
51
52 /* --- @safer_setup@ --- *
53  *
54  * Arguments:   @safer_ctx *k@ = pointer to context to initialize
55  *              @unsigned r@ = number of rounds wanted
56  *              @unsigned f@ = various other flags
57  *              @const void *buf@ = pointer to key material
58  *              @size_t sz@ = size of key material in bytes
59  *
60  * Returns:     ---
61  *
62  * Use:         Initializes an SAFER expanded key, with lots of options
63  *              controlling how to do it.
64  */
65
66 struct ksched {
67   unsigned i;
68   octet x[9];
69 };
70
71 static void init(struct ksched *t, const octet *k)
72 {
73   memcpy(t->x, k, 8);
74   t->i = 1;
75 }
76
77 static void init_sk(struct ksched *t, const octet *k)
78 {
79   unsigned i;
80   octet x;
81   memcpy(t->x, k, 8);
82   for (x = 0, i = 0; i < 8; x ^= k[i++])
83     ;
84   t->x[8] = x;
85   t->i = 1;
86 }
87
88 static void next(struct ksched *t, octet *k)
89 {
90   unsigned i;
91   if (k) {
92     memcpy(k, t->x, 8);
93     if (t->i > 1) {
94       for (i = 0; i < 8; i++)
95         k[i] += S[S[U8(9*t->i + i + 1)]];
96     }
97   }
98   for (i = 0; i < 8; i++)
99     t->x[i] = ROL8(t->x[i], 3);
100   t->i++;
101 }
102
103 static void next_sk(struct ksched *t, octet *k)
104 {
105   unsigned i;
106   i = (t->i - 1)%9;
107   if (k) {
108     if (i < 2)
109       memcpy(k, t->x + i, 8);
110     else {
111       memcpy(k, t->x + i, 9 - i);
112       memcpy(k + 9 - i, t->x, i - 1);
113     }
114     if (t->i > 1) {
115       for (i = 0; i < 8; i++)
116         k[i] += S[S[U8(9*t->i + i + 1)]];
117     }
118   }
119   for (i = 0; i < 9; i++)
120     t->x[i] = ROL8(t->x[i], 3);
121   t->i++;
122 }
123
124 void safer_setup(safer_ctx *k, unsigned r, unsigned f,
125                  const void *buf, size_t sz)
126 {
127   struct ksched ka, kb;
128   void (*in)(struct ksched *, const octet *);
129   void (*nx)(struct ksched *, octet *);
130   octet *kk;
131
132   assert(r <= SAFER_MAXROUNDS);
133   KSZ_ASSERT(safer, sz);
134
135   if (f & SAFER_SK) {
136     in = init_sk;
137     nx = next_sk;
138   } else {
139     in = init;
140     nx = next;
141   }
142
143   in(&kb, buf);
144   in(&ka, sz == 8 ? buf : (const octet *)buf + 8);
145
146   k->r = r;
147   kk = k->k;
148   while (r) {
149     nx(&ka, kk); nx(&kb, 0); kk += 8;
150     nx(&kb, kk); nx(&ka, 0); kk += 8;
151     r--;
152   }
153   nx(&ka, kk); kk += 8;
154 }
155
156 /* --- @safer_init@, @safersk_init@ --- *
157  *
158  * Arguments:   @safer_ctx *k@ = pointer to context to initialize
159  *              @const void *buf@ = pointer to key material
160  *              @size_t sz@ = size of key material in bytes
161  *
162  * Returns:     ---
163  *
164  * Use:         Initializes an SAFER expanded key.  A default number of
165  *              rounds is chosen, based on the key length.
166  */
167
168 void safer_init(safer_ctx *k, const void *buf, size_t sz)
169 {
170   safer_setup(k, sz == 8 ? 6 : 10, 0, buf, sz);
171 }
172
173 void safersk_init(safer_ctx *k, const void *buf, size_t sz)
174 {
175   safer_setup(k, sz == 8 ? 8 : 10, SAFER_SK, buf, sz);
176 }
177
178 /* --- @safer_eblk@, @safer_dblk@ --- *
179  *
180  * Arguments:   @const safer_ctx *k@ = pointer to SAFER context
181  *              @const uint32 s[2]@ = pointer to source block
182  *              @const uint32 d[2]@ = pointer to destination block
183  *
184  * Returns:     ---
185  *
186  * Use:         Low-level block encryption and decryption.
187  */
188
189 #define UNPACK(src, a, b, c, d, e, f, g, h) do {                        \
190   a = U8(src[0] >> 24); b = U8(src[0] >> 16);                           \
191   c = U8(src[0] >>  8); d = U8(src[0] >>  0);                           \
192   e = U8(src[1] >> 24); f = U8(src[1] >> 16);                           \
193   g = U8(src[1] >>  8); h = U8(src[1] >>  0);                           \
194 } while (0)
195
196 #define PACK(dst, a, b, c, d, e, f, g, h) do {                          \
197   dst[0] = (U8(a) << 24) | (U8(b) << 16) | (U8(c) << 8) | U8(d);        \
198   dst[1] = (U8(e) << 24) | (U8(f) << 16) | (U8(g) << 8) | U8(h);        \
199 } while (0)
200
201 #define F(x, y) y += x, x += y
202 #define G(x, y) x -= y, y -= x
203
204 #define PHT(a, b, c, d, e, f, g, h) do {                                \
205   F(a, b); F(c, d); F(e, f); F(g, h);                                   \
206   F(a, c); F(e, g); F(b, d); F(f, h);                                   \
207   F(a, e); F(b, f); F(c, g); F(d, h);                                   \
208 } while (0)
209  #define IPHT(a, b, c, d, e, f, g, h) do {                              \
210   G(a, e); G(b, f); G(c, g); G(d, h);                                   \
211   G(a, c); G(e, g); G(b, d); G(f, h);                                   \
212   G(a, b); G(c, d); G(e, f); G(g, h);                                   \
213 } while (0)
214
215 #define KXA(k, a, b, c, d, e, f, g, h) do {                             \
216   a ^= *k++; b += *k++; c += *k++; d ^= *k++;                           \
217   e ^= *k++; f += *k++; g += *k++; h ^= *k++;                           \
218 } while (0)
219 #define SUB(a, b, c, d, e, f, g, h) do {                                \
220   a = S[U8(a)]; b = SI[U8(b)]; c = SI[U8(c)]; d = S[U8(d)];             \
221   e = S[U8(e)]; f = SI[U8(f)]; g = SI[U8(g)]; h = S[U8(h)];             \
222 } while (0)
223 #define KAX(k, a, b, c, d, e, f, g, h) do {                             \
224   a += *k++; b ^= *k++; c ^= *k++; d += *k++;                           \
225   e += *k++; f ^= *k++; g ^= *k++; h += *k++;                           \
226 } while (0)
227
228 #define KXS(k, a, b, c, d, e, f, g, h) do {                             \
229   h ^= *--k; g -= *--k; f -= *--k; e ^= *--k;                           \
230   d ^= *--k; c -= *--k; b -= *--k; a ^= *--k;                           \
231 } while (0)
232 #define ISUB(a, b, c, d, e, f, g, h) do {                               \
233   a = SI[U8(a)]; b = S[U8(b)]; c = S[U8(c)]; d = SI[U8(d)];             \
234   e = SI[U8(e)]; f = S[U8(f)]; g = S[U8(g)]; h = SI[U8(h)];             \
235 } while (0)
236 #define KSX(k, a, b, c, d, e, f, g, h) do {                             \
237   h -= *--k; g ^= *--k; f ^= *--k; e -= *--k;                           \
238   d -= *--k; c ^= *--k; b ^= *--k; a -= *--k;                           \
239 } while (0)
240
241 #define EROUND(k, a, b, c, d, e, f, g, h) do {                          \
242   KXA(k, a, b, c, d, e, f, g, h);                                       \
243   SUB(a, b, c, d, e, f, g, h);                                          \
244   KAX(k, a, b, c, d, e, f, g, h);                                       \
245   PHT(a, b, c, d, e, f, g, h);                                          \
246 } while (0)
247
248 #define DROUND(k, a, b, c, d, e, f, g, h) do {                          \
249   IPHT(a, b, c, d, e, f, g, h);                                         \
250   KSX(k, a, b, c, d, e, f, g, h);                                       \
251   ISUB(a, b, c, d, e, f, g, h);                                         \
252   KXS(k, a, b, c, d, e, f, g, h);                                       \
253 } while (0)
254
255 void safer_eblk(const safer_ctx *k, const uint32 *src, uint32 *dst)
256 {
257   octet a, b, c, d, e, f, g, h;
258   unsigned r = k->r;
259   const octet *kk = k->k;
260
261   UNPACK(src, a, b, c, d, e, f, g, h);
262   while (r >= 3) {
263     EROUND(kk, a, b, c, d, e, f, g, h);
264     EROUND(kk, a, e, b, f, c, g, d, h);
265     EROUND(kk, a, c, e, g, b, d, f, h);
266     r -= 3;
267   }
268   switch (r) {
269     case 0:
270       KXA(kk, a, b, c, d, e, f, g, h);
271       PACK(dst, a, b, c, d, e, f, g ,h);
272       break;
273     case 1:
274       EROUND(kk, a, b, c, d, e, f, g, h);
275       KXA(kk, a, e, b, f, c, g, d, h);
276       PACK(dst, a, e, b, f, c, g, d, h);
277       break;
278     case 2:
279       EROUND(kk, a, b, c, d, e, f, g, h);
280       EROUND(kk, a, e, b, f, c, g, d, h);
281       KXA(kk, a, c, e, g, b, d, f, h);
282       PACK(dst, a, c, e, g, b, d, f, h);
283       break;
284   }
285 }
286
287 void safer_dblk(const safer_ctx *k, const uint32 *src, uint32 *dst)
288 {
289   octet a, b, c, d, e, f, g, h;
290   unsigned r = k->r;
291   const octet *kk = k->k + 16 * r + 8;
292   switch (r%3) {
293     default:
294     case 0:
295       UNPACK(src, a, b, c, d, e, f, g, h);
296       KXS(kk, a, b, c, d, e, f, g, h);
297       break;
298     case 1:
299       UNPACK(src, a, e, b, f, c, g, d, h);
300       KXS(kk, a, e, b, f, c, g, d, h);
301       r--;
302       goto one_round;
303     case 2:
304       UNPACK(src, a, c, e, g, b, d, f, h);
305       KXS(kk, a, c, e, g, b, d, f, h);
306       r -= 2;
307       DROUND(kk, a, e, b, f, c, g, d, h);
308     one_round:
309       DROUND(kk, a, b, c, d, e, f, g, h);
310       break;
311   }
312   while (r) {
313     DROUND(kk, a, c, e, g, b, d, f, h);
314     DROUND(kk, a, e, b, f, c, g, d, h);
315     DROUND(kk, a, b, c, d, e, f, g, h);
316     r -= 3;
317   }
318   PACK(dst, a, b, c, d, e, f, g, h);
319 }
320
321 /*----- Test rig ----------------------------------------------------------*/
322
323 #ifdef TEST_RIG
324
325 #include <mLib/testrig.h>
326
327 #define CIPHERS(_)                                                      \
328   _(SAFER, safer)                                                       \
329   _(SAFERSK, safersk)
330
331 CIPHERS(BLKC_VERIFY)
332
333 static const test_chunk defs[] = {
334   CIPHERS(BLKC_TESTDEFS)
335   { 0, 0, { 0 } }
336 };
337
338 int main(int argc, char *argv[])
339 {
340   test_run(argc, argv, defs, SRCDIR "/t/safer");
341   return (0);
342 }
343
344 #endif
345
346 /*----- That's all, folks -------------------------------------------------*/