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