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