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