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