C# IceKey Ver.I

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);
        }
    }
}

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注