public void ShiftLeftWrapped(BLOCK8BYTE s, int bitShift)
        {
            // this shift is only applied to the first 32 bits, and parity bit is ignored

            // Declaration of local variables
            int byteOffset;
            bool bit;

            // Copy byte and shift regardless
            for (byteOffset = 0; byteOffset < 4; byteOffset++)
                _data[byteOffset] = Convert.ToByte((s._data[byteOffset] << bitShift) & 0xFF);

            // if shifting by 1...
            if (bitShift == 1)
            {
                // repair bits on right of BYTE
                for (byteOffset = 0; byteOffset < 3; byteOffset++)
                {
                    // get repairing bit offsets
                    bit = s.GetBit(byteOffset + 1, 7);
                    this.SetBit(byteOffset, 1, bit);
                }
                // wrap around the final bit
                this.SetBit(3, 1, s.GetBit(0, 7));
            }
            else if (bitShift == 2)
            {
                // repair bits on right of BYTE
                for (byteOffset = 0; byteOffset < 3; byteOffset++)
                {
                    // get repairing bit offsets
                    bit = s.GetBit(byteOffset + 1, 7);
                    this.SetBit(byteOffset, 2, bit);
                    bit = s.GetBit(byteOffset + 1, 6);
                    this.SetBit(byteOffset, 1, bit);
                }
                // wrap around the final bit
                this.SetBit(3, 2, s.GetBit(0, 7));
                this.SetBit(3, 1, s.GetBit(0, 6));
            }
            else
                Debug.Assert(false);
        }
        protected KeySet ExpandKey(byte[] key, int offset)
        {
            //
            // Expand an 8 byte DES key into a set of permuted keys
            //

            // Declare return variable
            KeySet ftmp = new KeySet();

            // Declaration of local variables
            int arrayOffset, permOffset, byteOffset, bitOffset;
            bool bBit;

            // Put key into an 8-bit block
            BLOCK8BYTE k = new BLOCK8BYTE();
            k.Set(key, offset);

            // Permutate Kp with PC1
            BLOCK8BYTE kp = new BLOCK8BYTE();
            for (arrayOffset = 0; arrayOffset < DESTables.PC1.Length; arrayOffset++)
            {
                // Get permute offset
                permOffset = DESTables.PC1[arrayOffset];
                permOffset--;

                // Get and set bit
                kp.SetBit(
                    BitAddressToByteOffset(arrayOffset, 7),
                    BitAddressToBitOffset(arrayOffset, 7),
                    k.GetBit(
                        BitAddressToByteOffset(permOffset, 8),
                        BitAddressToBitOffset(permOffset, 8)
                    )
                );

            }

            // Create 17 blocks of C and D from Kp
            BLOCK8BYTE[] kpCn = new BLOCK8BYTE[17];
            BLOCK8BYTE[] kpDn = new BLOCK8BYTE[17];
            for (arrayOffset = 0; arrayOffset < 17; arrayOffset++)
            {
                kpCn[arrayOffset] = new BLOCK8BYTE();
                kpDn[arrayOffset] = new BLOCK8BYTE();
            }
            for (arrayOffset = 0; arrayOffset < 32; arrayOffset++)
            {
                // Set bit in KpCn
                byteOffset = BitAddressToByteOffset(arrayOffset, 8);
                bitOffset = BitAddressToBitOffset(arrayOffset, 8);
                bBit = kp.GetBit(byteOffset, bitOffset);
                kpCn[0].SetBit(byteOffset, bitOffset, bBit);

                // Set bit in KpDn
                bBit = kp.GetBit(byteOffset + 4, bitOffset);
                kpDn[0].SetBit(byteOffset, bitOffset, bBit);
            }
            for (arrayOffset = 1; arrayOffset < 17; arrayOffset++)
            {
                // Shift left wrapped
                kpCn[arrayOffset].ShiftLeftWrapped(kpCn[arrayOffset - 1], DESTables.Shifts[arrayOffset - 1]);
                kpDn[arrayOffset].ShiftLeftWrapped(kpDn[arrayOffset - 1], DESTables.Shifts[arrayOffset - 1]);
            }

            // Create 17 keys Kn
            for (arrayOffset = 0; arrayOffset < 17; arrayOffset++)
            {
                // Loop through the bits
                int tableOffset;
                for (tableOffset = 0; tableOffset < 48; tableOffset++)
                {
                    // Get address if bit
                    permOffset = DESTables.PC2[tableOffset];
                    permOffset--;

                    // Convert to byte and bit offsets
                    byteOffset = BitAddressToByteOffset(permOffset, 7);
                    bitOffset = BitAddressToBitOffset(permOffset, 7);

                    // Get bit
                    if (byteOffset < 4)
                        bBit = kpCn[arrayOffset].GetBit(byteOffset, bitOffset);
                    else
                        bBit = kpDn[arrayOffset].GetBit(byteOffset - 4, bitOffset);

                    // Set bit
                    byteOffset = BitAddressToByteOffset(tableOffset, 6);
                    bitOffset = BitAddressToBitOffset(tableOffset, 6);
                    ftmp.GetAt(arrayOffset).SetBit(byteOffset, bitOffset, bBit);
                }
            }
            return ftmp;
        }