xref: /optee_os/core/lib/libtomcrypt/src/ciphers/idea.c (revision 8411e6ad673d20c4742ed30c785e3f5cdea54dfa)
1*8411e6adSJerome Forissier /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2*8411e6adSJerome Forissier /* SPDX-License-Identifier: Unlicense */
35a913ee7SJerome Forissier 
45a913ee7SJerome Forissier /* Based on idea.cpp - originally written and placed in the public domain by Wei Dai
55a913ee7SJerome Forissier    https://github.com/weidai11/cryptopp/blob/master/idea.cpp
65a913ee7SJerome Forissier 
75a913ee7SJerome Forissier    Patents should be expired. On 2017-10-16 wikipedia says:
85a913ee7SJerome Forissier    https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm
95a913ee7SJerome Forissier 
105a913ee7SJerome Forissier    A patent application for IDEA was first filed in Switzerland (CH A 1690/90) on May 18, 1990,
115a913ee7SJerome Forissier    then an international patent application was filed under the Patent Cooperation Treaty on
125a913ee7SJerome Forissier    May 16, 1991. Patents were eventually granted in Austria, France, Germany, Italy, the Netherlands,
135a913ee7SJerome Forissier    Spain, Sweden, Switzerland, the United Kingdom, (European Patent Register entry for European
145a913ee7SJerome Forissier    patent no. 0482154, filed May 16, 1991, issued June 22, 1994 and expired May 16, 2011),
155a913ee7SJerome Forissier    the United States (U.S. Patent 5,214,703, issued May 25, 1993 and expired January 7, 2012)
165a913ee7SJerome Forissier    and Japan (JP 3225440) (expired May 16, 2011).
175a913ee7SJerome Forissier  */
185a913ee7SJerome Forissier 
195a913ee7SJerome Forissier #include "tomcrypt_private.h"
205a913ee7SJerome Forissier 
215a913ee7SJerome Forissier #ifdef LTC_IDEA
225a913ee7SJerome Forissier 
235a913ee7SJerome Forissier const struct ltc_cipher_descriptor idea_desc = {
245a913ee7SJerome Forissier    "idea",
255a913ee7SJerome Forissier    24,                  /* cipher_ID */
265a913ee7SJerome Forissier    16, 16, 8, 8,        /* min_key_len, max_key_len, block_len, default_rounds */
275a913ee7SJerome Forissier    &idea_setup,
285a913ee7SJerome Forissier    &idea_ecb_encrypt,
295a913ee7SJerome Forissier    &idea_ecb_decrypt,
305a913ee7SJerome Forissier    &idea_test,
315a913ee7SJerome Forissier    &idea_done,
325a913ee7SJerome Forissier    &idea_keysize,
335a913ee7SJerome Forissier    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
345a913ee7SJerome Forissier };
355a913ee7SJerome Forissier 
365a913ee7SJerome Forissier typedef unsigned short int ushort16;
375a913ee7SJerome Forissier 
38*8411e6adSJerome Forissier #define LOW16(x)     ((x)&0xffff)  /* compiler should be able to optimize this away if x is 16 bits */
39*8411e6adSJerome Forissier #define HIGH16(x)    ((x)>>16)
40*8411e6adSJerome Forissier #define MUL(a,b)     {                                               \
41*8411e6adSJerome Forissier                          ulong32 p = (ulong32)LOW16(a) * b;          \
425a913ee7SJerome Forissier                          if (p) {                                     \
43*8411e6adSJerome Forissier                             p = LOW16(p) - HIGH16(p);               \
44*8411e6adSJerome Forissier                             a = (ushort16)p - (ushort16)HIGH16(p);   \
455a913ee7SJerome Forissier                          }                                            \
465a913ee7SJerome Forissier                          else                                         \
475a913ee7SJerome Forissier                             a = 1 - a - b;                            \
485a913ee7SJerome Forissier                       }
49*8411e6adSJerome Forissier #define STORE16(x,y) { (y)[0] = (unsigned char)(((x)>>8)&255); (y)[1] = (unsigned char)((x)&255); }
50*8411e6adSJerome Forissier #define LOAD16(x,y)  { x = ((ushort16)((y)[0] & 255)<<8) | ((ushort16)((y)[1] & 255)); }
515a913ee7SJerome Forissier 
s_mul_inv(ushort16 x)52*8411e6adSJerome Forissier static ushort16 s_mul_inv(ushort16 x)
535a913ee7SJerome Forissier {
545a913ee7SJerome Forissier    ushort16 y = x;
555a913ee7SJerome Forissier    unsigned i;
565a913ee7SJerome Forissier 
575a913ee7SJerome Forissier    for (i = 0; i < 15; i++) {
58*8411e6adSJerome Forissier       MUL(y, LOW16(y));
59*8411e6adSJerome Forissier       MUL(y, x);
605a913ee7SJerome Forissier    }
61*8411e6adSJerome Forissier    return LOW16(y);
625a913ee7SJerome Forissier }
635a913ee7SJerome Forissier 
s_add_inv(ushort16 x)64*8411e6adSJerome Forissier static ushort16 s_add_inv(ushort16 x)
655a913ee7SJerome Forissier {
66*8411e6adSJerome Forissier    return LOW16(0 - x);
675a913ee7SJerome Forissier }
685a913ee7SJerome Forissier 
s_setup_key(const unsigned char * key,symmetric_key * skey)69*8411e6adSJerome Forissier static int s_setup_key(const unsigned char *key, symmetric_key *skey)
705a913ee7SJerome Forissier {
715a913ee7SJerome Forissier    int i, j;
725a913ee7SJerome Forissier    ushort16 *e_key = skey->idea.ek;
735a913ee7SJerome Forissier    ushort16 *d_key = skey->idea.dk;
745a913ee7SJerome Forissier 
755a913ee7SJerome Forissier    /* prepare enc key */
765a913ee7SJerome Forissier    for (i = 0; i < 8; i++) {
77*8411e6adSJerome Forissier       LOAD16(e_key[i], key + 2 * i);
785a913ee7SJerome Forissier    }
795a913ee7SJerome Forissier    for (; i < LTC_IDEA_KEYLEN; i++) {
805a913ee7SJerome Forissier       j = (i - i % 8) - 8;
81*8411e6adSJerome Forissier       e_key[i] = LOW16((e_key[j+(i+1)%8] << 9) | (e_key[j+(i+2)%8] >> 7));
825a913ee7SJerome Forissier    }
835a913ee7SJerome Forissier 
845a913ee7SJerome Forissier    /* prepare dec key */
855a913ee7SJerome Forissier    for (i = 0; i < LTC_IDEA_ROUNDS; i++) {
86*8411e6adSJerome Forissier       d_key[i*6+0] = s_mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+0]);
87*8411e6adSJerome Forissier       d_key[i*6+1] = s_add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+1+(i>0 ? 1 : 0)]);
88*8411e6adSJerome Forissier       d_key[i*6+2] = s_add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+2-(i>0 ? 1 : 0)]);
89*8411e6adSJerome Forissier       d_key[i*6+3] = s_mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+3]);
905a913ee7SJerome Forissier       d_key[i*6+4] =           e_key[(LTC_IDEA_ROUNDS-1-i)*6+4];
915a913ee7SJerome Forissier       d_key[i*6+5] =           e_key[(LTC_IDEA_ROUNDS-1-i)*6+5];
925a913ee7SJerome Forissier    }
93*8411e6adSJerome Forissier    d_key[i*6+0] = s_mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+0]);
94*8411e6adSJerome Forissier    d_key[i*6+1] = s_add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+1]);
95*8411e6adSJerome Forissier    d_key[i*6+2] = s_add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+2]);
96*8411e6adSJerome Forissier    d_key[i*6+3] = s_mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+3]);
975a913ee7SJerome Forissier 
985a913ee7SJerome Forissier    return CRYPT_OK;
995a913ee7SJerome Forissier }
1005a913ee7SJerome Forissier 
s_process_block(const unsigned char * in,unsigned char * out,const ushort16 * m_key)101*8411e6adSJerome Forissier static int s_process_block(const unsigned char *in, unsigned char *out, const ushort16 *m_key)
1025a913ee7SJerome Forissier {
1035a913ee7SJerome Forissier    int i;
1045a913ee7SJerome Forissier    ushort16 x0, x1, x2, x3, t0, t1;
1055a913ee7SJerome Forissier 
106*8411e6adSJerome Forissier    LOAD16(x0, in + 0);
107*8411e6adSJerome Forissier    LOAD16(x1, in + 2);
108*8411e6adSJerome Forissier    LOAD16(x2, in + 4);
109*8411e6adSJerome Forissier    LOAD16(x3, in + 6);
1105a913ee7SJerome Forissier 
1115a913ee7SJerome Forissier    for (i = 0; i < LTC_IDEA_ROUNDS; i++) {
112*8411e6adSJerome Forissier       MUL(x0, m_key[i*6+0]);
1135a913ee7SJerome Forissier       x1 += m_key[i*6+1];
1145a913ee7SJerome Forissier       x2 += m_key[i*6+2];
115*8411e6adSJerome Forissier       MUL(x3, m_key[i*6+3]);
1165a913ee7SJerome Forissier       t0 = x0^x2;
117*8411e6adSJerome Forissier       MUL(t0, m_key[i*6+4]);
1185a913ee7SJerome Forissier       t1 = t0 + (x1^x3);
119*8411e6adSJerome Forissier       MUL(t1, m_key[i*6+5]);
1205a913ee7SJerome Forissier       t0 += t1;
1215a913ee7SJerome Forissier       x0 ^= t1;
1225a913ee7SJerome Forissier       x3 ^= t0;
1235a913ee7SJerome Forissier       t0 ^= x1;
1245a913ee7SJerome Forissier       x1 = x2^t1;
1255a913ee7SJerome Forissier       x2 = t0;
1265a913ee7SJerome Forissier    }
1275a913ee7SJerome Forissier 
128*8411e6adSJerome Forissier    MUL(x0, m_key[LTC_IDEA_ROUNDS*6+0]);
1295a913ee7SJerome Forissier    x2 += m_key[LTC_IDEA_ROUNDS*6+1];
1305a913ee7SJerome Forissier    x1 += m_key[LTC_IDEA_ROUNDS*6+2];
131*8411e6adSJerome Forissier    MUL(x3, m_key[LTC_IDEA_ROUNDS*6+3]);
1325a913ee7SJerome Forissier 
133*8411e6adSJerome Forissier    STORE16(x0, out + 0);
134*8411e6adSJerome Forissier    STORE16(x2, out + 2);
135*8411e6adSJerome Forissier    STORE16(x1, out + 4);
136*8411e6adSJerome Forissier    STORE16(x3, out + 6);
1375a913ee7SJerome Forissier 
1385a913ee7SJerome Forissier    return CRYPT_OK;
1395a913ee7SJerome Forissier }
1405a913ee7SJerome Forissier 
idea_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)1415a913ee7SJerome Forissier int idea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
1425a913ee7SJerome Forissier {
1435a913ee7SJerome Forissier    LTC_ARGCHK(key  != NULL);
1445a913ee7SJerome Forissier    LTC_ARGCHK(skey != NULL);
1455a913ee7SJerome Forissier 
1465a913ee7SJerome Forissier    if (num_rounds != 0 && num_rounds != 8) return CRYPT_INVALID_ROUNDS;
1475a913ee7SJerome Forissier    if (keylen != 16) return CRYPT_INVALID_KEYSIZE;
1485a913ee7SJerome Forissier 
149*8411e6adSJerome Forissier    return s_setup_key(key, skey);
1505a913ee7SJerome Forissier }
1515a913ee7SJerome Forissier 
idea_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)1525a913ee7SJerome Forissier int idea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
1535a913ee7SJerome Forissier {
154*8411e6adSJerome Forissier    int err = s_process_block(pt, ct, skey->idea.ek);
1555a913ee7SJerome Forissier #ifdef LTC_CLEAN_STACK
1565a913ee7SJerome Forissier    burn_stack(sizeof(ushort16) * 6 + sizeof(int));
1575a913ee7SJerome Forissier #endif
1585a913ee7SJerome Forissier    return err;
1595a913ee7SJerome Forissier }
1605a913ee7SJerome Forissier 
idea_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)1615a913ee7SJerome Forissier int idea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
1625a913ee7SJerome Forissier {
163*8411e6adSJerome Forissier    int err = s_process_block(ct, pt, skey->idea.dk);
1645a913ee7SJerome Forissier #ifdef LTC_CLEAN_STACK
1655a913ee7SJerome Forissier    burn_stack(sizeof(ushort16) * 6 + sizeof(int));
1665a913ee7SJerome Forissier #endif
1675a913ee7SJerome Forissier    return err;
1685a913ee7SJerome Forissier }
1695a913ee7SJerome Forissier 
idea_done(symmetric_key * skey)1705a913ee7SJerome Forissier void idea_done(symmetric_key *skey)
1715a913ee7SJerome Forissier {
1725a913ee7SJerome Forissier    LTC_UNUSED_PARAM(skey);
1735a913ee7SJerome Forissier }
1745a913ee7SJerome Forissier 
idea_keysize(int * keysize)1755a913ee7SJerome Forissier int idea_keysize(int *keysize)
1765a913ee7SJerome Forissier {
1775a913ee7SJerome Forissier    LTC_ARGCHK(keysize != NULL);
1785a913ee7SJerome Forissier    if (*keysize < 16) {
1795a913ee7SJerome Forissier       return CRYPT_INVALID_KEYSIZE;
1805a913ee7SJerome Forissier    }
1815a913ee7SJerome Forissier    *keysize = 16;
1825a913ee7SJerome Forissier    return CRYPT_OK;
1835a913ee7SJerome Forissier }
1845a913ee7SJerome Forissier 
idea_test(void)1855a913ee7SJerome Forissier int idea_test(void)
1865a913ee7SJerome Forissier {
1875a913ee7SJerome Forissier #ifndef LTC_TEST
1885a913ee7SJerome Forissier    return CRYPT_NOP;
1895a913ee7SJerome Forissier #else
1905a913ee7SJerome Forissier    static const struct {
1915a913ee7SJerome Forissier       unsigned char key[16], pt[8], ct[8];
1925a913ee7SJerome Forissier    } tests[] = {
1935a913ee7SJerome Forissier       {
1945a913ee7SJerome Forissier          /* key */ { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1955a913ee7SJerome Forissier          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1965a913ee7SJerome Forissier          /* ct  */ { 0xB1, 0xF5, 0xF7, 0xF8, 0x79, 0x01, 0x37, 0x0F }
1975a913ee7SJerome Forissier       },
1985a913ee7SJerome Forissier       {
1995a913ee7SJerome Forissier          /* key */ { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2005a913ee7SJerome Forissier          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2015a913ee7SJerome Forissier          /* ct  */ { 0xB3, 0x92, 0x7D, 0xFF, 0xB6, 0x35, 0x86, 0x26 }
2025a913ee7SJerome Forissier       },
2035a913ee7SJerome Forissier       {
2045a913ee7SJerome Forissier          /* key */ { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2055a913ee7SJerome Forissier          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2065a913ee7SJerome Forissier          /* ct  */ { 0xE9, 0x87, 0xE0, 0x02, 0x9F, 0xB9, 0x97, 0x85 }
2075a913ee7SJerome Forissier       },
2085a913ee7SJerome Forissier       {
2095a913ee7SJerome Forissier          /* key */ { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2105a913ee7SJerome Forissier          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2115a913ee7SJerome Forissier          /* ct  */ { 0x75, 0x4A, 0x03, 0xCE, 0x08, 0xDB, 0x7D, 0xAA }
2125a913ee7SJerome Forissier       },
2135a913ee7SJerome Forissier       {
2145a913ee7SJerome Forissier          /* key */ { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2155a913ee7SJerome Forissier          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2165a913ee7SJerome Forissier          /* ct  */ { 0xF0, 0x15, 0xF9, 0xFB, 0x0C, 0xFC, 0x7E, 0x1C }
2175a913ee7SJerome Forissier       },
2185a913ee7SJerome Forissier    };
2195a913ee7SJerome Forissier 
2205a913ee7SJerome Forissier    unsigned char buf[2][8];
2215a913ee7SJerome Forissier    symmetric_key key;
2225a913ee7SJerome Forissier    int err, x;
2235a913ee7SJerome Forissier 
2245a913ee7SJerome Forissier    if (sizeof(ushort16) != 2) {
2255a913ee7SJerome Forissier       return CRYPT_FAIL_TESTVECTOR;
2265a913ee7SJerome Forissier    }
2275a913ee7SJerome Forissier 
2285a913ee7SJerome Forissier    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
2295a913ee7SJerome Forissier       if ((err = idea_setup(tests[x].key, 16, 8, &key)) != CRYPT_OK) {
2305a913ee7SJerome Forissier          return err;
2315a913ee7SJerome Forissier       }
2325a913ee7SJerome Forissier       if ((err = idea_ecb_encrypt(tests[x].pt, buf[0], &key)) != CRYPT_OK) {
2335a913ee7SJerome Forissier          return err;
2345a913ee7SJerome Forissier       }
2355a913ee7SJerome Forissier       if (compare_testvector(buf[0], 8, tests[x].ct, 8, "IDEA Encrypt", x)) {
2365a913ee7SJerome Forissier          return CRYPT_FAIL_TESTVECTOR;
2375a913ee7SJerome Forissier       }
2385a913ee7SJerome Forissier       if ((err = idea_ecb_decrypt(tests[x].ct, buf[1], &key)) != CRYPT_OK) {
2395a913ee7SJerome Forissier          return err;
2405a913ee7SJerome Forissier       }
2415a913ee7SJerome Forissier       if (compare_testvector(buf[1], 8, tests[x].pt, 8, "IDEA Decrypt", x)) {
2425a913ee7SJerome Forissier          return CRYPT_FAIL_TESTVECTOR;
2435a913ee7SJerome Forissier       }
2445a913ee7SJerome Forissier    }
2455a913ee7SJerome Forissier 
2465a913ee7SJerome Forissier    return CRYPT_OK;
2475a913ee7SJerome Forissier #endif
2485a913ee7SJerome Forissier }
2495a913ee7SJerome Forissier 
2505a913ee7SJerome Forissier #endif
251