< Summary

Information
Class: Renci.SshNet.Security.Cryptography.Ciphers.TwofishCipher
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Ciphers\TwofishCipher.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 280
Coverable lines: 280
Total lines: 519
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 44
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)0%100%
EncryptBlock(...)0%20%
DecryptBlock(...)0%20%
.cctor()100%10%
SetKey(...)0%150%
F32(...)0%50%
RS_MDS_Encode(...)100%10%
RS_rem(...)0%40%
LFSR1(...)0%20%
LFSR2(...)0%40%
Mx_X(...)100%10%
Mx_Y(...)100%10%
M_b0(...)100%10%
M_b1(...)100%10%
M_b2(...)100%10%
M_b3(...)100%10%
Fe32_0(...)100%10%
Fe32_3(...)100%10%
BytesTo32Bits(...)100%10%
Bits32ToBytes(...)100%10%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Ciphers\TwofishCipher.cs

#LineLine coverage
 1using System;
 2
 3namespace Renci.SshNet.Security.Cryptography.Ciphers
 4{
 5    /// <summary>
 6    /// Implements Twofish cipher algorithm.
 7    /// </summary>
 8    public sealed class TwofishCipher : BlockCipher
 9    {
 10        /**
 11         * Define the fixed p0/p1 permutations used in keyed S-box lookup.
 12         * By changing the following constant definitions, the S-boxes will
 13         * automatically Get changed in the Twofish engine.
 14         */
 15#pragma warning disable SA1310 // Field names should not contain underscore
 16        private const int P_00 = 1;
 17        private const int P_01 = 0;
 18        private const int P_02 = 0;
 19        private const int P_03 = P_01 ^ 1;
 20        private const int P_04 = 1;
 21
 22        private const int P_10 = 0;
 23        private const int P_11 = 0;
 24        private const int P_12 = 1;
 25        private const int P_13 = P_11 ^ 1;
 26        private const int P_14 = 0;
 27
 28        private const int P_20 = 1;
 29        private const int P_21 = 1;
 30        private const int P_22 = 0;
 31        private const int P_23 = P_21 ^ 1;
 32        private const int P_24 = 0;
 33
 34        private const int P_30 = 0;
 35        private const int P_31 = 1;
 36        private const int P_32 = 1;
 37        private const int P_33 = P_31 ^ 1;
 38        private const int P_34 = 1;
 39
 40        /* Primitive polynomial for GF(256) */
 41        private const int GF256_FDBK = 0x169;
 42        private const int GF256_FDBK_2 = GF256_FDBK / 2;
 43        private const int GF256_FDBK_4 = GF256_FDBK / 4;
 44
 45        private const int RS_GF_FDBK = 0x14D; // field generator
 46
 47        private const int ROUNDS = 16;
 48        private const int MAX_ROUNDS = 16;  // bytes = 128 bits
 49        private const int MAX_KEY_BITS = 256;
 50
 51        private const int INPUT_WHITEN = 0;
 52        private const int OUTPUT_WHITEN = INPUT_WHITEN + (16 / 4); // 4
 53        private const int ROUND_SUBKEYS = OUTPUT_WHITEN + (16 / 4); // 8
 54
 55        private const int TOTAL_SUBKEYS = ROUND_SUBKEYS + (2 * MAX_ROUNDS); // 40
 56
 57        private const int SK_STEP = 0x02020202;
 58        private const int SK_BUMP = 0x01010101;
 59        private const int SK_ROTL = 9;
 60#pragma warning restore SA1310 // Field names should not contain underscore
 61
 062        private readonly int[] _gMDS0 = new int[MAX_KEY_BITS];
 063        private readonly int[] _gMDS1 = new int[MAX_KEY_BITS];
 064        private readonly int[] _gMDS2 = new int[MAX_KEY_BITS];
 065        private readonly int[] _gMDS3 = new int[MAX_KEY_BITS];
 66
 67        private readonly int _k64Cnt;
 68
 69        /*
 70         * _gSubKeys[] and _gSBox[] are eventually used in the
 71         * encryption and decryption methods.
 72         */
 73        private int[] _gSubKeys;
 74        private int[] _gSBox;
 75
 76        /// <summary>
 77        /// Initializes a new instance of the <see cref="TwofishCipher"/> class.
 78        /// </summary>
 79        /// <param name="key">The key.</param>
 80        /// <param name="mode">The mode.</param>
 81        /// <param name="padding">The padding.</param>
 82        /// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/>.</exception>
 83        /// <exception cref="ArgumentException">Keysize is not valid for this algorithm.</exception>
 84        public TwofishCipher(byte[] key, CipherMode mode, CipherPadding padding)
 085            : base(key, 16, mode, padding)
 086        {
 087            var keySize = key.Length * 8;
 88
 089            if (keySize is not (128 or 192 or 256))
 090            {
 091                throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
 92            }
 93
 94            // calculate the MDS matrix
 095            var m1 = new int[2];
 096            var mX = new int[2];
 097            var mY = new int[2];
 98
 099            for (var i = 0; i < MAX_KEY_BITS; i++)
 0100            {
 0101                var j = P[0 + i] & 0xff;
 0102                m1[0] = j;
 0103                mX[0] = Mx_X(j) & 0xff;
 0104                mY[0] = Mx_Y(j) & 0xff;
 105
 0106                j = P[(1 * 256) + i] & 0xff;
 0107                m1[1] = j;
 0108                mX[1] = Mx_X(j) & 0xff;
 0109                mY[1] = Mx_Y(j) & 0xff;
 110
 0111                _gMDS0[i] = m1[P_00] | mX[P_00] << 8 | mY[P_00] << 16 | mY[P_00] << 24;
 112
 0113                _gMDS1[i] = mY[P_10] | mY[P_10] << 8 | mX[P_10] << 16 | m1[P_10] << 24;
 114
 0115                _gMDS2[i] = mX[P_20] | mY[P_20] << 8 | m1[P_20] << 16 | mY[P_20] << 24;
 116
 0117                _gMDS3[i] = mX[P_30] | m1[P_30] << 8 | mY[P_30] << 16 | mX[P_30] << 24;
 0118            }
 119
 0120            _k64Cnt = key.Length / 8; // pre-padded ?
 0121            SetKey(key);
 0122        }
 123
 124        /// <summary>
 125        /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region 
 126        /// </summary>
 127        /// <param name="inputBuffer">The input data to encrypt.</param>
 128        /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 129        /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 130        /// <param name="outputBuffer">The output to which to write encrypted data.</param>
 131        /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 132        /// <returns>
 133        /// The number of bytes encrypted.
 134        /// </returns>
 135        public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int o
 0136        {
 0137            var x0 = BytesTo32Bits(inputBuffer, inputOffset) ^ _gSubKeys[INPUT_WHITEN];
 0138            var x1 = BytesTo32Bits(inputBuffer, inputOffset + 4) ^ _gSubKeys[INPUT_WHITEN + 1];
 0139            var x2 = BytesTo32Bits(inputBuffer, inputOffset + 8) ^ _gSubKeys[INPUT_WHITEN + 2];
 0140            var x3 = BytesTo32Bits(inputBuffer, inputOffset + 12) ^ _gSubKeys[INPUT_WHITEN + 3];
 141
 0142            var k = ROUND_SUBKEYS;
 0143            for (var r = 0; r < ROUNDS; r += 2)
 0144            {
 0145                var t0 = Fe32_0(_gSBox, x0);
 0146                var t1 = Fe32_3(_gSBox, x1);
 0147                x2 ^= t0 + t1 + _gSubKeys[k++];
 0148                x2 = (int)((uint)x2 >> 1) | x2 << 31;
 0149                x3 = (x3 << 1 | (int)((uint)x3 >> 31)) ^ (t0 + (2 * t1) + _gSubKeys[k++]);
 150
 0151                t0 = Fe32_0(_gSBox, x2);
 0152                t1 = Fe32_3(_gSBox, x3);
 0153                x0 ^= t0 + t1 + _gSubKeys[k++];
 0154                x0 = (int)((uint)x0 >> 1) | x0 << 31;
 0155                x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + (2 * t1) + _gSubKeys[k++]);
 0156            }
 157
 0158            Bits32ToBytes(x2 ^ _gSubKeys[OUTPUT_WHITEN], outputBuffer, outputOffset);
 0159            Bits32ToBytes(x3 ^ _gSubKeys[OUTPUT_WHITEN + 1], outputBuffer, outputOffset + 4);
 0160            Bits32ToBytes(x0 ^ _gSubKeys[OUTPUT_WHITEN + 2], outputBuffer, outputOffset + 8);
 0161            Bits32ToBytes(x1 ^ _gSubKeys[OUTPUT_WHITEN + 3], outputBuffer, outputOffset + 12);
 162
 0163            return BlockSize;
 0164        }
 165
 166        /// <summary>
 167        /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region 
 168        /// </summary>
 169        /// <param name="inputBuffer">The input data to decrypt.</param>
 170        /// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
 171        /// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
 172        /// <param name="outputBuffer">The output to which to write decrypted data.</param>
 173        /// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
 174        /// <returns>
 175        /// The number of bytes decrypted.
 176        /// </returns>
 177        public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int o
 0178        {
 0179            var x2 = BytesTo32Bits(inputBuffer, inputOffset) ^ _gSubKeys[OUTPUT_WHITEN];
 0180            var x3 = BytesTo32Bits(inputBuffer, inputOffset + 4) ^ _gSubKeys[OUTPUT_WHITEN + 1];
 0181            var x0 = BytesTo32Bits(inputBuffer, inputOffset + 8) ^ _gSubKeys[OUTPUT_WHITEN + 2];
 0182            var x1 = BytesTo32Bits(inputBuffer, inputOffset + 12) ^ _gSubKeys[OUTPUT_WHITEN + 3];
 183
 0184            var k = ROUND_SUBKEYS + (2 * ROUNDS) - 1;
 0185            for (var r = 0; r < ROUNDS; r += 2)
 0186            {
 0187                var t0 = Fe32_0(_gSBox, x2);
 0188                var t1 = Fe32_3(_gSBox, x3);
 0189                x1 ^= t0 + (2 * t1) + _gSubKeys[k--];
 0190                x0 = (x0 << 1 | (int) ((uint) x0 >> 31)) ^ (t0 + t1 + _gSubKeys[k--]);
 0191                x1 = (int) ((uint) x1 >> 1) | x1 << 31;
 192
 0193                t0 = Fe32_0(_gSBox, x0);
 0194                t1 = Fe32_3(_gSBox, x1);
 0195                x3 ^= t0 + (2 * t1) + _gSubKeys[k--];
 0196                x2 = (x2 << 1 | (int) ((uint) x2 >> 31)) ^ (t0 + t1 + _gSubKeys[k--]);
 0197                x3 = (int) ((uint) x3 >> 1) | x3 << 31;
 0198            }
 199
 0200            Bits32ToBytes(x0 ^ _gSubKeys[INPUT_WHITEN], outputBuffer, outputOffset);
 0201            Bits32ToBytes(x1 ^ _gSubKeys[INPUT_WHITEN + 1], outputBuffer, outputOffset + 4);
 0202            Bits32ToBytes(x2 ^ _gSubKeys[INPUT_WHITEN + 2], outputBuffer, outputOffset + 8);
 0203            Bits32ToBytes(x3 ^ _gSubKeys[INPUT_WHITEN + 3], outputBuffer, outputOffset + 12);
 204
 0205            return BlockSize;
 0206        }
 207
 0208        private static readonly byte[] P =
 0209            {
 0210                // p0
 0211                0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
 0212                0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
 0213                0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
 0214                0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
 0215                0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
 0216                0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
 0217                0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
 0218                0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
 0219                0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
 0220                0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
 0221                0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
 0222                0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
 0223                0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
 0224                0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
 0225                0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
 0226                0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0,
 0227
 0228                // p1
 0229                0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
 0230                0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
 0231                0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
 0232                0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
 0233                0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
 0234                0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
 0235                0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
 0236                0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
 0237                0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
 0238                0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
 0239                0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
 0240                0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
 0241                0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
 0242                0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
 0243                0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
 0244                0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
 0245            };
 246
 247        private void SetKey(byte[] key)
 0248        {
 0249            var k32e = new int[MAX_KEY_BITS / 64]; // 4
 0250            var k32o = new int[MAX_KEY_BITS / 64]; // 4
 251
 0252            var sBoxKeys = new int[MAX_KEY_BITS / 64]; // 4
 0253            _gSubKeys = new int[TOTAL_SUBKEYS];
 254
 0255            if (_k64Cnt < 1)
 0256            {
 0257                throw new ArgumentException("Key size less than 64 bits");
 258            }
 259
 0260            if (_k64Cnt > 4)
 0261            {
 0262                throw new ArgumentException("Key size larger than 256 bits");
 263            }
 264
 265            /*
 266            * k64Cnt is the number of 8 byte blocks (64 chunks)
 267            * that are in the input key.  The input key is a
 268            * maximum of 32 bytes ( 256 bits ), so the range
 269            * for k64Cnt is 1..4
 270            */
 0271            for (var i = 0; i < _k64Cnt; i++)
 0272            {
 0273                var p = i * 8;
 274
 0275                k32e[i] = BytesTo32Bits(key, p);
 0276                k32o[i] = BytesTo32Bits(key, p + 4);
 277
 0278                sBoxKeys[_k64Cnt - 1 - i] = RS_MDS_Encode(k32e[i], k32o[i]);
 0279            }
 280
 0281            for (var i = 0; i < TOTAL_SUBKEYS / 2; i++)
 0282            {
 0283                var q = i * SK_STEP;
 0284                var a = F32(q, k32e);
 0285                var b = F32(q + SK_BUMP, k32o);
 0286                b = b << 8 | (int)((uint)b >> 24);
 0287                a += b;
 0288                _gSubKeys[i * 2] = a;
 0289                a += b;
 0290                _gSubKeys[(i * 2) + 1] = a << SK_ROTL | (int)((uint)a >> (32 - SK_ROTL));
 0291            }
 292
 293            /*
 294            * fully expand the table for speed
 295            */
 0296            var k0 = sBoxKeys[0];
 0297            var k1 = sBoxKeys[1];
 0298            var k2 = sBoxKeys[2];
 0299            var k3 = sBoxKeys[3];
 0300            _gSBox = new int[4 * MAX_KEY_BITS];
 0301            for (var i = 0; i < MAX_KEY_BITS; i++)
 0302            {
 303                int b1, b2, b3;
 0304                var b0 = b1 = b2 = b3 = i;
 305
 306#pragma warning disable IDE0010 // Add missing cases
 0307                switch (_k64Cnt & 3)
 308                {
 309                    case 1:
 0310                        _gSBox[i * 2] = _gMDS0[(P[(P_01 * 256) + b0] & 0xff) ^ M_b0(k0)];
 0311                        _gSBox[(i * 2) + 1] = _gMDS1[(P[(P_11 * 256) + b1] & 0xff) ^ M_b1(k0)];
 0312                        _gSBox[(i * 2) + 0x200] = _gMDS2[(P[(P_21 * 256) + b2] & 0xff) ^ M_b2(k0)];
 0313                        _gSBox[(i * 2) + 0x201] = _gMDS3[(P[(P_31 * 256) + b3] & 0xff) ^ M_b3(k0)];
 0314                        break;
 315                    case 0: /* 256 bits of key */
 0316                        b0 = (P[(P_04 * 256) + b0] & 0xff) ^ M_b0(k3);
 0317                        b1 = (P[(P_14 * 256) + b1] & 0xff) ^ M_b1(k3);
 0318                        b2 = (P[(P_24 * 256) + b2] & 0xff) ^ M_b2(k3);
 0319                        b3 = (P[(P_34 * 256) + b3] & 0xff) ^ M_b3(k3);
 0320                        goto case 3;
 321                    case 3:
 0322                        b0 = (P[(P_03 * 256) + b0] & 0xff) ^ M_b0(k2);
 0323                        b1 = (P[(P_13 * 256) + b1] & 0xff) ^ M_b1(k2);
 0324                        b2 = (P[(P_23 * 256) + b2] & 0xff) ^ M_b2(k2);
 0325                        b3 = (P[(P_33 * 256) + b3] & 0xff) ^ M_b3(k2);
 0326                        goto case 2;
 327                    case 2:
 0328                        _gSBox[i * 2] = _gMDS0[(P[(P_01 * 256) + (P[(P_02 * 256) + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b
 0329                        _gSBox[(i * 2) + 1] = _gMDS1[(P[(P_11 * 256) + (P[(P_12 * 256) + b1] & 0xff) ^ M_b1(k1)] & 0xff)
 0330                        _gSBox[(i * 2) + 0x200] = _gMDS2[(P[(P_21 * 256) + (P[(P_22 * 256) + b2] & 0xff) ^ M_b2(k1)] & 0
 0331                        _gSBox[(i * 2) + 0x201] = _gMDS3[(P[(P_31 * 256) + (P[(P_32 * 256) + b3] & 0xff) ^ M_b3(k1)] & 0
 0332                        break;
 333                }
 334#pragma warning restore IDE0010 // Add missing cases
 0335            }
 336
 337            /*
 338            * the function exits having setup the gSBox with the
 339            * input key material.
 340            */
 0341        }
 342
 343        /*
 344        * TODO:  This can be optimised and made cleaner by combining
 345        * the functionality in this function and applying it appropriately
 346        * to the creation of the subkeys during key setup.
 347        */
 348        private int F32(int x, int[] k32)
 0349        {
 0350            var b0 = M_b0(x);
 0351            var b1 = M_b1(x);
 0352            var b2 = M_b2(x);
 0353            var b3 = M_b3(x);
 0354            var k0 = k32[0];
 0355            var k1 = k32[1];
 0356            var k2 = k32[2];
 0357            var k3 = k32[3];
 358
 0359            var result = 0;
 360
 361#pragma warning disable IDE0010 // Add missing cases
 0362            switch (_k64Cnt & 3)
 363            {
 364                case 1:
 0365                    result = _gMDS0[(P[(P_01 * 256) + b0] & 0xff) ^ M_b0(k0)] ^
 0366                             _gMDS1[(P[(P_11 * 256) + b1] & 0xff) ^ M_b1(k0)] ^
 0367                             _gMDS2[(P[(P_21 * 256) + b2] & 0xff) ^ M_b2(k0)] ^
 0368                             _gMDS3[(P[(P_31 * 256) + b3] & 0xff) ^ M_b3(k0)];
 0369                    break;
 370                case 0: /* 256 bits of key */
 0371                    b0 = (P[(P_04 * 256) + b0] & 0xff) ^ M_b0(k3);
 0372                    b1 = (P[(P_14 * 256) + b1] & 0xff) ^ M_b1(k3);
 0373                    b2 = (P[(P_24 * 256) + b2] & 0xff) ^ M_b2(k3);
 0374                    b3 = (P[(P_34 * 256) + b3] & 0xff) ^ M_b3(k3);
 0375                    goto case 3;
 376                case 3:
 0377                    b0 = (P[(P_03 * 256) + b0] & 0xff) ^ M_b0(k2);
 0378                    b1 = (P[(P_13 * 256) + b1] & 0xff) ^ M_b1(k2);
 0379                    b2 = (P[(P_23 * 256) + b2] & 0xff) ^ M_b2(k2);
 0380                    b3 = (P[(P_33 * 256) + b3] & 0xff) ^ M_b3(k2);
 0381                    goto case 2;
 382                case 2:
 0383                    result =
 0384                    _gMDS0[(P[(P_01 * 256) + (P[(P_02 * 256) + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)] ^
 0385                    _gMDS1[(P[(P_11 * 256) + (P[(P_12 * 256) + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)] ^
 0386                    _gMDS2[(P[(P_21 * 256) + (P[(P_22 * 256) + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)] ^
 0387                    _gMDS3[(P[(P_31 * 256) + (P[(P_32 * 256) + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)];
 0388                    break;
 389            }
 390#pragma warning restore IDE0010 // Add missing cases
 391
 0392            return result;
 0393        }
 394
 395        /**
 396        * Use (12, 8) Reed-Solomon code over GF(256) to produce
 397        * a key S-box 32-bit entity from 2 key material 32-bit
 398        * entities.
 399        *
 400        * @param    k0 first 32-bit entity
 401        * @param    k1 second 32-bit entity
 402        * @return     Remainder polynomial Generated using RS code
 403        */
 404        private static int RS_MDS_Encode(int k0, int k1)
 0405        {
 0406            var r = k1;
 407
 408            // shift 1 byte at a time
 0409            r = RS_rem(r);
 0410            r = RS_rem(r);
 0411            r = RS_rem(r);
 0412            r = RS_rem(r);
 0413            r ^= k0;
 0414            r = RS_rem(r);
 0415            r = RS_rem(r);
 0416            r = RS_rem(r);
 0417            r = RS_rem(r);
 418
 0419            return r;
 0420        }
 421
 422        /**
 423        * Reed-Solomon code parameters: (12,8) reversible code:
 424        * <p>
 425        * <pre>
 426        * G(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
 427        * </pre>
 428        * where a = primitive root of field generator 0x14D.
 429        * </p>
 430        */
 431        private static int RS_rem(int x)
 0432        {
 0433            var b = (int) (((uint) x >> 24) & 0xff);
 0434            var g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
 0435            var g3 = ((int) ((uint) b >> 1) ^ ((b & 0x01) != 0 ? (int) ((uint) RS_GF_FDBK >> 1) : 0)) ^ g2;
 0436            return (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b;
 0437        }
 438
 439        private static int LFSR1(int x)
 0440        {
 0441            return (x >> 1) ^ (((x & 0x01) != 0) ? GF256_FDBK_2 : 0);
 0442        }
 443
 444        private static int LFSR2(int x)
 0445        {
 0446            return (x >> 2) ^ (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^ (((x & 0x01) != 0) ? GF256_FDBK_4 : 0);
 0447        }
 448
 449        private static int Mx_X(int x)
 0450        {
 0451            return x ^ LFSR2(x);
 0452        } // 5B
 453
 454        private static int Mx_Y(int x)
 0455        {
 0456            return x ^ LFSR1(x) ^ LFSR2(x);
 0457        } // EF
 458
 459#pragma warning disable IDE1006 // Naming Styles
 460        private static int M_b0(int x)
 461#pragma warning restore IDE1006 // Naming Styles
 0462        {
 0463            return x & 0xff;
 0464        }
 465
 466#pragma warning disable IDE1006 // Naming Styles
 467        private static int M_b1(int x)
 468#pragma warning restore IDE1006 // Naming Styles
 0469        {
 0470            return (int)((uint)x >> 8) & 0xff;
 0471        }
 472
 473#pragma warning disable IDE1006 // Naming Styles
 474        private static int M_b2(int x)
 475#pragma warning restore IDE1006 // Naming Styles
 0476        {
 0477            return (int)((uint)x >> 16) & 0xff;
 0478        }
 479
 480#pragma warning disable IDE1006 // Naming Styles
 481        private static int M_b3(int x)
 482#pragma warning restore IDE1006 // Naming Styles
 0483        {
 0484            return (int)((uint)x >> 24) & 0xff;
 0485        }
 486
 487        private static int Fe32_0(int[] gSBox1, int x)
 0488        {
 0489            return gSBox1[0x000 + (2 * (x & 0xff))] ^
 0490                   gSBox1[0x001 + (2 * ((int)((uint)x >> 8) & 0xff))] ^
 0491                   gSBox1[0x200 + (2 * ((int)((uint)x >> 16) & 0xff))] ^
 0492                   gSBox1[0x201 + (2 * ((int)((uint)x >> 24) & 0xff))];
 0493        }
 494
 495        private static int Fe32_3(int[] gSBox1, int x)
 0496        {
 0497            return gSBox1[0x000 + (2 * ((int) ((uint) x >> 24) & 0xff))] ^
 0498                   gSBox1[0x001 + (2 * (x & 0xff))] ^
 0499                   gSBox1[0x200 + (2 * ((int)((uint)x >> 8) & 0xff))] ^
 0500                   gSBox1[0x201 + (2 * ((int)((uint)x >> 16) & 0xff))];
 0501        }
 502
 503        private static int BytesTo32Bits(byte[] b, int p)
 0504        {
 0505            return (b[p] & 0xff) |
 0506                ((b[p + 1] & 0xff) << 8) |
 0507                ((b[p + 2] & 0xff) << 16) |
 0508                ((b[p + 3] & 0xff) << 24);
 0509        }
 510
 511        private static void Bits32ToBytes(int inData, byte[] b, int offset)
 0512        {
 0513            b[offset] = (byte)inData;
 0514            b[offset + 1] = (byte)(inData >> 8);
 0515            b[offset + 2] = (byte)(inData >> 16);
 0516            b[offset + 3] = (byte)(inData >> 24);
 0517        }
 518    }
 519}