aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/block/idea/idea.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/block/idea/idea.cpp')
-rw-r--r--src/lib/block/idea/idea.cpp169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/lib/block/idea/idea.cpp b/src/lib/block/idea/idea.cpp
new file mode 100644
index 000000000..61a938c57
--- /dev/null
+++ b/src/lib/block/idea/idea.cpp
@@ -0,0 +1,169 @@
+/*
+* IDEA
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/idea.h>
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+namespace {
+
+/*
+* Multiplication modulo 65537
+*/
+inline u16bit mul(u16bit x, u16bit y)
+ {
+ const u32bit P = static_cast<u32bit>(x) * y;
+
+ // P ? 0xFFFF : 0
+ const u16bit P_mask = !P - 1;
+
+ const u32bit P_hi = P >> 16;
+ const u32bit P_lo = P & 0xFFFF;
+
+ const u16bit r_1 = (P_lo - P_hi) + (P_lo < P_hi);
+ const u16bit r_2 = 1 - x - y;
+
+ return (r_1 & P_mask) | (r_2 & ~P_mask);
+ }
+
+/*
+* Find multiplicative inverses modulo 65537
+*
+* 65537 is prime; thus Fermat's little theorem tells us that
+* x^65537 == x modulo 65537, which means
+* x^(65537-2) == x^-1 modulo 65537 since
+* x^(65537-2) * x == 1 mod 65537
+*
+* Do the exponentiation with a basic square and multiply: all bits are
+* of exponent are 1 so we always multiply
+*/
+u16bit mul_inv(u16bit x)
+ {
+ u16bit y = x;
+
+ for(size_t i = 0; i != 15; ++i)
+ {
+ y = mul(y, y); // square
+ y = mul(y, x);
+ }
+
+ return y;
+ }
+
+/**
+* IDEA is involutional, depending only on the key schedule
+*/
+void idea_op(const byte in[], byte out[], size_t blocks, const u16bit K[52])
+ {
+ const size_t BLOCK_SIZE = 8;
+
+ for(size_t i = 0; i != blocks; ++i)
+ {
+ u16bit X1 = load_be<u16bit>(in, 0);
+ u16bit X2 = load_be<u16bit>(in, 1);
+ u16bit X3 = load_be<u16bit>(in, 2);
+ u16bit X4 = load_be<u16bit>(in, 3);
+
+ for(size_t j = 0; j != 8; ++j)
+ {
+ X1 = mul(X1, K[6*j+0]);
+ X2 += K[6*j+1];
+ X3 += K[6*j+2];
+ X4 = mul(X4, K[6*j+3]);
+
+ u16bit T0 = X3;
+ X3 = mul(X3 ^ X1, K[6*j+4]);
+
+ u16bit T1 = X2;
+ X2 = mul((X2 ^ X4) + X3, K[6*j+5]);
+ X3 += X2;
+
+ X1 ^= X2;
+ X4 ^= X3;
+ X2 ^= T0;
+ X3 ^= T1;
+ }
+
+ X1 = mul(X1, K[48]);
+ X2 += K[50];
+ X3 += K[49];
+ X4 = mul(X4, K[51]);
+
+ store_be(out, X1, X3, X2, X4);
+
+ in += BLOCK_SIZE;
+ out += BLOCK_SIZE;
+ }
+ }
+
+}
+
+/*
+* IDEA Encryption
+*/
+void IDEA::encrypt_n(const byte in[], byte out[], size_t blocks) const
+ {
+ idea_op(in, out, blocks, &EK[0]);
+ }
+
+/*
+* IDEA Decryption
+*/
+void IDEA::decrypt_n(const byte in[], byte out[], size_t blocks) const
+ {
+ idea_op(in, out, blocks, &DK[0]);
+ }
+
+/*
+* IDEA Key Schedule
+*/
+void IDEA::key_schedule(const byte key[], size_t)
+ {
+ EK.resize(52);
+ DK.resize(52);
+
+ for(size_t i = 0; i != 8; ++i)
+ EK[i] = load_be<u16bit>(key, i);
+
+ for(size_t i = 1, j = 8, offset = 0; j != 52; i %= 8, ++i, ++j)
+ {
+ EK[i+7+offset] = static_cast<u16bit>((EK[(i % 8) + offset] << 9) |
+ (EK[((i+1) % 8) + offset] >> 7));
+ offset += (i == 8) ? 8 : 0;
+ }
+
+ DK[51] = mul_inv(EK[3]);
+ DK[50] = -EK[2];
+ DK[49] = -EK[1];
+ DK[48] = mul_inv(EK[0]);
+
+ for(size_t i = 1, j = 4, counter = 47; i != 8; ++i, j += 6)
+ {
+ DK[counter--] = EK[j+1];
+ DK[counter--] = EK[j];
+ DK[counter--] = mul_inv(EK[j+5]);
+ DK[counter--] = -EK[j+3];
+ DK[counter--] = -EK[j+4];
+ DK[counter--] = mul_inv(EK[j+2]);
+ }
+
+ DK[5] = EK[47];
+ DK[4] = EK[46];
+ DK[3] = mul_inv(EK[51]);
+ DK[2] = -EK[50];
+ DK[1] = -EK[49];
+ DK[0] = mul_inv(EK[48]);
+ }
+
+void IDEA::clear()
+ {
+ zap(EK);
+ zap(DK);
+ }
+
+}