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