|
@@ -0,0 +1,252 @@
|
|
|
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
|
|
+ *
|
|
|
+ * LibTomCrypt is a library that provides various cryptographic
|
|
|
+ * algorithms in a highly modular and flexible manner.
|
|
|
+ *
|
|
|
+ * The library is free for all purposes without any express
|
|
|
+ * guarantee it works.
|
|
|
+ */
|
|
|
+
|
|
|
+/* Based on idea.cpp - originally written and placed in the public domain by Wei Dai
|
|
|
+ https://github.com/weidai11/cryptopp/blob/master/idea.cpp
|
|
|
+
|
|
|
+ Patents should be expired. On 2017-10-16 wikipedia says:
|
|
|
+ https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm
|
|
|
+
|
|
|
+ A patent application for IDEA was first filed in Switzerland (CH A 1690/90) on May 18, 1990,
|
|
|
+ then an international patent application was filed under the Patent Cooperation Treaty on
|
|
|
+ May 16, 1991. Patents were eventually granted in Austria, France, Germany, Italy, the Netherlands,
|
|
|
+ Spain, Sweden, Switzerland, the United Kingdom, (European Patent Register entry for European
|
|
|
+ patent no. 0482154, filed May 16, 1991, issued June 22, 1994 and expired May 16, 2011),
|
|
|
+ the United States (U.S. Patent 5,214,703, issued May 25, 1993 and expired January 7, 2012)
|
|
|
+ and Japan (JP 3225440) (expired May 16, 2011).
|
|
|
+ */
|
|
|
+
|
|
|
+#include "tomcrypt.h"
|
|
|
+
|
|
|
+#ifdef LTC_IDEA
|
|
|
+
|
|
|
+const struct ltc_cipher_descriptor idea_desc = {
|
|
|
+ "idea",
|
|
|
+ 24, /* cipher_ID */
|
|
|
+ 16, 16, 8, 8, /* min_key_len, max_key_len, block_len, default_rounds */
|
|
|
+ &idea_setup,
|
|
|
+ &idea_ecb_encrypt,
|
|
|
+ &idea_ecb_decrypt,
|
|
|
+ &idea_test,
|
|
|
+ &idea_done,
|
|
|
+ &idea_keysize,
|
|
|
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
|
|
+};
|
|
|
+
|
|
|
+typedef unsigned short int ushort16;
|
|
|
+
|
|
|
+#define _LOW16(x) ((x)&0xffff) /* compiler should be able to optimize this away if x is 16 bits */
|
|
|
+#define _HIGH16(x) ((x)>>16)
|
|
|
+#define _MUL(a,b) { \
|
|
|
+ ulong32 p = (ulong32)_LOW16(a) * b; \
|
|
|
+ if (p) { \
|
|
|
+ p = _LOW16(p) - _HIGH16(p); \
|
|
|
+ a = (ushort16)p - (ushort16)_HIGH16(p); \
|
|
|
+ } \
|
|
|
+ else \
|
|
|
+ a = 1 - a - b; \
|
|
|
+ }
|
|
|
+#define _STORE16(x,y) { (y)[0] = (unsigned char)(((x)>>8)&255); (y)[1] = (unsigned char)((x)&255); }
|
|
|
+#define _LOAD16(x,y) { x = ((ushort16)((y)[0] & 255)<<8) | ((ushort16)((y)[1] & 255)); }
|
|
|
+
|
|
|
+static ushort16 _mul_inv(ushort16 x)
|
|
|
+{
|
|
|
+ ushort16 y = x;
|
|
|
+ unsigned i;
|
|
|
+
|
|
|
+ for (i = 0; i < 15; i++) {
|
|
|
+ _MUL(y, _LOW16(y));
|
|
|
+ _MUL(y, x);
|
|
|
+ }
|
|
|
+ return _LOW16(y);
|
|
|
+}
|
|
|
+
|
|
|
+static ushort16 _add_inv(ushort16 x)
|
|
|
+{
|
|
|
+ return _LOW16(0 - x);
|
|
|
+}
|
|
|
+
|
|
|
+static int _setup_key(const unsigned char *key, symmetric_key *skey)
|
|
|
+{
|
|
|
+ int i, j;
|
|
|
+ ushort16 *e_key = skey->idea.ek;
|
|
|
+ ushort16 *d_key = skey->idea.dk;
|
|
|
+
|
|
|
+ /* prepare enc key */
|
|
|
+ for (i = 0; i < 8; i++) {
|
|
|
+ _LOAD16(e_key[i], key + 2 * i);
|
|
|
+ }
|
|
|
+ for (; i < LTC_IDEA_KEYLEN; i++) {
|
|
|
+ j = (i - i % 8) - 8;
|
|
|
+ e_key[i] = _LOW16((e_key[j+(i+1)%8] << 9) | (e_key[j+(i+2)%8] >> 7));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* prepare dec key */
|
|
|
+ for (i = 0; i < LTC_IDEA_ROUNDS; i++) {
|
|
|
+ d_key[i*6+0] = _mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+0]);
|
|
|
+ d_key[i*6+1] = _add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+1+(i>0 ? 1 : 0)]);
|
|
|
+ d_key[i*6+2] = _add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+2-(i>0 ? 1 : 0)]);
|
|
|
+ d_key[i*6+3] = _mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+3]);
|
|
|
+ d_key[i*6+4] = e_key[(LTC_IDEA_ROUNDS-1-i)*6+4];
|
|
|
+ d_key[i*6+5] = e_key[(LTC_IDEA_ROUNDS-1-i)*6+5];
|
|
|
+ }
|
|
|
+ d_key[i*6+0] = _mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+0]);
|
|
|
+ d_key[i*6+1] = _add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+1]);
|
|
|
+ d_key[i*6+2] = _add_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+2]);
|
|
|
+ d_key[i*6+3] = _mul_inv(e_key[(LTC_IDEA_ROUNDS-i)*6+3]);
|
|
|
+
|
|
|
+ return CRYPT_OK;
|
|
|
+}
|
|
|
+
|
|
|
+static int _process_block(const unsigned char *in, unsigned char *out, ushort16 *m_key)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ ushort16 x0, x1, x2, x3, t0, t1;
|
|
|
+
|
|
|
+ _LOAD16(x0, in + 0);
|
|
|
+ _LOAD16(x1, in + 2);
|
|
|
+ _LOAD16(x2, in + 4);
|
|
|
+ _LOAD16(x3, in + 6);
|
|
|
+
|
|
|
+ for (i = 0; i < LTC_IDEA_ROUNDS; i++) {
|
|
|
+ _MUL(x0, m_key[i*6+0]);
|
|
|
+ x1 += m_key[i*6+1];
|
|
|
+ x2 += m_key[i*6+2];
|
|
|
+ _MUL(x3, m_key[i*6+3]);
|
|
|
+ t0 = x0^x2;
|
|
|
+ _MUL(t0, m_key[i*6+4]);
|
|
|
+ t1 = t0 + (x1^x3);
|
|
|
+ _MUL(t1, m_key[i*6+5]);
|
|
|
+ t0 += t1;
|
|
|
+ x0 ^= t1;
|
|
|
+ x3 ^= t0;
|
|
|
+ t0 ^= x1;
|
|
|
+ x1 = x2^t1;
|
|
|
+ x2 = t0;
|
|
|
+ }
|
|
|
+
|
|
|
+ _MUL(x0, m_key[LTC_IDEA_ROUNDS*6+0]);
|
|
|
+ x2 += m_key[LTC_IDEA_ROUNDS*6+1];
|
|
|
+ x1 += m_key[LTC_IDEA_ROUNDS*6+2];
|
|
|
+ _MUL(x3, m_key[LTC_IDEA_ROUNDS*6+3]);
|
|
|
+
|
|
|
+ _STORE16(x0, out + 0);
|
|
|
+ _STORE16(x2, out + 2);
|
|
|
+ _STORE16(x1, out + 4);
|
|
|
+ _STORE16(x3, out + 6);
|
|
|
+
|
|
|
+ return CRYPT_OK;
|
|
|
+}
|
|
|
+
|
|
|
+int idea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
|
|
|
+{
|
|
|
+ LTC_ARGCHK(key != NULL);
|
|
|
+ LTC_ARGCHK(skey != NULL);
|
|
|
+
|
|
|
+ if (num_rounds != 0 && num_rounds != 8) return CRYPT_INVALID_ROUNDS;
|
|
|
+ if (keylen != 16) return CRYPT_INVALID_KEYSIZE;
|
|
|
+
|
|
|
+ return _setup_key(key, skey);
|
|
|
+}
|
|
|
+
|
|
|
+int idea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
|
|
|
+{
|
|
|
+ return _process_block(pt, ct, skey->idea.ek);
|
|
|
+}
|
|
|
+
|
|
|
+int idea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
|
|
|
+{
|
|
|
+ return _process_block(ct, pt, skey->idea.dk);
|
|
|
+}
|
|
|
+
|
|
|
+void idea_done(symmetric_key *skey)
|
|
|
+{
|
|
|
+ LTC_UNUSED_PARAM(skey);
|
|
|
+}
|
|
|
+
|
|
|
+int idea_keysize(int *keysize)
|
|
|
+{
|
|
|
+ LTC_ARGCHK(keysize != NULL);
|
|
|
+ if (*keysize < 16) {
|
|
|
+ return CRYPT_INVALID_KEYSIZE;
|
|
|
+ }
|
|
|
+ *keysize = 16;
|
|
|
+ return CRYPT_OK;
|
|
|
+}
|
|
|
+
|
|
|
+int idea_test(void)
|
|
|
+{
|
|
|
+#ifndef LTC_TEST
|
|
|
+ return CRYPT_NOP;
|
|
|
+#else
|
|
|
+ static const struct {
|
|
|
+ unsigned char key[16], pt[8], ct[8];
|
|
|
+ } tests[] = {
|
|
|
+ {
|
|
|
+ /* key */ { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* pt */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* ct */ { 0xB1, 0xF5, 0xF7, 0xF8, 0x79, 0x01, 0x37, 0x0F }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ /* key */ { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* pt */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* ct */ { 0xB3, 0x92, 0x7D, 0xFF, 0xB6, 0x35, 0x86, 0x26 }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ /* key */ { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* pt */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* ct */ { 0xE9, 0x87, 0xE0, 0x02, 0x9F, 0xB9, 0x97, 0x85 }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ /* key */ { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* pt */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* ct */ { 0x75, 0x4A, 0x03, 0xCE, 0x08, 0xDB, 0x7D, 0xAA }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ /* key */ { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* pt */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
|
|
+ /* ct */ { 0xF0, 0x15, 0xF9, 0xFB, 0x0C, 0xFC, 0x7E, 0x1C }
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ unsigned char buf[2][8];
|
|
|
+ symmetric_key key;
|
|
|
+ int err, x;
|
|
|
+
|
|
|
+ if (sizeof(ushort16) != 2) {
|
|
|
+ return CRYPT_FAIL_TESTVECTOR;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
|
|
|
+ if ((err = idea_setup(tests[x].key, 16, 8, &key)) != CRYPT_OK) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ if ((err = idea_ecb_encrypt(tests[x].pt, buf[0], &key)) != CRYPT_OK) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ if (compare_testvector(buf[0], 8, tests[x].ct, 8, "IDEA Encrypt", x)) {
|
|
|
+ return CRYPT_FAIL_TESTVECTOR;
|
|
|
+ }
|
|
|
+ if ((err = idea_ecb_decrypt(tests[x].ct, buf[1], &key)) != CRYPT_OK) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ if (compare_testvector(buf[1], 8, tests[x].pt, 8, "IDEA Decrypt", x)) {
|
|
|
+ return CRYPT_FAIL_TESTVECTOR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return CRYPT_OK;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+/* ref: $Format:%D$ */
|
|
|
+/* git commit: $Format:%H$ */
|
|
|
+/* commit time: $Format:%ai$ */
|