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