public void initializeKey(byte[] key)
        {
            int  i, j, len = key.Length;
            uint temp;

            Array.Copy(blowfish_pbox, 0, P, 0, 18);
            Array.Copy(blowfish_sbox, 0, S0, 0, 256);
            Array.Copy(blowfish_sbox, 256, S1, 0, 256);
            Array.Copy(blowfish_sbox, 512, S2, 0, 256);
            Array.Copy(blowfish_sbox, 768, S3, 0, 256);

            for (j = 0, i = 0; i < 16 + 2; i++)
            {
                temp = (((uint)(key[j]) << 24) |
                        ((uint)(key[(j + 1) % len]) << 16) |
                        ((uint)(key[(j + 2) % len]) << 8) |
                        ((uint)(key[(j + 3) % len])));
                P[i] = P[i] ^ temp;
                j    = (j + 4) % len;
            }

            byte[] LR = new byte[8];

            for (i = 0; i < 16 + 2; i += 2)
            {
                blockEncrypt(LR, 0, LR, 0);
                P[i]     = CipherUtil.GetIntBE(LR, 0);
                P[i + 1] = CipherUtil.GetIntBE(LR, 4);
            }

            for (j = 0; j < 256; j += 2)
            {
                blockEncrypt(LR, 0, LR, 0);
                S0[j]     = CipherUtil.GetIntBE(LR, 0);
                S0[j + 1] = CipherUtil.GetIntBE(LR, 4);
            }
            for (j = 0; j < 256; j += 2)
            {
                blockEncrypt(LR, 0, LR, 0);
                S1[j]     = CipherUtil.GetIntBE(LR, 0);
                S1[j + 1] = CipherUtil.GetIntBE(LR, 4);
            }
            for (j = 0; j < 256; j += 2)
            {
                blockEncrypt(LR, 0, LR, 0);
                S2[j]     = CipherUtil.GetIntBE(LR, 0);
                S2[j + 1] = CipherUtil.GetIntBE(LR, 4);
            }
            for (j = 0; j < 256; j += 2)
            {
                blockEncrypt(LR, 0, LR, 0);
                S3[j]     = CipherUtil.GetIntBE(LR, 0);
                S3[j + 1] = CipherUtil.GetIntBE(LR, 4);
            }
        }
        public void blockDecrypt(byte[] input, int inOffset, byte[] output, int outOffset)
        {
            uint L, R;

            L = CipherUtil.GetIntBE(input, inOffset);
            R = CipherUtil.GetIntBE(input, inOffset + 4);

            L ^= P[17];
            R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
                    S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[16]);
            L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
                    S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[15]);
            R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
                    S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[14]);
            L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
                    S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[13]);
            R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
                    S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[12]);
            L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
                    S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[11]);
            R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
                    S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[10]);
            L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
                    S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[9]);
            R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
                    S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[8]);
            L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
                    S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[7]);
            R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
                    S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[6]);
            L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
                    S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[5]);
            R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
                    S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[4]);
            L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
                    S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[3]);
            R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
                    S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[2]);
            L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
                    S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[1]);
            R ^= P[0];

            CipherUtil.PutIntBE(R, output, outOffset);
            CipherUtil.PutIntBE(L, output, outOffset + 4);
        }