1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /* Based on idea.cpp - originally written and placed in the public domain by Wei Dai
5    https://github.com/weidai11/cryptopp/blob/master/idea.cpp
6 
7    Patents should be expired. On 2017-10-16 wikipedia says:
8    https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm
9 
10    A patent application for IDEA was first filed in Switzerland (CH A 1690/90) on May 18, 1990,
11    then an international patent application was filed under the Patent Cooperation Treaty on
12    May 16, 1991. Patents were eventually granted in Austria, France, Germany, Italy, the Netherlands,
13    Spain, Sweden, Switzerland, the United Kingdom, (European Patent Register entry for European
14    patent no. 0482154, filed May 16, 1991, issued June 22, 1994 and expired May 16, 2011),
15    the United States (U.S. Patent 5,214,703, issued May 25, 1993 and expired January 7, 2012)
16    and Japan (JP 3225440) (expired May 16, 2011).
17  */
18 
19 #include "tomcrypt_private.h"
20 
21 #ifdef LTC_IDEA
22 
23 const struct ltc_cipher_descriptor idea_desc = {
24    "idea",
25    24,                  /* cipher_ID */
26    16, 16, 8, 8,        /* min_key_len, max_key_len, block_len, default_rounds */
27    &idea_setup,
28    &idea_ecb_encrypt,
29    &idea_ecb_decrypt,
30    &idea_test,
31    &idea_done,
32    &idea_keysize,
33    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
34 };
35 
36 typedef unsigned short int ushort16;
37 
38 #define LOW16(x)     ((x)&0xffff)  /* compiler should be able to optimize this away if x is 16 bits */
39 #define HIGH16(x)    ((x)>>16)
40 #define MUL(a,b)     {                                               \
41                          ulong32 p = (ulong32)LOW16(a) * b;          \
42                          if (p) {                                     \
43                             p = LOW16(p) - HIGH16(p);               \
44                             a = (ushort16)p - (ushort16)HIGH16(p);   \
45                          }                                            \
46                          else                                         \
47                             a = 1 - a - b;                            \
48                       }
49 #define STORE16(x,y) { (y)[0] = (unsigned char)(((x)>>8)&255); (y)[1] = (unsigned char)((x)&255); }
50 #define LOAD16(x,y)  { x = ((ushort16)((y)[0] & 255)<<8) | ((ushort16)((y)[1] & 255)); }
51 
s_mul_inv(ushort16 x)52 static ushort16 s_mul_inv(ushort16 x)
53 {
54    ushort16 y = x;
55    unsigned i;
56 
57    for (i = 0; i < 15; i++) {
58       MUL(y, LOW16(y));
59       MUL(y, x);
60    }
61    return LOW16(y);
62 }
63 
s_add_inv(ushort16 x)64 static ushort16 s_add_inv(ushort16 x)
65 {
66    return LOW16(0 - x);
67 }
68 
s_setup_key(const unsigned char * key,symmetric_key * skey)69 static int s_setup_key(const unsigned char *key, symmetric_key *skey)
70 {
71    int i, j;
72    ushort16 *e_key = skey->idea.ek;
73    ushort16 *d_key = skey->idea.dk;
74 
75    /* prepare enc key */
76    for (i = 0; i < 8; i++) {
77       LOAD16(e_key[i], key + 2 * i);
78    }
79    for (; i < LTC_IDEA_KEYLEN; i++) {
80       j = (i - i % 8) - 8;
81       e_key[i] = LOW16((e_key[j+(i+1)%8] << 9) | (e_key[j+(i+2)%8] >> 7));
82    }
83 
84    /* prepare dec key */
85    for (i = 0; i < LTC_IDEA_ROUNDS; i++) {
86       d_key[i*6+0] = s_mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+0]);
87       d_key[i*6+1] = s_add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+1+(i>0 ? 1 : 0)]);
88       d_key[i*6+2] = s_add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+2-(i>0 ? 1 : 0)]);
89       d_key[i*6+3] = s_mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+3]);
90       d_key[i*6+4] =           e_key[(LTC_IDEA_ROUNDS-1-i)*6+4];
91       d_key[i*6+5] =           e_key[(LTC_IDEA_ROUNDS-1-i)*6+5];
92    }
93    d_key[i*6+0] = s_mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+0]);
94    d_key[i*6+1] = s_add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+1]);
95    d_key[i*6+2] = s_add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+2]);
96    d_key[i*6+3] = s_mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+3]);
97 
98    return CRYPT_OK;
99 }
100 
s_process_block(const unsigned char * in,unsigned char * out,const ushort16 * m_key)101 static int s_process_block(const unsigned char *in, unsigned char *out, const ushort16 *m_key)
102 {
103    int i;
104    ushort16 x0, x1, x2, x3, t0, t1;
105 
106    LOAD16(x0, in + 0);
107    LOAD16(x1, in + 2);
108    LOAD16(x2, in + 4);
109    LOAD16(x3, in + 6);
110 
111    for (i = 0; i < LTC_IDEA_ROUNDS; i++) {
112       MUL(x0, m_key[i*6+0]);
113       x1 += m_key[i*6+1];
114       x2 += m_key[i*6+2];
115       MUL(x3, m_key[i*6+3]);
116       t0 = x0^x2;
117       MUL(t0, m_key[i*6+4]);
118       t1 = t0 + (x1^x3);
119       MUL(t1, m_key[i*6+5]);
120       t0 += t1;
121       x0 ^= t1;
122       x3 ^= t0;
123       t0 ^= x1;
124       x1 = x2^t1;
125       x2 = t0;
126    }
127 
128    MUL(x0, m_key[LTC_IDEA_ROUNDS*6+0]);
129    x2 += m_key[LTC_IDEA_ROUNDS*6+1];
130    x1 += m_key[LTC_IDEA_ROUNDS*6+2];
131    MUL(x3, m_key[LTC_IDEA_ROUNDS*6+3]);
132 
133    STORE16(x0, out + 0);
134    STORE16(x2, out + 2);
135    STORE16(x1, out + 4);
136    STORE16(x3, out + 6);
137 
138    return CRYPT_OK;
139 }
140 
idea_setup(const unsigned char * key,int keylen,int num_rounds,symmetric_key * skey)141 int idea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
142 {
143    LTC_ARGCHK(key  != NULL);
144    LTC_ARGCHK(skey != NULL);
145 
146    if (num_rounds != 0 && num_rounds != 8) return CRYPT_INVALID_ROUNDS;
147    if (keylen != 16) return CRYPT_INVALID_KEYSIZE;
148 
149    return s_setup_key(key, skey);
150 }
151 
idea_ecb_encrypt(const unsigned char * pt,unsigned char * ct,const symmetric_key * skey)152 int idea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const symmetric_key *skey)
153 {
154    int err = s_process_block(pt, ct, skey->idea.ek);
155 #ifdef LTC_CLEAN_STACK
156    burn_stack(sizeof(ushort16) * 6 + sizeof(int));
157 #endif
158    return err;
159 }
160 
idea_ecb_decrypt(const unsigned char * ct,unsigned char * pt,const symmetric_key * skey)161 int idea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const symmetric_key *skey)
162 {
163    int err = s_process_block(ct, pt, skey->idea.dk);
164 #ifdef LTC_CLEAN_STACK
165    burn_stack(sizeof(ushort16) * 6 + sizeof(int));
166 #endif
167    return err;
168 }
169 
idea_done(symmetric_key * skey)170 void idea_done(symmetric_key *skey)
171 {
172    LTC_UNUSED_PARAM(skey);
173 }
174 
idea_keysize(int * keysize)175 int idea_keysize(int *keysize)
176 {
177    LTC_ARGCHK(keysize != NULL);
178    if (*keysize < 16) {
179       return CRYPT_INVALID_KEYSIZE;
180    }
181    *keysize = 16;
182    return CRYPT_OK;
183 }
184 
idea_test(void)185 int idea_test(void)
186 {
187 #ifndef LTC_TEST
188    return CRYPT_NOP;
189 #else
190    static const struct {
191       unsigned char key[16], pt[8], ct[8];
192    } tests[] = {
193       {
194          /* key */ { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
195          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
196          /* ct  */ { 0xB1, 0xF5, 0xF7, 0xF8, 0x79, 0x01, 0x37, 0x0F }
197       },
198       {
199          /* key */ { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
200          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
201          /* ct  */ { 0xB3, 0x92, 0x7D, 0xFF, 0xB6, 0x35, 0x86, 0x26 }
202       },
203       {
204          /* key */ { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
205          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
206          /* ct  */ { 0xE9, 0x87, 0xE0, 0x02, 0x9F, 0xB9, 0x97, 0x85 }
207       },
208       {
209          /* key */ { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
210          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
211          /* ct  */ { 0x75, 0x4A, 0x03, 0xCE, 0x08, 0xDB, 0x7D, 0xAA }
212       },
213       {
214          /* key */ { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
215          /* pt  */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
216          /* ct  */ { 0xF0, 0x15, 0xF9, 0xFB, 0x0C, 0xFC, 0x7E, 0x1C }
217       },
218    };
219 
220    unsigned char buf[2][8];
221    symmetric_key key;
222    int err, x;
223 
224    if (sizeof(ushort16) != 2) {
225       return CRYPT_FAIL_TESTVECTOR;
226    }
227 
228    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
229       if ((err = idea_setup(tests[x].key, 16, 8, &key)) != CRYPT_OK) {
230          return err;
231       }
232       if ((err = idea_ecb_encrypt(tests[x].pt, buf[0], &key)) != CRYPT_OK) {
233          return err;
234       }
235       if (compare_testvector(buf[0], 8, tests[x].ct, 8, "IDEA Encrypt", x)) {
236          return CRYPT_FAIL_TESTVECTOR;
237       }
238       if ((err = idea_ecb_decrypt(tests[x].ct, buf[1], &key)) != CRYPT_OK) {
239          return err;
240       }
241       if (compare_testvector(buf[1], 8, tests[x].pt, 8, "IDEA Decrypt", x)) {
242          return CRYPT_FAIL_TESTVECTOR;
243       }
244    }
245 
246    return CRYPT_OK;
247 #endif
248 }
249 
250 #endif
251