HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM
Implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk)
This document was written to help programmers to understand how to
implement the IDEA cryptosystem.
Thanks to Colin Plumb (colin@nyx10.cs.du.edu) for helping to clear up
the mistakes I made in the draft version of this document. Sources were
taken from Colin Plumb's IDEA in 8086 assembly implementation, and the
IDEA reference source by Richard De Moliner (demoliner@isi.ee.ethz.ch).
Please let me know of any errors or ommisions.
IDEA works on 16 bit units. If you're processing bytes, it's defined to
be big-endian, so an Intel machine needs to swap the bytes around.
IDEA has a user key size of 16 bytes (128 bits) which is expanded to a
104 byte (832 bit) subkey. Data is processed in 8 byte (64 bit) blocks.
The Idea function needs the subkey for input, not the user key. The
following code example requires that the multiplication is done modulo
65537 (as defined in the IDEA specification). A zero input is taken to
be 65536.
void Idea(u_int16 *in, u_int16 *out, u_int16 *key)
{
u_int16 x0, x1, x2, x3, t0, t1, round;
x0 = *in++;
x1 = *in++;
x2 = *in++;
x3 = *in;
for (round = 0; round < 8; round++) {
x0 *= *key++;
x1 += *key++;
x2 += *key++;
x3 *= *key++;
t0 = x1;
t1 = x2;
x2 ^= x0;
x1 ^= x3;
x2 *= *key++;
x1 += x2;
x1 *= *key++;
x2 += x1;
x0 ^= x1;
x3 ^= x2;
x1 ^= t1;
x2 ^= t0;
}
*out++ = x0 * *key++;
*out++ = x2 + *key++; /* NB: Order */
*out++ = x1 + *key++;
*out = x3 * *key;
}
The following function can be used to perform the necessary
multiplication modulo 65537 used in IDEA.
u_int16 mul(u_int16 x, u_int16 y)
{
u_int32 p=x*y;
if (p == 0)
x = 65537-x-y;
else {
x = p >> 16;
y = p;
x = y-x;
if (y < x) x += 65537;
}
return x;
}
The following function is used to expand the user key to the encryption
subkey. The first 16 bytes are the user key, and the rest of the subkey
is calculated by rotating the previous 16 bytes by 25 bits to the left,
and so on until the subkey is completed. The following code could be
optimised.
void Expandkey(u_int16 *ukey, u_int16 *key)
{
int i;
for (i=0; i<8; i++) key[i]=ukey[i];
for (i=8; i<52; i++) {
if ((i & 7) < 6)
key[i]=(key[i-7] & 127) << 9 | key[i-6] >> 7;
else if ((i & 7) == 6)
key[i]=(key[i-7] & 127) << 9 | key[i-14] >> 7;
else
key[i]=(key[i-15] & 127) << 9 | key[i-14] >> 7;
}
}
The function to invert the encryption subkey to the decryption subkey is
required for decryption using ECB and CBC modes. It also involves the
multiplicative inverse and the additive inverse functions.
Rules:
x + addinv(x) == 0
x * mulinv(x) == 1 (modulo 65537)
void Invertkey(u_int16 *in, u_int16 *out)
{
u_int16 t1, t2, t3, t4, round;
u_int16 *p = out + 52; /* We work backwards */
t1 = mulinv(*in++);
t2 = addinv(*in++);
t3 = addinv(*in++);
t4 = mulinv(*in++);
*--p = t4;
*--p = t3;
*--p = t2;
*--p = t1;
for (round = 1; round < 8; round++) {
t1 = *in++;
t2 = *in++;
*--p = t2;
*--p = t1;
t1 = mulinv(*in++);
t2 = addinv(*in++);
t3 = addinv(*in++);
t4 = mulinv(*in++);
*--p = t4;
*--p = t2; /* NB: Order */
*--p = t3;
*--p = t1;
}
t1 = *in++;
t2 = *in++;
*--p = t2;
*--p = t1;
t1 = mulinv(*in++);
t2 = addinv(*in++);
t3 = addinv(*in++);
t4 = mulinv(*in++);
*--p = t4;
*--p = t3;
*--p = t2;
*--p = t1;
}
u_int16 addinv(u_int16 x)
{
return 0-x;
}
This function computes multiplicative inverse using Euclid's Greatest
Common Divisor algorithm. Zero and one are self inverse.
u_int16 mulinv(u_int16 x)
{
u_int16 t0, t1, q, y;
if (x < 2) return x;
t0 = 0;
t1 = 65537 / x;
y = 65537 % x;
while (y != 1) {
q = x / y;
x = x % y;
t0 = t0 + (t1 * q);
if (x == 1) return t0;
q = y / x;
y = y % x;
t1 = t1 + (t0 * q);
}
return 65537-x;
}
END