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