1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /**
5   @file multi2.c
6   Multi-2 implementation (not public domain, hence the default disable)
7 */
8 #include "tomcrypt_private.h"
9 
10 #ifdef LTC_MULTI2
11 
s_pi1(ulong32 * p)12 static void s_pi1(ulong32 *p)
13 {
14    p[1] ^= p[0];
15 }
16 
s_pi2(ulong32 * p,const ulong32 * k)17 static void s_pi2(ulong32 *p, const ulong32 *k)
18 {
19    ulong32 t;
20    t = (p[1] + k[0]) & 0xFFFFFFFFUL;
21    t = (ROL(t, 1) + t - 1)  & 0xFFFFFFFFUL;
22    t = (ROL(t, 4) ^ t)  & 0xFFFFFFFFUL;
23    p[0] ^= t;
24 }
25 
s_pi3(ulong32 * p,const ulong32 * k)26 static void s_pi3(ulong32 *p, const ulong32 *k)
27 {
28    ulong32 t;
29    t = p[0] + k[1];
30    t = (ROL(t, 2) + t + 1)  & 0xFFFFFFFFUL;
31    t = (ROL(t, 8) ^ t)  & 0xFFFFFFFFUL;
32    t = (t + k[2])  & 0xFFFFFFFFUL;
33    t = (ROL(t, 1) - t)  & 0xFFFFFFFFUL;
34    t = ROL(t, 16) ^ (p[0] | t);
35    p[1] ^= t;
36 }
37 
s_pi4(ulong32 * p,const ulong32 * k)38 static void s_pi4(ulong32 *p, const ulong32 *k)
39 {
40    ulong32 t;
41    t = (p[1] + k[3])  & 0xFFFFFFFFUL;
42    t = (ROL(t, 2) + t + 1)  & 0xFFFFFFFFUL;
43    p[0] ^= t;
44 }
45 
s_setup(const ulong32 * dk,const ulong32 * k,ulong32 * uk)46 static void s_setup(const ulong32 *dk, const ulong32 *k, ulong32 *uk)
47 {
48    int n, t;
49    ulong32 p[2];
50 
51    p[0] = dk[0]; p[1] = dk[1];
52 
53    t = 4;
54    n = 0;
55       s_pi1(p);
56       s_pi2(p, k);
57       uk[n++] = p[0];
58       s_pi3(p, k);
59       uk[n++] = p[1];
60       s_pi4(p, k);
61       uk[n++] = p[0];
62       s_pi1(p);
63       uk[n++] = p[1];
64       s_pi2(p, k+t);
65       uk[n++] = p[0];
66       s_pi3(p, k+t);
67       uk[n++] = p[1];
68       s_pi4(p, k+t);
69       uk[n++] = p[0];
70       s_pi1(p);
71       uk[n++] = p[1];
72 }
73 
s_encrypt(ulong32 * p,int N,const ulong32 * uk)74 static void s_encrypt(ulong32 *p, int N, const ulong32 *uk)
75 {
76    int n, t;
77    for (t = n = 0; ; ) {
78       s_pi1(p); if (++n == N) break;
79       s_pi2(p, uk+t); if (++n == N) break;
80       s_pi3(p, uk+t); if (++n == N) break;
81       s_pi4(p, uk+t); if (++n == N) break;
82       t ^= 4;
83    }
84 }
85 
s_decrypt(ulong32 * p,int N,const ulong32 * uk)86 static void s_decrypt(ulong32 *p, int N, const ulong32 *uk)
87 {
88    int n, t;
89    for (t = 4*(((N-1)>>2)&1), n = N; ;  ) {
90       switch (n<=4 ? n : ((n-1)%4)+1) {
91          case 4: s_pi4(p, uk+t); --n; /* FALLTHROUGH */
92          case 3: s_pi3(p, uk+t); --n; /* FALLTHROUGH */
93          case 2: s_pi2(p, uk+t); --n; /* FALLTHROUGH */
94          case 1: s_pi1(p); --n; break;
95          case 0: return;
96       }
97       t ^= 4;
98    }
99 }
100 
101 const struct ltc_cipher_descriptor multi2_desc = {
102    "multi2",
103    22,
104    40, 40, 8, 128,
105    &multi2_setup,
106    &multi2_ecb_encrypt,
107    &multi2_ecb_decrypt,
108    &multi2_test,
109    &multi2_done,
110    &multi2_keysize,
111    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
112 };
113 
multi2_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)114 int  multi2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
115 {
116    ulong32 sk[8], dk[2];
117    int      x;
118 
119    LTC_ARGCHK(key  != NULL);
120    LTC_ARGCHK(skey != NULL);
121 
122    if (keylen != 40) return CRYPT_INVALID_KEYSIZE;
123    if (num_rounds == 0) num_rounds = 128;
124 
125    skey->multi2.N = num_rounds;
126    for (x = 0; x < 8; x++) {
127        LOAD32H(sk[x], key + x*4);
128    }
129    LOAD32H(dk[0], key + 32);
130    LOAD32H(dk[1], key + 36);
131    s_setup(dk, sk, skey->multi2.uk);
132 
133    zeromem(sk, sizeof(sk));
134    zeromem(dk, sizeof(dk));
135    return CRYPT_OK;
136 }
137 
138 /**
139   Encrypts a block of text with multi2
140   @param pt The input plaintext (8 bytes)
141   @param ct The output ciphertext (8 bytes)
142   @param skey The key as scheduled
143   @return CRYPT_OK if successful
144 */
multi2_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)145 int multi2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
146 {
147    ulong32 p[2];
148    LTC_ARGCHK(pt   != NULL);
149    LTC_ARGCHK(ct   != NULL);
150    LTC_ARGCHK(skey != NULL);
151    LOAD32H(p[0], pt);
152    LOAD32H(p[1], pt+4);
153    s_encrypt(p, skey->multi2.N, skey->multi2.uk);
154    STORE32H(p[0], ct);
155    STORE32H(p[1], ct+4);
156    return CRYPT_OK;
157 }
158 
159 /**
160   Decrypts a block of text with multi2
161   @param ct The input ciphertext (8 bytes)
162   @param pt The output plaintext (8 bytes)
163   @param skey The key as scheduled
164   @return CRYPT_OK if successful
165 */
multi2_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)166 int multi2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
167 {
168    ulong32 p[2];
169    LTC_ARGCHK(pt   != NULL);
170    LTC_ARGCHK(ct   != NULL);
171    LTC_ARGCHK(skey != NULL);
172    LOAD32H(p[0], ct);
173    LOAD32H(p[1], ct+4);
174    s_decrypt(p, skey->multi2.N, skey->multi2.uk);
175    STORE32H(p[0], pt);
176    STORE32H(p[1], pt+4);
177    return CRYPT_OK;
178 }
179 
180 /**
181   Performs a self-test of the multi2 block cipher
182   @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
183 */
multi2_test(void)184 int multi2_test(void)
185 {
186    static const struct {
187       unsigned char key[40];
188       unsigned char pt[8], ct[8];
189       int           rounds;
190    } tests[] = {
191 {
192    {
193       0x00, 0x00, 0x00, 0x00,
194       0x00, 0x00, 0x00, 0x00,
195       0x00, 0x00, 0x00, 0x00,
196       0x00, 0x00, 0x00, 0x00,
197 
198       0x00, 0x00, 0x00, 0x00,
199       0x00, 0x00, 0x00, 0x00,
200       0x00, 0x00, 0x00, 0x00,
201       0x00, 0x00, 0x00, 0x00,
202 
203       0x01, 0x23, 0x45, 0x67,
204       0x89, 0xAB, 0xCD, 0xEF
205    },
206    {
207       0x00, 0x00, 0x00, 0x00,
208       0x00, 0x00, 0x00, 0x01,
209    },
210    {
211       0xf8, 0x94, 0x40, 0x84,
212       0x5e, 0x11, 0xcf, 0x89
213    },
214    128,
215 },
216 {
217    {
218       0x35, 0x91, 0x9d, 0x96,
219       0x07, 0x02, 0xe2, 0xce,
220       0x8d, 0x0b, 0x58, 0x3c,
221       0xc9, 0xc8, 0x9d, 0x59,
222       0xa2, 0xae, 0x96, 0x4e,
223       0x87, 0x82, 0x45, 0xed,
224       0x3f, 0x2e, 0x62, 0xd6,
225       0x36, 0x35, 0xd0, 0x67,
226 
227       0xb1, 0x27, 0xb9, 0x06,
228       0xe7, 0x56, 0x22, 0x38,
229    },
230    {
231       0x1f, 0xb4, 0x60, 0x60,
232       0xd0, 0xb3, 0x4f, 0xa5
233    },
234    {
235       0xca, 0x84, 0xa9, 0x34,
236       0x75, 0xc8, 0x60, 0xe5
237    },
238    216,
239 }
240 };
241    unsigned char buf[8];
242    symmetric_key skey;
243    int err, x;
244 
245    for (x = 1; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
246       if ((err = multi2_setup(tests[x].key, 40, tests[x].rounds, &skey)) != CRYPT_OK) {
247          return err;
248       }
249       if ((err = multi2_ecb_encrypt(tests[x].pt, buf, &skey)) != CRYPT_OK) {
250          return err;
251       }
252 
253       if (compare_testvector(buf, 8, tests[x].ct, 8, "Multi2 Encrypt", x)) {
254          return CRYPT_FAIL_TESTVECTOR;
255       }
256 
257       if ((err = multi2_ecb_decrypt(buf, buf, &skey)) != CRYPT_OK) {
258          return err;
259       }
260       if (compare_testvector(buf, 8, tests[x].pt, 8, "Multi2 Decrypt", x)) {
261          return CRYPT_FAIL_TESTVECTOR;
262       }
263    }
264 
265    for (x = 128; x < 256; ++x) {
266         unsigned char ct[8];
267 
268         if ((err = multi2_setup(tests[0].key, 40, x, &skey)) != CRYPT_OK) {
269                 return err;
270         }
271         if ((err = multi2_ecb_encrypt(tests[0].pt, ct, &skey)) != CRYPT_OK) {
272                 return err;
273         }
274         if ((err = multi2_ecb_decrypt(ct, buf, &skey)) != CRYPT_OK) {
275                 return err;
276         }
277         if (compare_testvector(buf, 8, tests[0].pt, 8, "Multi2 Rounds", x)) {
278                 return CRYPT_FAIL_TESTVECTOR;
279         }
280    }
281 
282    return CRYPT_OK;
283 }
284 
285 /** Terminate the context
286    @param skey    The scheduled key
287 */
multi2_done(symmetric_key * skey)288 void multi2_done(symmetric_key *skey)
289 {
290   LTC_UNUSED_PARAM(skey);
291 }
292 
293 /**
294   Gets suitable key size
295   @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
296   @return CRYPT_OK if the input key size is acceptable.
297 */
multi2_keysize(int * keysize)298 int multi2_keysize(int *keysize)
299 {
300    LTC_ARGCHK(keysize != NULL);
301    if (*keysize >= 40) {
302       *keysize = 40;
303    } else {
304       return CRYPT_INVALID_KEYSIZE;
305    }
306    return CRYPT_OK;
307 }
308 
309 #endif
310