1 /** 2 * IDEA 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.block.idea; 12 13 import botan.constants; 14 static if (BOTAN_HAS_IDEA): 15 16 import botan.block.block_cipher; 17 import botan.utils.loadstor; 18 import botan.utils.types; 19 import botan.utils.mem_ops; 20 21 /** 22 * IDEA 23 */ 24 class IDEA : BlockCipherFixedParams!(8, 16), BlockCipher, SymmetricAlgorithm 25 { 26 public: 27 /* 28 * IDEA Encryption 29 */ 30 override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks) 31 { 32 idea_op(input, output, blocks, m_EK.ptr); 33 } 34 35 /* 36 * IDEA Decryption 37 */ 38 override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks) 39 { 40 idea_op(input, output, blocks, m_DK.ptr); 41 } 42 43 override void clear() 44 { 45 zap(m_EK); 46 zap(m_DK); 47 } 48 49 @property string name() const { return "IDEA"; } 50 override @property size_t parallelism() const { return 1; } 51 override BlockCipher clone() const { return new IDEA; } 52 override size_t blockSize() const { return super.blockSize(); } 53 override KeyLengthSpecification keySpec() const { return super.keySpec(); } 54 protected: 55 /** 56 * Returns: const reference to encryption subkeys 57 */ 58 ref const(SecureVector!ushort) getEK() const { return m_EK; } 59 60 /** 61 * Returns: const reference to decryption subkeys 62 */ 63 ref const(SecureVector!ushort) getDK() const { return m_DK; } 64 65 /* 66 * IDEA Key Schedule 67 */ 68 override void keySchedule(const(ubyte)* key, size_t) 69 { 70 m_EK.resize(52); 71 m_DK.resize(52); 72 73 foreach (size_t i; 0 .. 8) 74 m_EK[i] = loadBigEndian!ushort(key, i); 75 76 for (size_t i = 1, j = 8, offset = 0; j != 52; i %= 8, ++i, ++j) 77 { 78 m_EK[i+7+offset] = cast(ushort)((m_EK[(i % 8) + offset] << 9) | 79 (m_EK[((i+1) % 8) + offset] >> 7)); 80 offset += (i == 8) ? 8 : 0; 81 } 82 83 m_DK[51] = mul_inv(m_EK[3]); 84 m_DK[50] = -cast(int)m_EK[2]; 85 m_DK[49] = -cast(int)m_EK[1]; 86 m_DK[48] = mul_inv(m_EK[0]); 87 88 for (size_t i = 1, j = 4, counter = 47; i != 8; ++i, j += 6) 89 { 90 m_DK[counter--] = m_EK[j+1]; 91 m_DK[counter--] = m_EK[j]; 92 m_DK[counter--] = mul_inv(m_EK[j+5]); 93 m_DK[counter--] = -cast(int)m_EK[j+3]; 94 m_DK[counter--] = -cast(int)m_EK[j+4]; 95 m_DK[counter--] = mul_inv(m_EK[j+2]); 96 } 97 98 m_DK[5] = m_EK[47]; 99 m_DK[4] = m_EK[46]; 100 m_DK[3] = mul_inv(m_EK[51]); 101 m_DK[2] = -cast(int)m_EK[50]; 102 m_DK[1] = -cast(int)m_EK[49]; 103 m_DK[0] = mul_inv(m_EK[48]); 104 } 105 106 SecureVector!ushort m_EK, m_DK; 107 } 108 109 package: 110 111 /* 112 * Multiplication modulo 65537 113 */ 114 ushort mul(ushort x, ushort y) pure 115 { 116 const uint P = cast(uint)(x) * y; 117 118 // P ? 0xFFFF : 0 119 const ushort P_mask = cast(const ushort)(!P - 1); 120 121 const uint P_hi = P >> 16; 122 const uint P_lo = P & 0xFFFF; 123 124 const ushort r_1 = cast(const ushort) ((P_lo - P_hi) + (P_lo < P_hi)); 125 const ushort r_2 = cast(const ushort) (1 - x - y); 126 127 return cast(const ushort) ((r_1 & P_mask) | (r_2 & ~cast(int)P_mask)); 128 } 129 130 /* 131 * Find multiplicative inverses modulo 65537 132 * 133 * 65537 is prime; thus Fermat's little theorem tells us that 134 * x^65537 == x modulo 65537, which means 135 * x^(65537-2) == x^-1 modulo 65537 since 136 * x^(65537-2) * x == 1 mod 65537 137 * 138 * Do the exponentiation with a basic square and multiply: all bits are 139 * of exponent are 1 so we always multiply 140 */ 141 ushort mul_inv(ushort x) pure 142 { 143 ushort y = x; 144 145 foreach (size_t i; 0 .. 15) 146 { 147 y = mul(y, y); // square 148 y = mul(y, x); 149 } 150 151 return y; 152 } 153 154 /** 155 * IDEA is involutional, depending only on the key schedule 156 */ 157 void idea_op(const(ubyte)* input, ubyte* output, size_t blocks, in const(ushort)* K) 158 { 159 __gshared immutable size_t BLOCK_SIZE = 8; 160 161 foreach (size_t i; 0 .. blocks) 162 { 163 ushort X1 = loadBigEndian!ushort(input, 0); 164 ushort X2 = loadBigEndian!ushort(input, 1); 165 ushort X3 = loadBigEndian!ushort(input, 2); 166 ushort X4 = loadBigEndian!ushort(input, 3); 167 168 foreach (size_t j; 0 .. 8) 169 { 170 X1 = mul(X1, K[6*j+0]); 171 X2 += K[6*j+1]; 172 X3 += K[6*j+2]; 173 X4 = mul(X4, K[6*j+3]); 174 175 ushort T0 = X3; 176 X3 = mul(X3 ^ X1, K[6*j+4]); 177 178 ushort T1 = X2; 179 X2 = mul(cast(ushort) ((X2 ^ X4) + X3), K[6*j+5]); 180 X3 += X2; 181 182 X1 ^= X2; 183 X4 ^= X3; 184 X2 ^= T0; 185 X3 ^= T1; 186 } 187 188 X1 = mul(X1, K[48]); 189 X2 += K[50]; 190 X3 += K[49]; 191 X4 = mul(X4, K[51]); 192 193 storeBigEndian(output, X1, X3, X2, X4); 194 195 input += BLOCK_SIZE; 196 output += BLOCK_SIZE; 197 } 198 }