--- /dev/null
+/* -*-c-*-
+ *
+ * Implementation of the IDEA cipher
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#include "blkc.h"
+#include "gcipher.h"
+#include "idea.h"
+
+/*----- Global variables --------------------------------------------------*/
+
+const octet idea_keysz[] = { KSZ_SET, IDEA_KEYSZ };
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @inv@ --- *
+ *
+ * Arguments: @uint16 n@ = number to invert
+ *
+ * Returns: Multiplicative inverse of @n@ %$\pmod{2^{16} + 1}$%.
+ *
+ * Use: Computes multiplicative inverses. This is handy for the
+ * decryption key scheduling.
+ */
+
+static uint16 inv(uint16 n)
+{
+ uint32 m = 0x10001;
+ uint32 a = 1, b = 0;
+ uint32 nn = n;
+
+ if (!nn)
+ nn = 0x10000;
+ for (;;) {
+ uint32 q, r, t;
+ if (!(r = m % nn))
+ break;
+ q = m / nn;
+ m = nn; nn = r;
+ t = a; a = b - q * a; b = t;
+ }
+ if (a > MASK16)
+ a += 1;
+ return (U16(a));
+}
+
+/* --- @MUL@ --- *
+ *
+ * Arguments @x@ and @y@ are two 32-bit values to multiply. On exit, @x@ is
+ * the product of the two arguments. The result is not normalized back to 16
+ * bits; the arguments are not expected to be normalized.
+ *
+ * This code is from `Side Channel Attack Hardening of the IDEA Cipher',
+ * published by Ascom Tech.
+ */
+
+#define MUL(x, y) do { \
+ unsigned _t; \
+ uint32 _tt; \
+ \
+ x = U16(x - 1); \
+ _t = U16(y - 1); \
+ _tt = (uint32)x * (uint32)_t + (uint32)x + (uint32)_t + 1; \
+ x = U16(_tt); \
+ _t = U16(_tt >> 16); \
+ x = x - _t + (x <= _t); \
+} while (0)
+
+/* --- @idea_init@ --- *
+ *
+ * Arguments: @idea_ctx *k@ = pointer to key block
+ * @const void *buf@ = pointer to key buffer
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an IDEA key buffer. The buffer must be exactly
+ * 16 bytes in size, because IDEA is only defined with a key
+ * size of 128 bits.
+ */
+
+void idea_init(idea_ctx *k, const void *buf, size_t sz)
+{
+ KSZ_ASSERT(idea, sz);
+
+ /* --- Unpack the encryption key --- */
+
+ {
+ const octet *p = buf;
+ uint16 *q = k->e;
+ uint32 a = LOAD32(p + 0);
+ uint32 b = LOAD32(p + 4);
+ uint32 c = LOAD32(p + 8);
+ uint32 d = LOAD32(p + 12);
+ int i;
+
+ /* --- Main unpacking loop --- */
+
+ for (i = 0; i < 6; i++) {
+
+ /* --- Spit out the next 8 subkeys --- */
+
+ q[0] = U16(a >> 16);
+ q[1] = U16(a >> 0);
+ q[2] = U16(b >> 16);
+ q[3] = U16(b >> 0);
+ q[4] = U16(c >> 16);
+ q[5] = U16(c >> 0);
+ q[6] = U16(d >> 16);
+ q[7] = U16(d >> 0);
+ q += 8;
+
+ /* --- Rotate and permute the subkeys --- */
+
+ {
+ uint32 t = a;
+ a = U32((a << 25) | (b >> 7));
+ b = U32((b << 25) | (c >> 7));
+ c = U32((c << 25) | (d >> 7));
+ d = U32((d << 25) | (t >> 7));
+ }
+ }
+
+ /* --- Write out the tail-enders --- */
+
+ q[0] = U16(a >> 16);
+ q[1] = U16(a >> 0);
+ q[2] = U16(b >> 16);
+ q[3] = U16(b >> 0);
+ }
+
+ /* --- Convert this into the decryption key --- */
+
+ {
+ uint16 *p = k->e + 52;
+ uint16 *q = k->d;
+ int i;
+
+ /* --- Translate the main round keys --- */
+
+ for (i = 0; i < 8; i++) {
+ p -= 6;
+ q[4] = p[0];
+ q[5] = p[1];
+ q[0] = inv(p[2]);
+ q[3] = inv(p[5]);
+ if (i) {
+ q[1] = 0x10000 - p[4];
+ q[2] = 0x10000 - p[3];
+ } else {
+ q[1] = 0x10000 - p[3];
+ q[2] = 0x10000 - p[4];
+ }
+ q += 6;
+ }
+
+ /* --- Translate the tail-enders --- */
+
+ p -= 4;
+ q[0] = inv(p[0]);
+ q[1] = 0x10000 - p[1];
+ q[2] = 0x10000 - p[2];
+ q[3] = inv(p[3]);
+ }
+}
+
+/* --- @ROUND@ --- */
+
+#define MIX(k, a, b, c, d) do { \
+ MUL(a, k[0]); \
+ b += k[1]; \
+ c += k[2]; \
+ MUL(d, k[3]); \
+} while (0)
+
+#define MA(k, a, b, c, d) do { \
+ unsigned _u = a ^ c; \
+ unsigned _v = b ^ d; \
+ MUL(_u, k[4]); \
+ _v += _u; \
+ MUL(_v, k[5]); \
+ _u += _v; \
+ a ^= _v; \
+ b ^= _u; \
+ c ^= _v; \
+ d ^= _u; \
+} while (0);
+
+#define ROUND(k, a, b, c, d) do { \
+ MIX(k, a, b, c, d); \
+ MA(k, a, b, c, d); \
+ (k) += 6; \
+} while (0)
+
+/* --- Encryption --- */
+
+#define EBLK(k, a, b, c, d) do { \
+ unsigned _a = U16(a >> 16); \
+ unsigned _b = U16(a >> 0); \
+ unsigned _c = U16(b >> 16); \
+ unsigned _d = U16(b >> 0); \
+ const uint16 *_k = (k); \
+ \
+ ROUND(_k, _a, _b, _c, _d); \
+ ROUND(_k, _a, _c, _b, _d); \
+ ROUND(_k, _a, _b, _c, _d); \
+ ROUND(_k, _a, _c, _b, _d); \
+ ROUND(_k, _a, _b, _c, _d); \
+ ROUND(_k, _a, _c, _b, _d); \
+ ROUND(_k, _a, _b, _c, _d); \
+ ROUND(_k, _a, _c, _b, _d); \
+ MIX (_k, _a, _c, _b, _d); \
+ c = ((uint32)U16(_a) << 16) | (uint32)U16(_c); \
+ d = ((uint32)U16(_b) << 16) | (uint32)U16(_d); \
+} while (0)
+
+#define DBLK(k, a, b) EBLK((k), (a), (b))
+
+/* --- @idea_eblk@, @idea_dblk@ --- *
+ *
+ * Arguments: @const idea_ctx *k@ = pointer to a key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+void idea_eblk(const idea_ctx *k, const uint32 *s, uint32 *d)
+{
+ EBLK(k->e, s[0], s[1], d[0], d[1]);
+}
+
+void idea_dblk(const idea_ctx *k, const uint32 *s, uint32 *d)
+{
+ EBLK(k->d, s[0], s[1], d[0], d[1]);
+}
+
+BLKC_TEST(IDEA, idea)
+
+/*----- That's all, folks -------------------------------------------------*/