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 19 static void pi1(ulong32 *p) 20 { 21 p[1] ^= p[0]; 22 } 23 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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