C# IceKey
namespace IceKey { class IceKey { private int size; private int rounds; private uint[,] keySchedule; private static ulong[,] spBox = new ulong[4, 1024]; private static bool spBoxInitialised = false; private static uint[,] sMod =new uint[,] { {333, 313, 505, 369}, {379, 375, 319, 391}, {361, 445, 451, 397}, {397, 425, 395, 505}}; private static uint[,] sXor =new uint[,] { {0x83, 0x85, 0x9b, 0xcd}, {0xcc, 0xa7, 0xad, 0x41}, {0x4b, 0x2e, 0xd4, 0x33}, {0xea, 0xcb, 0x2e, 0x04}}; private static uint[] pBox =new uint[] { 0x00000001, 0x00000080, 0x00000400, 0x00002000, 0x00080000, 0x00200000, 0x01000000, 0x40000000, 0x00000008, 0x00000020, 0x00000100, 0x00004000, 0x00010000, 0x00800000, 0x04000000, 0x20000000, 0x00000004, 0x00000010, 0x00000200, 0x00008000, 0x00020000, 0x00400000, 0x08000000, 0x10000000, 0x00000002, 0x00000040, 0x00000800, 0x00001000, 0x00040000, 0x00100000, 0x02000000, 0x80000000}; private static int[] keyrot =new int[] { 0, 1, 2, 3, 2, 1, 3, 0, 1, 3, 2, 0, 3, 1, 0, 2}; private uint gf_mult(uint a, uint b, uint m) { uint res = 0; while (b != 0) { if ((b & 1) != 0) res ^= a; a <<= 1; b >>= 1; if (a >= 256) a ^= m; } return (res); } // 8-bit Galois Field exponentiation. // Raise the base to the power of 7, modulo m. private uint gf_exp7(uint b, uint m) { uint x; if (b == 0) return (0); x = gf_mult(b, b, m); x = gf_mult(b, x, m); x = gf_mult(x, x, m); return (gf_mult(b, x, m)); } // Carry out the ICE 32-bit permutation. private uint perm32(uint x) { uint res = 0; uint i = 0; while (x != 0) { if ((x & 1) != 0) res |= pBox[i]; i++; x >>= 1; } return (res); } // Initialise the substitution/permutation boxes. private void spBoxInit() { uint i; for (i = 0; i < 1024; i++) { uint col = (i >> 1) & 0xff; uint row = (i & 0x1) | ((i & 0x200) >> 8); uint x; x = gf_exp7(col ^ sXor[0,row], sMod[0,row]) << 24; spBox[0,i] = perm32(x); x = gf_exp7(col ^ sXor[1,row], sMod[1,row]) << 16; spBox[1,i] = perm32(x); x = gf_exp7(col ^ sXor[2,row], sMod[2,row]) << 8; spBox[2,i] = perm32(x); x = gf_exp7(col ^ sXor[3,row], sMod[3,row]); spBox[3,i] = perm32(x); } } // Create a new ICE key with the specified level. IceKey(int level) { if (!spBoxInitialised) { spBoxInit(); spBoxInitialised = true; } if (level < 1) { size = 1; rounds = 8; } else { size = level; rounds = level * 16; } keySchedule = new uint[rounds,3]; } // Set 8 rounds [n, n+7] of the key schedule of an ICE key. private void scheduleBuild(uint[] kb, int n, int krot_idx) { int i; for (i = 0; i < 8; i++) { uint j; int kr = keyrot[krot_idx + i]; ulong[] subkey = new ulong[keySchedule.GetLength(0)]; for(int k=0;k<keySchedule.GetLength(0);++k) { subkey[k] = keySchedule[n + i, k]; } for (j = 0; j < 3; j++) { keySchedule[n + i,j] = 0; } for (j = 0; j < 15; j++) { int k; uint curr_sk = j % 3; for (k = 0; k < 4; k++) { uint curr_kb = kb[(kr + k) & 3]; uint bit = curr_kb & 1; subkey[curr_sk] = (subkey[curr_sk] << 1) | bit; kb[(kr + k) & 3] = (curr_kb >> 1) | ((bit ^ 1) << 15); } } } } // Set the key schedule of an ICE key. public void set(uint[] key) { int i; uint[] kb = new uint[4]; if (rounds == 8) { for (i = 0; i < 4; i++) kb[3 - i] = ((key[i * 2] & 0xff) << 8) | (key[i * 2 + 1] & 0xff); scheduleBuild(kb, 0, 0); return; } for (i = 0; i < size; i++) { int j; for (j = 0; j < 4; j++) kb[3 - j] = ((key[i * 8 + j * 2] & 0xff) << 8) | (key[i * 8 + j * 2 + 1] & 0xff); scheduleBuild(kb, i * 8, 0); scheduleBuild(kb, rounds - 8 - i * 8, 8); } } // Clear the key schedule to prevent memory snooping. public void clear() { int i, j; for (i = 0; i < rounds; i++) for (j = 0; j < 3; j++) keySchedule[i,j] = 0; } // The single round ICE f function. private ulong roundFunc(ulong p, ulong[] subkey) { ulong tl, tr; ulong al, ar; tl = ((p >> 16) & 0x3ff) | (((p >> 14) | (p << 18)) & 0xffc00); tr = (p & 0x3ff) | ((p << 2) & 0xffc00); // al = (tr & subkey[2]) | (tl & ~subkey[2]); // ar = (tl & subkey[2]) | (tr & ~subkey[2]); al = subkey[2] & (tl ^ tr); ar = al ^ tr; al ^= tl; al ^= subkey[0]; ar ^= subkey[1]; return (spBox[0,al >> 10] | spBox[1,al & 0x3ff] | spBox[2,ar >> 10] | spBox[3,ar & 0x3ff]); } // Encrypt a block of 8 bytes of data. public void encrypt(byte[] plaintext, byte[] ciphertext) { int i; ulong l = 0, r = 0; for (i = 0; i < 4; i++) { l |= ((ulong)plaintext[i] & 0xff) << (24 - i * 8); r |= ((ulong)plaintext[i + 4] & 0xff) << (24 - i * 8); } for (i = 0; i < rounds; i += 2) { ulong[] subkey = new ulong[keySchedule.GetLength(0)]; for (int j = 0; j < keySchedule.GetLength(0); ++j) subkey[i] = keySchedule[i, j]; l ^= roundFunc(r, subkey); for (int j = 0; j < keySchedule.GetLength(0); ++j) subkey[i] = keySchedule[i+1, j]; r ^= roundFunc(l, subkey); } for (i = 0; i < 4; i++) { ciphertext[3 - i] = (byte)(r & 0xff); ciphertext[7 - i] = (byte)(l & 0xff); r >>= 8; l >>= 8; } } // Decrypt a block of 8 bytes of data. public void decrypt(byte[] ciphertext, byte[] plaintext) { int i; ulong l = 0, r = 0; for (i = 0; i < 4; i++) { l |= (ciphertext[i] & 0xffu) << (24 - i * 8); r |= (ciphertext[i + 4] & 0xffu) << (24 - i * 8); } for (i = rounds - 1; i > 0; i -= 2) { ulong[] subkey = new ulong[keySchedule.GetLength(0)]; for (int k = 0; k < keySchedule.GetLength(0); ++k) { subkey[k] = keySchedule[i, k]; } l ^= roundFunc(r, subkey); for (int k = 0; k < keySchedule.GetLength(0); ++k) { subkey[k] = keySchedule[i-1, k]; } r ^= roundFunc(l, subkey); } for (i = 0; i < 4; i++) { plaintext[3 - i] = (byte)(r & 0xff); plaintext[7 - i] = (byte)(l & 0xff); r >>= 8; l >>= 8; } } // Return the key size, in bytes. public int keySize() { return (size * 8); } // Return the block size, in bytes. public int blockSize() { return (8); } } }