1 /*
2 * Copyright (c) 2001-2019, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7
8
9 /* file multi2_soft.c
10 * This code is a patch for multi2 (based on libtomcrypt-1.17
11 * It includes the following additions:
12 * 1) bug fix when num_of_rounds%4 !=0
13 * 2) num_rounds is not restricted to 128
14 * 3) support cbc mode (with IV)
15 */
16
17 #include "tomcrypt.h"
18
19 unsigned char cbc_iv[8];
20
pi1(ulong32 * p)21 static void pi1(ulong32 *p)
22 {
23 p[1] ^= p[0];
24 }
25
pi2(ulong32 * p,ulong32 * k)26 static void pi2(ulong32 *p, ulong32 *k)
27 {
28 ulong32 t;
29 t = (p[1] + k[0]) & 0xFFFFFFFFUL;
30 t = (ROL(t, 1) + t - 1) & 0xFFFFFFFFUL;
31 t = (ROL(t, 4) ^ t) & 0xFFFFFFFFUL;
32 p[0] ^= t;
33 }
34
pi3(ulong32 * p,ulong32 * k)35 static void pi3(ulong32 *p, ulong32 *k)
36 {
37 ulong32 t;
38 t = p[0] + k[1];
39 t = (ROL(t, 2) + t + 1) & 0xFFFFFFFFUL;
40 t = (ROL(t, 8) ^ t) & 0xFFFFFFFFUL;
41 t = (t + k[2]) & 0xFFFFFFFFUL;
42 t = (ROL(t, 1) - t) & 0xFFFFFFFFUL;
43 t = ROL(t, 16) ^ (p[0] | t);
44 p[1] ^= t;
45 }
46
pi4(ulong32 * p,ulong32 * k)47 static void pi4(ulong32 *p, ulong32 *k)
48 {
49 ulong32 t;
50 t = (p[1] + k[3]) & 0xFFFFFFFFUL;
51 t = (ROL(t, 2) + t + 1) & 0xFFFFFFFFUL;
52 p[0] ^= t;
53 }
54
setup(ulong32 * dk,ulong32 * k,ulong32 * uk)55 static void setup(ulong32 *dk, ulong32 *k, ulong32 *uk)
56 {
57 int n, t;
58 ulong32 p[2];
59
60 p[0] = dk[0]; p[1] = dk[1];
61
62 t = 4;
63 n = 0;
64 pi1(p);
65 pi2(p, k);
66 uk[n++] = p[0];
67 pi3(p, k);
68 uk[n++] = p[1];
69 pi4(p, k);
70 uk[n++] = p[0];
71 pi1(p);
72 uk[n++] = p[1];
73 pi2(p, k+t);
74 uk[n++] = p[0];
75 pi3(p, k+t);
76 uk[n++] = p[1];
77 pi4(p, k+t);
78 uk[n++] = p[0];
79 pi1(p);
80 uk[n++] = p[1];
81 }
82
encrypt(ulong32 * p,int N,ulong32 * uk)83 static void encrypt(ulong32 *p, int N, ulong32 *uk)
84 {
85 int n, t;
86 for (t = n = 0; ; ) {
87 pi1(p); if (++n == N) break;
88 pi2(p, uk+t); if (++n == N) break;
89 pi3(p, uk+t); if (++n == N) break;
90 pi4(p, uk+t); if (++n == N) break;
91 t ^= 4;
92 }
93 }
94
decrypt(ulong32 * p,int N,ulong32 * uk)95 static void decrypt(ulong32 *p, int N, ulong32 *uk)
96 {
97 int n, t;
98 for (t = 4*(((N-1)>>2)&1), n = N; ; ) {
99 switch (n<=4 ? n : ((n-1)%4)+1) {
100 case 4: pi4(p, uk+t); --n;
101 case 3: pi3(p, uk+t); --n;
102 case 2: pi2(p, uk+t); --n;
103 case 1: pi1(p); --n; break;
104 case 0: return;
105 default: return;
106 }
107 t ^= 4;
108 }
109 }
110
multi2_soft_ecb_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)111 int multi2_soft_ecb_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
112 {
113 ulong32 sk[8], dk[2];
114 int x;
115
116 LTC_ARGCHK(key != NULL);
117 LTC_ARGCHK(skey != NULL);
118
119 if (keylen != 40) return CRYPT_INVALID_KEYSIZE;
120
121 skey->multi2.N = num_rounds;
122 for (x = 0; x < 8; x++) {
123 LOAD32H(sk[x], key + x*4);
124 }
125 LOAD32H(dk[0], key + 32);
126 LOAD32H(dk[1], key + 36);
127 setup(dk, sk, skey->multi2.uk);
128
129 zeromem(sk, sizeof(sk));
130 zeromem(dk, sizeof(dk));
131 return CRYPT_OK;
132 }
133
134 /**
135 Encrypts a block of text with multi2
136 @param pt The input plaintext (8 bytes)
137 @param ct The output ciphertext (8 bytes)
138 @param skey The key as scheduled
139 @return CRYPT_OK if successful
140 */
multi2_soft_ecb_encrypt(const unsigned char * pt,unsigned char * ct,unsigned long len,symmetric_key * skey)141 int multi2_soft_ecb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_key *skey)
142 {
143 ulong32 p[2];
144 LTC_ARGCHK(pt != NULL);
145 LTC_ARGCHK(ct != NULL);
146 LTC_ARGCHK(skey != NULL);
147
148 if (len % 8) {
149 return CRYPT_INVALID_ARG;
150 }
151
152 while (len) {
153
154 LOAD32H(p[0], pt);
155 LOAD32H(p[1], pt+4);
156 encrypt(p, skey->multi2.N, skey->multi2.uk);
157 STORE32H(p[0], ct);
158 STORE32H(p[1], ct+4);
159
160 ct += 8;
161 pt += 8;
162 len -= 8;
163 }
164
165 return CRYPT_OK;
166 }
167
168 /**
169 Decrypts a block of text with multi2
170 @param ct The input ciphertext (8 bytes)
171 @param pt The output plaintext (8 bytes)
172 @param skey The key as scheduled
173 @return CRYPT_OK if successful
174 */
multi2_soft_ecb_decrypt(const unsigned char * ct,unsigned char * pt,unsigned long len,symmetric_key * skey)175 int multi2_soft_ecb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_key *skey)
176 {
177 ulong32 p[2];
178 LTC_ARGCHK(pt != NULL);
179 LTC_ARGCHK(ct != NULL);
180 LTC_ARGCHK(skey != NULL);
181
182 if (len % 8) {
183 return CRYPT_INVALID_ARG;
184 }
185
186 while (len) {
187
188 LOAD32H(p[0], ct);
189 LOAD32H(p[1], ct+4);
190 decrypt(p, skey->multi2.N, skey->multi2.uk);
191 STORE32H(p[0], pt);
192 STORE32H(p[1], pt+4);
193
194 ct += 8;
195 pt += 8;
196 len -= 8;
197 }
198
199 return CRYPT_OK;
200 }
201
multi2_soft_cbc_setup(const unsigned char * iv,const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)202 int multi2_soft_cbc_setup(const unsigned char *iv, const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
203 {
204 ulong32 sk[8], dk[2];
205 int x;
206
207 LTC_ARGCHK(key != NULL);
208 LTC_ARGCHK(skey != NULL);
209 LTC_ARGCHK(iv != NULL);
210
211 if (keylen != 40) return CRYPT_INVALID_KEYSIZE;
212 //if (num_rounds == 0) num_rounds = 128;
213
214 skey->multi2.N = num_rounds;
215 for (x = 0; x < 8; x++) {
216 LOAD32H(sk[x], key + x*4);
217 }
218 LOAD32H(dk[0], key + 32);
219 LOAD32H(dk[1], key + 36);
220 setup(dk, sk, skey->multi2.uk);
221
222 zeromem(sk, sizeof(sk));
223 zeromem(dk, sizeof(dk));
224
225 /* copy IV */
226 memcpy(&cbc_iv,iv,8);
227
228 return CRYPT_OK;
229 }
230
231 /**
232 Encrypts a block of text with multi2
233 @param pt The input plaintext (8 bytes)
234 @param ct The output ciphertext (8 bytes)
235 @param skey The key as scheduled
236 @return CRYPT_OK if successful
237 */
multi2_soft_cbc_encrypt(unsigned char * pt,unsigned char * ct,unsigned long len,symmetric_key * skey)238 int multi2_soft_cbc_encrypt(unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_key *skey)
239 {
240 int x;
241 ulong32 p[2];
242 LTC_ARGCHK(pt != NULL);
243 LTC_ARGCHK(ct != NULL);
244 LTC_ARGCHK(skey != NULL);
245
246 if (len % 8) {
247 return CRYPT_INVALID_ARG;
248 }
249
250 while (len) {
251 /* xor IV against plaintext */
252 for (x = 0; x < 8; x++) {
253 pt[x] ^= cbc_iv[x];
254 }
255
256 /* encrypt */
257 LOAD32H(p[0], pt);
258 LOAD32H(p[1], pt+4);
259 encrypt(p, skey->multi2.N, skey->multi2.uk);
260 STORE32H(p[0], ct);
261 STORE32H(p[1], ct+4);
262
263 /* store IV [ciphertext] for a future block */
264 for (x = 0; x < 8; x++) {
265 cbc_iv[x] = ct[x];
266 }
267
268 ct += 8;
269 pt += 8;
270 len -= 8;
271 }
272
273 return CRYPT_OK;
274 }
275
276 /**
277 Decrypts a block of text with multi2
278 @param ct The input ciphertext (8 bytes)
279 @param pt The output plaintext (8 bytes)
280 @param skey The key as scheduled
281 @return CRYPT_OK if successful
282 */
multi2_soft_cbc_decrypt(unsigned char * ct,unsigned char * pt,unsigned long len,symmetric_key * skey)283 int multi2_soft_cbc_decrypt(unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_key *skey)
284 {
285 int x;
286 ulong32 p[2];
287 LTC_ARGCHK(pt != NULL);
288 LTC_ARGCHK(ct != NULL);
289 LTC_ARGCHK(skey != NULL);
290
291 if (len % 8) {
292 return CRYPT_INVALID_ARG;
293 }
294
295 while (len) {
296
297 /* decrypt */
298 LOAD32H(p[0], ct);
299 LOAD32H(p[1], ct+4);
300 decrypt(p, skey->multi2.N, skey->multi2.uk);
301 STORE32H(p[0], pt);
302 STORE32H(p[1], pt+4);
303
304 /* xor IV against plaintext */
305 for (x = 0; x < 8; x++) {
306 pt[x] ^= cbc_iv[x];
307 }
308
309 /* store IV [ciphertext] for a future block */
310 for (x = 0; x < 8; x++) {
311 cbc_iv[x] = ct[x];
312 }
313
314 ct += 8;
315 pt += 8;
316 len -= 8;
317 }
318
319 return CRYPT_OK;
320 }
321
322
323 /** Terminate the context
324 @param skey The scheduled key
325 */
multi2_soft_done(symmetric_key * skey)326 void multi2_soft_done(symmetric_key *skey)
327 {
328 }
329
330
331
332
333