1*8411e6adSJerome Forissier /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2*8411e6adSJerome Forissier /* SPDX-License-Identifier: Unlicense */
35a913ee7SJerome Forissier
45a913ee7SJerome Forissier /**
55a913ee7SJerome Forissier @file multi2.c
65a913ee7SJerome Forissier Multi-2 implementation (not public domain, hence the default disable)
75a913ee7SJerome Forissier */
85a913ee7SJerome Forissier #include "tomcrypt_private.h"
95a913ee7SJerome Forissier
105a913ee7SJerome Forissier #ifdef LTC_MULTI2
115a913ee7SJerome Forissier
s_pi1(ulong32 * p)12*8411e6adSJerome Forissier static void s_pi1(ulong32 *p)
135a913ee7SJerome Forissier {
145a913ee7SJerome Forissier p[1] ^= p[0];
155a913ee7SJerome Forissier }
165a913ee7SJerome Forissier
s_pi2(ulong32 * p,const ulong32 * k)17*8411e6adSJerome Forissier static void s_pi2(ulong32 *p, const ulong32 *k)
185a913ee7SJerome Forissier {
195a913ee7SJerome Forissier ulong32 t;
205a913ee7SJerome Forissier t = (p[1] + k[0]) & 0xFFFFFFFFUL;
215a913ee7SJerome Forissier t = (ROL(t, 1) + t - 1) & 0xFFFFFFFFUL;
225a913ee7SJerome Forissier t = (ROL(t, 4) ^ t) & 0xFFFFFFFFUL;
235a913ee7SJerome Forissier p[0] ^= t;
245a913ee7SJerome Forissier }
255a913ee7SJerome Forissier
s_pi3(ulong32 * p,const ulong32 * k)26*8411e6adSJerome Forissier static void s_pi3(ulong32 *p, const ulong32 *k)
275a913ee7SJerome Forissier {
285a913ee7SJerome Forissier ulong32 t;
295a913ee7SJerome Forissier t = p[0] + k[1];
305a913ee7SJerome Forissier t = (ROL(t, 2) + t + 1) & 0xFFFFFFFFUL;
315a913ee7SJerome Forissier t = (ROL(t, 8) ^ t) & 0xFFFFFFFFUL;
325a913ee7SJerome Forissier t = (t + k[2]) & 0xFFFFFFFFUL;
335a913ee7SJerome Forissier t = (ROL(t, 1) - t) & 0xFFFFFFFFUL;
345a913ee7SJerome Forissier t = ROL(t, 16) ^ (p[0] | t);
355a913ee7SJerome Forissier p[1] ^= t;
365a913ee7SJerome Forissier }
375a913ee7SJerome Forissier
s_pi4(ulong32 * p,const ulong32 * k)38*8411e6adSJerome Forissier static void s_pi4(ulong32 *p, const ulong32 *k)
395a913ee7SJerome Forissier {
405a913ee7SJerome Forissier ulong32 t;
415a913ee7SJerome Forissier t = (p[1] + k[3]) & 0xFFFFFFFFUL;
425a913ee7SJerome Forissier t = (ROL(t, 2) + t + 1) & 0xFFFFFFFFUL;
435a913ee7SJerome Forissier p[0] ^= t;
445a913ee7SJerome Forissier }
455a913ee7SJerome Forissier
s_setup(const ulong32 * dk,const ulong32 * k,ulong32 * uk)46*8411e6adSJerome Forissier static void s_setup(const ulong32 *dk, const ulong32 *k, ulong32 *uk)
475a913ee7SJerome Forissier {
485a913ee7SJerome Forissier int n, t;
495a913ee7SJerome Forissier ulong32 p[2];
505a913ee7SJerome Forissier
515a913ee7SJerome Forissier p[0] = dk[0]; p[1] = dk[1];
525a913ee7SJerome Forissier
535a913ee7SJerome Forissier t = 4;
545a913ee7SJerome Forissier n = 0;
55*8411e6adSJerome Forissier s_pi1(p);
56*8411e6adSJerome Forissier s_pi2(p, k);
575a913ee7SJerome Forissier uk[n++] = p[0];
58*8411e6adSJerome Forissier s_pi3(p, k);
595a913ee7SJerome Forissier uk[n++] = p[1];
60*8411e6adSJerome Forissier s_pi4(p, k);
615a913ee7SJerome Forissier uk[n++] = p[0];
62*8411e6adSJerome Forissier s_pi1(p);
635a913ee7SJerome Forissier uk[n++] = p[1];
64*8411e6adSJerome Forissier s_pi2(p, k+t);
655a913ee7SJerome Forissier uk[n++] = p[0];
66*8411e6adSJerome Forissier s_pi3(p, k+t);
675a913ee7SJerome Forissier uk[n++] = p[1];
68*8411e6adSJerome Forissier s_pi4(p, k+t);
695a913ee7SJerome Forissier uk[n++] = p[0];
70*8411e6adSJerome Forissier s_pi1(p);
715a913ee7SJerome Forissier uk[n++] = p[1];
725a913ee7SJerome Forissier }
735a913ee7SJerome Forissier
s_encrypt(ulong32 * p,int N,const ulong32 * uk)74*8411e6adSJerome Forissier static void s_encrypt(ulong32 *p, int N, const ulong32 *uk)
755a913ee7SJerome Forissier {
765a913ee7SJerome Forissier int n, t;
775a913ee7SJerome Forissier for (t = n = 0; ; ) {
78*8411e6adSJerome Forissier s_pi1(p); if (++n == N) break;
79*8411e6adSJerome Forissier s_pi2(p, uk+t); if (++n == N) break;
80*8411e6adSJerome Forissier s_pi3(p, uk+t); if (++n == N) break;
81*8411e6adSJerome Forissier s_pi4(p, uk+t); if (++n == N) break;
825a913ee7SJerome Forissier t ^= 4;
835a913ee7SJerome Forissier }
845a913ee7SJerome Forissier }
855a913ee7SJerome Forissier
s_decrypt(ulong32 * p,int N,const ulong32 * uk)86*8411e6adSJerome Forissier static void s_decrypt(ulong32 *p, int N, const ulong32 *uk)
875a913ee7SJerome Forissier {
885a913ee7SJerome Forissier int n, t;
895a913ee7SJerome Forissier for (t = 4*(((N-1)>>2)&1), n = N; ; ) {
905a913ee7SJerome Forissier switch (n<=4 ? n : ((n-1)%4)+1) {
91*8411e6adSJerome Forissier case 4: s_pi4(p, uk+t); --n; /* FALLTHROUGH */
92*8411e6adSJerome Forissier case 3: s_pi3(p, uk+t); --n; /* FALLTHROUGH */
93*8411e6adSJerome Forissier case 2: s_pi2(p, uk+t); --n; /* FALLTHROUGH */
94*8411e6adSJerome Forissier case 1: s_pi1(p); --n; break;
955a913ee7SJerome Forissier case 0: return;
965a913ee7SJerome Forissier }
975a913ee7SJerome Forissier t ^= 4;
985a913ee7SJerome Forissier }
995a913ee7SJerome Forissier }
1005a913ee7SJerome Forissier
1015a913ee7SJerome Forissier const struct ltc_cipher_descriptor multi2_desc = {
1025a913ee7SJerome Forissier "multi2",
1035a913ee7SJerome Forissier 22,
1045a913ee7SJerome Forissier 40, 40, 8, 128,
1055a913ee7SJerome Forissier &multi2_setup,
1065a913ee7SJerome Forissier &multi2_ecb_encrypt,
1075a913ee7SJerome Forissier &multi2_ecb_decrypt,
1085a913ee7SJerome Forissier &multi2_test,
1095a913ee7SJerome Forissier &multi2_done,
1105a913ee7SJerome Forissier &multi2_keysize,
1115a913ee7SJerome Forissier NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
1125a913ee7SJerome Forissier };
1135a913ee7SJerome Forissier
multi2_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)1145a913ee7SJerome Forissier int multi2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
1155a913ee7SJerome Forissier {
1165a913ee7SJerome Forissier ulong32 sk[8], dk[2];
1175a913ee7SJerome Forissier int x;
1185a913ee7SJerome Forissier
1195a913ee7SJerome Forissier LTC_ARGCHK(key != NULL);
1205a913ee7SJerome Forissier LTC_ARGCHK(skey != NULL);
1215a913ee7SJerome Forissier
1225a913ee7SJerome Forissier if (keylen != 40) return CRYPT_INVALID_KEYSIZE;
1235a913ee7SJerome Forissier if (num_rounds == 0) num_rounds = 128;
1245a913ee7SJerome Forissier
1255a913ee7SJerome Forissier skey->multi2.N = num_rounds;
1265a913ee7SJerome Forissier for (x = 0; x < 8; x++) {
1275a913ee7SJerome Forissier LOAD32H(sk[x], key + x*4);
1285a913ee7SJerome Forissier }
1295a913ee7SJerome Forissier LOAD32H(dk[0], key + 32);
1305a913ee7SJerome Forissier LOAD32H(dk[1], key + 36);
131*8411e6adSJerome Forissier s_setup(dk, sk, skey->multi2.uk);
1325a913ee7SJerome Forissier
1335a913ee7SJerome Forissier zeromem(sk, sizeof(sk));
1345a913ee7SJerome Forissier zeromem(dk, sizeof(dk));
1355a913ee7SJerome Forissier return CRYPT_OK;
1365a913ee7SJerome Forissier }
1375a913ee7SJerome Forissier
1385a913ee7SJerome Forissier /**
1395a913ee7SJerome Forissier Encrypts a block of text with multi2
1405a913ee7SJerome Forissier @param pt The input plaintext (8 bytes)
1415a913ee7SJerome Forissier @param ct The output ciphertext (8 bytes)
1425a913ee7SJerome Forissier @param skey The key as scheduled
1435a913ee7SJerome Forissier @return CRYPT_OK if successful
1445a913ee7SJerome Forissier */
multi2_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)1455a913ee7SJerome Forissier int multi2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
1465a913ee7SJerome Forissier {
1475a913ee7SJerome Forissier ulong32 p[2];
1485a913ee7SJerome Forissier LTC_ARGCHK(pt != NULL);
1495a913ee7SJerome Forissier LTC_ARGCHK(ct != NULL);
1505a913ee7SJerome Forissier LTC_ARGCHK(skey != NULL);
1515a913ee7SJerome Forissier LOAD32H(p[0], pt);
1525a913ee7SJerome Forissier LOAD32H(p[1], pt+4);
153*8411e6adSJerome Forissier s_encrypt(p, skey->multi2.N, skey->multi2.uk);
1545a913ee7SJerome Forissier STORE32H(p[0], ct);
1555a913ee7SJerome Forissier STORE32H(p[1], ct+4);
1565a913ee7SJerome Forissier return CRYPT_OK;
1575a913ee7SJerome Forissier }
1585a913ee7SJerome Forissier
1595a913ee7SJerome Forissier /**
1605a913ee7SJerome Forissier Decrypts a block of text with multi2
1615a913ee7SJerome Forissier @param ct The input ciphertext (8 bytes)
1625a913ee7SJerome Forissier @param pt The output plaintext (8 bytes)
1635a913ee7SJerome Forissier @param skey The key as scheduled
1645a913ee7SJerome Forissier @return CRYPT_OK if successful
1655a913ee7SJerome Forissier */
multi2_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)1665a913ee7SJerome Forissier int multi2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
1675a913ee7SJerome Forissier {
1685a913ee7SJerome Forissier ulong32 p[2];
1695a913ee7SJerome Forissier LTC_ARGCHK(pt != NULL);
1705a913ee7SJerome Forissier LTC_ARGCHK(ct != NULL);
1715a913ee7SJerome Forissier LTC_ARGCHK(skey != NULL);
1725a913ee7SJerome Forissier LOAD32H(p[0], ct);
1735a913ee7SJerome Forissier LOAD32H(p[1], ct+4);
174*8411e6adSJerome Forissier s_decrypt(p, skey->multi2.N, skey->multi2.uk);
1755a913ee7SJerome Forissier STORE32H(p[0], pt);
1765a913ee7SJerome Forissier STORE32H(p[1], pt+4);
1775a913ee7SJerome Forissier return CRYPT_OK;
1785a913ee7SJerome Forissier }
1795a913ee7SJerome Forissier
1805a913ee7SJerome Forissier /**
1815a913ee7SJerome Forissier Performs a self-test of the multi2 block cipher
1825a913ee7SJerome Forissier @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
1835a913ee7SJerome Forissier */
multi2_test(void)1845a913ee7SJerome Forissier int multi2_test(void)
1855a913ee7SJerome Forissier {
1865a913ee7SJerome Forissier static const struct {
1875a913ee7SJerome Forissier unsigned char key[40];
1885a913ee7SJerome Forissier unsigned char pt[8], ct[8];
1895a913ee7SJerome Forissier int rounds;
1905a913ee7SJerome Forissier } tests[] = {
1915a913ee7SJerome Forissier {
1925a913ee7SJerome Forissier {
1935a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
1945a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
1955a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
1965a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
1975a913ee7SJerome Forissier
1985a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
1995a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
2005a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
2015a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
2025a913ee7SJerome Forissier
2035a913ee7SJerome Forissier 0x01, 0x23, 0x45, 0x67,
2045a913ee7SJerome Forissier 0x89, 0xAB, 0xCD, 0xEF
2055a913ee7SJerome Forissier },
2065a913ee7SJerome Forissier {
2075a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x00,
2085a913ee7SJerome Forissier 0x00, 0x00, 0x00, 0x01,
2095a913ee7SJerome Forissier },
2105a913ee7SJerome Forissier {
2115a913ee7SJerome Forissier 0xf8, 0x94, 0x40, 0x84,
2125a913ee7SJerome Forissier 0x5e, 0x11, 0xcf, 0x89
2135a913ee7SJerome Forissier },
2145a913ee7SJerome Forissier 128,
2155a913ee7SJerome Forissier },
2165a913ee7SJerome Forissier {
2175a913ee7SJerome Forissier {
2185a913ee7SJerome Forissier 0x35, 0x91, 0x9d, 0x96,
2195a913ee7SJerome Forissier 0x07, 0x02, 0xe2, 0xce,
2205a913ee7SJerome Forissier 0x8d, 0x0b, 0x58, 0x3c,
2215a913ee7SJerome Forissier 0xc9, 0xc8, 0x9d, 0x59,
2225a913ee7SJerome Forissier 0xa2, 0xae, 0x96, 0x4e,
2235a913ee7SJerome Forissier 0x87, 0x82, 0x45, 0xed,
2245a913ee7SJerome Forissier 0x3f, 0x2e, 0x62, 0xd6,
2255a913ee7SJerome Forissier 0x36, 0x35, 0xd0, 0x67,
2265a913ee7SJerome Forissier
2275a913ee7SJerome Forissier 0xb1, 0x27, 0xb9, 0x06,
2285a913ee7SJerome Forissier 0xe7, 0x56, 0x22, 0x38,
2295a913ee7SJerome Forissier },
2305a913ee7SJerome Forissier {
2315a913ee7SJerome Forissier 0x1f, 0xb4, 0x60, 0x60,
2325a913ee7SJerome Forissier 0xd0, 0xb3, 0x4f, 0xa5
2335a913ee7SJerome Forissier },
2345a913ee7SJerome Forissier {
2355a913ee7SJerome Forissier 0xca, 0x84, 0xa9, 0x34,
2365a913ee7SJerome Forissier 0x75, 0xc8, 0x60, 0xe5
2375a913ee7SJerome Forissier },
2385a913ee7SJerome Forissier 216,
2395a913ee7SJerome Forissier }
2405a913ee7SJerome Forissier };
2415a913ee7SJerome Forissier unsigned char buf[8];
2425a913ee7SJerome Forissier symmetric_key skey;
2435a913ee7SJerome Forissier int err, x;
2445a913ee7SJerome Forissier
2455a913ee7SJerome Forissier for (x = 1; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
2465a913ee7SJerome Forissier if ((err = multi2_setup(tests[x].key, 40, tests[x].rounds, &skey)) != CRYPT_OK) {
2475a913ee7SJerome Forissier return err;
2485a913ee7SJerome Forissier }
2495a913ee7SJerome Forissier if ((err = multi2_ecb_encrypt(tests[x].pt, buf, &skey)) != CRYPT_OK) {
2505a913ee7SJerome Forissier return err;
2515a913ee7SJerome Forissier }
2525a913ee7SJerome Forissier
2535a913ee7SJerome Forissier if (compare_testvector(buf, 8, tests[x].ct, 8, "Multi2 Encrypt", x)) {
2545a913ee7SJerome Forissier return CRYPT_FAIL_TESTVECTOR;
2555a913ee7SJerome Forissier }
2565a913ee7SJerome Forissier
2575a913ee7SJerome Forissier if ((err = multi2_ecb_decrypt(buf, buf, &skey)) != CRYPT_OK) {
2585a913ee7SJerome Forissier return err;
2595a913ee7SJerome Forissier }
2605a913ee7SJerome Forissier if (compare_testvector(buf, 8, tests[x].pt, 8, "Multi2 Decrypt", x)) {
2615a913ee7SJerome Forissier return CRYPT_FAIL_TESTVECTOR;
2625a913ee7SJerome Forissier }
2635a913ee7SJerome Forissier }
2645a913ee7SJerome Forissier
2655a913ee7SJerome Forissier for (x = 128; x < 256; ++x) {
2665a913ee7SJerome Forissier unsigned char ct[8];
2675a913ee7SJerome Forissier
2685a913ee7SJerome Forissier if ((err = multi2_setup(tests[0].key, 40, x, &skey)) != CRYPT_OK) {
2695a913ee7SJerome Forissier return err;
2705a913ee7SJerome Forissier }
2715a913ee7SJerome Forissier if ((err = multi2_ecb_encrypt(tests[0].pt, ct, &skey)) != CRYPT_OK) {
2725a913ee7SJerome Forissier return err;
2735a913ee7SJerome Forissier }
2745a913ee7SJerome Forissier if ((err = multi2_ecb_decrypt(ct, buf, &skey)) != CRYPT_OK) {
2755a913ee7SJerome Forissier return err;
2765a913ee7SJerome Forissier }
2775a913ee7SJerome Forissier if (compare_testvector(buf, 8, tests[0].pt, 8, "Multi2 Rounds", x)) {
2785a913ee7SJerome Forissier return CRYPT_FAIL_TESTVECTOR;
2795a913ee7SJerome Forissier }
2805a913ee7SJerome Forissier }
2815a913ee7SJerome Forissier
2825a913ee7SJerome Forissier return CRYPT_OK;
2835a913ee7SJerome Forissier }
2845a913ee7SJerome Forissier
2855a913ee7SJerome Forissier /** Terminate the context
2865a913ee7SJerome Forissier @param skey The scheduled key
2875a913ee7SJerome Forissier */
multi2_done(symmetric_key * skey)2885a913ee7SJerome Forissier void multi2_done(symmetric_key *skey)
2895a913ee7SJerome Forissier {
2905a913ee7SJerome Forissier LTC_UNUSED_PARAM(skey);
2915a913ee7SJerome Forissier }
2925a913ee7SJerome Forissier
2935a913ee7SJerome Forissier /**
2945a913ee7SJerome Forissier Gets suitable key size
2955a913ee7SJerome Forissier @param keysize [in/out] The length of the recommended key (in bytes). This function will store the suitable size back in this variable.
2965a913ee7SJerome Forissier @return CRYPT_OK if the input key size is acceptable.
2975a913ee7SJerome Forissier */
multi2_keysize(int * keysize)2985a913ee7SJerome Forissier int multi2_keysize(int *keysize)
2995a913ee7SJerome Forissier {
3005a913ee7SJerome Forissier LTC_ARGCHK(keysize != NULL);
3015a913ee7SJerome Forissier if (*keysize >= 40) {
3025a913ee7SJerome Forissier *keysize = 40;
3035a913ee7SJerome Forissier } else {
3045a913ee7SJerome Forissier return CRYPT_INVALID_KEYSIZE;
3055a913ee7SJerome Forissier }
3065a913ee7SJerome Forissier return CRYPT_OK;
3075a913ee7SJerome Forissier }
3085a913ee7SJerome Forissier
3095a913ee7SJerome Forissier #endif
310