Exemplo n.º 1
0
        public static byte[] ApplyPadding(PaddingMode mode, byte[] bytes, int blockSizeInBytes)
        {
            int paddingBytesNeeded = GetPaddingBytesNeeded(mode, bytes.Length, blockSizeInBytes);

            if (paddingBytesNeeded == 0)
            {
                // sanity check
                return(ByteUtilities.Clone(bytes));
            }

            byte[] output = new byte[blockSizeInBytes];
            Buffer.BlockCopy(bytes, 0, output, 0, bytes.Length);

            switch (mode)
            {
            case PaddingMode.ANSIX923:
                ApplyAnsiX923Padding(output, paddingBytesNeeded);
                break;

            case PaddingMode.ISO10126:
                ApplyIso10126Padding(output, paddingBytesNeeded);
                break;

            case PaddingMode.PKCS7:
                ApplyPkcs7Padding(output, paddingBytesNeeded);
                break;

            case PaddingMode.Zeros:
                // nop
                break;

            default:
                throw new NotImplementedException("Padding mode not implemented");
            }

            return(output);
        }
Exemplo n.º 2
0
        private static void ShowRijndaelBookTestVectors()
        {
            WriteHeader("Rijndael Book Test");
            Console.WriteLine("Here are the test vectors from Appendix D of \"The Design of Rijndael\" book.");
            Console.WriteLine("(Note how there are more variants than AES allows)");
            Console.WriteLine();
            for (int keyLength = 128; keyLength <= 256; keyLength += 32)
            {
                for (int blockLength = 128; blockLength <= 256; blockLength += 32)
                {
                    Console.WriteLine("block length {0}  key length {1}", blockLength, keyLength);
                    byte[] blockBytes = new byte[blockLength / Constants.BitsPerByte];
                    byte[] keyBytes   = new byte[keyLength / Constants.BitsPerByte];

                    var encrypted = Rijndael.Encrypt(blockBytes, keyBytes);
                    ByteUtilities.WriteBytes(encrypted);
                    var decrypted = Rijndael.Decrypt(encrypted, keyBytes);

                    for (int i = 0; i < decrypted.Length; i++)
                    {
                        if (decrypted[i] != 0)
                        {
                            throw new CryptographicException("The decrypted Rijndael book values were not all zero.");
                        }
                    }

                    var encryptedAgain = Rijndael.Encrypt(encrypted, keyBytes);
                    ByteUtilities.WriteBytes(encryptedAgain);

                    var decryptedAgain = Rijndael.Decrypt(encryptedAgain, keyBytes);
                    ByteUtilities.AssertBytesEqual(decryptedAgain, encrypted);
                    Console.WriteLine();
                }
            }
            Console.WriteLine();
        }
        private static void PerformRandomizedTest(CipherMode mode, PaddingMode padding, int keySize)
        {
            var aesCapi = new AesCryptoServiceProvider();

            aesCapi.Mode    = mode;
            aesCapi.Padding = padding;

            aesCapi.Key = ByteUtilities.GetCryptographicallyRandomBytes(keySize / Constants.BitsPerByte);
            aesCapi.IV  = ByteUtilities.GetCryptographicallyRandomBytes(128 / Constants.BitsPerByte);
            var capiEncryptionTransform = aesCapi.CreateEncryptor();

            var ours = new Rijndael(aesCapi.Key);
            var ourEncryptionTransform = ours.CreateEncryptor(aesCapi.Mode, aesCapi.IV, aesCapi.FeedbackSize,
                                                              aesCapi.Padding);

            byte[] encryptedResult = PerformRandomizedTest(capiEncryptionTransform, ourEncryptionTransform, null);

            var capiDecryptionTransform = aesCapi.CreateDecryptor();
            var ourDecryptionTransform  = ours.CreateDecryptor(aesCapi.Mode, aesCapi.IV, aesCapi.FeedbackSize,
                                                               aesCapi.Padding);

            byte[] decryptedResult = PerformRandomizedTest(capiDecryptionTransform, ourDecryptionTransform,
                                                           encryptedResult);
        }
Exemplo n.º 4
0
        private static void ShowExamplesOfRijndaelMath()
        {
            WriteHeader("Rijndael Math");
            string m = "x^8 + " + ByteUtilities.ToPolynomial(0x1B);

            Console.WriteLine("Rijndael involves math in a finite field modulo m(x) = {0} where bytes are treated as polynomials", m);
            Console.WriteLine();
            Console.WriteLine("Some examples:");

            const byte left  = 0x1B;
            const byte right = 0xAA;

            Console.WriteLine("({0}) * ({1}) = {2:X2} * {3:X2}", left.ToPolynomial(), right.ToPolynomial(), left, right);

            byte logLeft     = FiniteFieldMath.Log(left);
            byte logRight    = FiniteFieldMath.Log(right);
            byte logAddition = (byte)(logLeft + logRight);

            Console.WriteLine("Log({0:X2}) + Log({1:X2}) = {2:X2} ^ {3:X2} = {4:X2}", left, right, logLeft, logRight, logAddition);
            Console.WriteLine("AntiLog({0:X2}) = Log^-1 ({0:X2}) = {1:X2}", logAddition, FiniteFieldMath.AntiLog(logAddition));
            Console.WriteLine("So {0:X2} * {1:X2} = {2:X2}", left, right, FiniteFieldMath.Multiply(left, right));
            Console.WriteLine();



            byte accumulator = 0x01;

            for (int i = 0; i < 0x10; i++)
            {
                const byte multiplier = 0x03;
                byte       newResult  = FiniteFieldMath.Multiply(accumulator, multiplier);
                Console.WriteLine(
                    "({0}) * ({1}) = {2} => {3:X2} * {4:X2} = {5:X2}",
                    multiplier.ToPolynomial(),
                    accumulator.ToPolynomial(),
                    newResult.ToPolynomial(),
                    multiplier,
                    accumulator,
                    newResult);
                accumulator = newResult;
            }

            Random weakRng = new Random();

            Console.WriteLine();
            Console.WriteLine("Rijndael's substitution box uses the \"g\" function that gives inverses in the field: g(a) = a^-1 mod m");
            Console.WriteLine();
            Console.WriteLine("Examples of a * g(a):");
            for (int i = 0; i < 5; i++)
            {
                byte currentByte = (byte)weakRng.Next(2, 256);
                byte inverseByte = FiniteFieldMath.G(currentByte);
                byte resultByte  = FiniteFieldMath.Multiply(currentByte, inverseByte);

                Console.WriteLine(
                    "({0}) * ({1}) = {2} => {3:X2} * {4:X2} = {5:X2}",
                    currentByte.ToPolynomial(),
                    inverseByte.ToPolynomial(),
                    resultByte.ToPolynomial(),
                    currentByte,
                    inverseByte,
                    resultByte);
            }

            Console.WriteLine();
            Console.WriteLine("The actual s-box values is f(g(a)) where \"f\" is an affine transform");
            Console.WriteLine();
            Console.WriteLine("Some examples:");
            for (int i = 0; i < 5; i++)
            {
                byte currentByte = (byte)weakRng.Next(2, 256);
                byte resultByte  = FiniteFieldMath.F(FiniteFieldMath.G(currentByte));

                Console.WriteLine("f(g({0:X2})) = {1:X2}", currentByte, resultByte);
            }
        }
Exemplo n.º 5
0
 public Rijndael()
     : this(ByteUtilities.GetCryptographicallyRandomBytes(256 / Constants.BitsPerByte))
 {
 }
Exemplo n.º 6
0
        /// <summary>
        /// Updates the key schedule with a new key and plaintext block size count.
        /// </summary>
        /// <param name="key">The key to derive round keys from.</param>
        /// <param name="plaintextBlockSizeInBytes">The intended plaintext block size.</param>
        private void Rekey(byte[] key, int plaintextBlockSizeInBytes)
        {
            _Key = key;

            int keyColumns = key.Length / Constants.StateRows;

            if (keyColumns < Constants.MinKeySizeColumns)
            {
                throw new ArgumentException("Key must be at least 128 bits", "key");
            }

            if ((key.Length % Constants.StateRows) != 0)
            {
                throw new ArgumentException("Key must be a multiple of 32 bits", "key");
            }

            ByteMatrix keyMatrix = new ByteMatrix(Constants.StateRows, key);

            int plaintextBlockSizeColumns = plaintextBlockSizeInBytes / Constants.StateRows;
            int numberOfRounds            = Constants.GetRounds(keyMatrix.Columns, plaintextBlockSizeColumns);

            // There are Nr rounds, so Nb * (Nr + 1) round keys where Nr is the number of rounds (plus the initial round)
            // and Nb is the size of the block in columns.
            ByteMatrix allRoundKeys = new ByteMatrix(Constants.StateRows, plaintextBlockSizeColumns * (numberOfRounds + 1));

            // The initial round key (#0) is the key itself
            for (int col = 0; col < keyMatrix.Columns; col++)
            {
                for (int row = 0; row < Constants.StateRows; row++)
                {
                    allRoundKeys[row, col] = keyMatrix[row, col];
                }
            }

            ByteMatrix[] roundKeys = new ByteMatrix[numberOfRounds + 1];

            // 30 round constants are enough for a 256 bit block and a 256 bit key
            byte[] roundConstants = Constants.GetRoundConstants(30);

            // The basic idea for the round keys is that you start with the initial round key
            // and then when you go to generate the next round key, you take the last column
            // of the previous round key and move it up by one byte (the previous top byte goes
            // to the bottom). Then you put each of the bytes of that column through the S-box.
            // Then you XOR the new top byte with the round key. Finally, you xor the whole column
            // with the column Nb columns earlier.

            // The other columns are made by xor-ing the previous column with the column Nb columns
            // earlier.

            // Say you have a key like this

            // | S |   |   |   |
            // | O | 1 | B | K |
            // | M | 2 | I | E |
            // | E | 8 | T | Y |

            // Taking the last column gives us:
            //
            // |   |
            // | K |
            // | E |
            // | Y |

            // Bumping it up and then moving the top to the bottom and then putting it
            // through the s-box gives us:

            // | K | = | 53 | => | S-Box | => | B3 |
            // | E | = | 45 | => | S-Box | => | 6E |
            // | Y | = | 59 | => | S-Box | => | CB |
            // |   | = | 20 | => | S-Box | => | B7 |

            // Adding in the first round constant gives us:

            // | B3 | ⊕ | 01 | => | B2 |
            // | 6E | ⊕ | 00 | => | 6E |
            // | CB | ⊕ | 00 | => | CB |
            // | B7 | ⊕ | 00 | => | B7 |

            // Now, we xor that with the column from 4 columns ago (e.g. the first column of the
            // initial round key)

            // | S | = | 53 | ⊕ | B2 | = | E1 |
            // | O | = | 4F | ⊕ | 6E | = | 21 |
            // | M | = | 4D | ⊕ | CB | = | 86 |
            // | E | = | 45 | ⊕ | B7 | = | F2 |

            // This means the first column of the next round key is:
            // | E1 |
            // | 21 |
            // | 86 |
            // | F2 |

            // Now, to calculate the next column, we just xor the previous column with the
            // one from 4 columns ago:

            // |   | = | 20 | ⊕ | E1 | = | C1 |
            // | 1 | = | 31 | ⊕ | 21 | = | 10 |
            // | 2 | = | 32 | ⊕ | 86 | = | B4 |
            // | 8 | = | 38 | ⊕ | F2 | = | CA |

            // So the second column is
            // | C1 |
            // | 10 |
            // | B4 |
            // | CA |

            // The third and fourth column are computed similarly. The next round key starts
            // the process over again with a new round key (02) and the process continues until
            // all round keys are made.

            // (Note: For keys bigger than 192 bits, you put every 4th column through the s-box first.)

            for (int col = keyMatrix.Columns; col < allRoundKeys.Columns; col++)
            {
                if ((col % keyMatrix.Columns) == 0)
                {
                    // Most of the work is when we're starting a new round key
                    byte roundConstant = roundConstants[col / keyMatrix.Columns];

                    // The upper left byte is xor'd with the round constant to prevent symmetry
                    allRoundKeys[0, col] =
                        (byte)
                        (allRoundKeys[0, col - keyMatrix.Columns] ^ SubstitutionBox.Value(allRoundKeys[1, col - 1]) ^ roundConstant);

                    for (int row = 1; row < Constants.StateRows; row++)
                    {
                        allRoundKeys[row, col] =
                            (byte)
                            (allRoundKeys[row, col - keyMatrix.Columns] ^
                             SubstitutionBox.Value(allRoundKeys[(row + 1) % Constants.StateRows, col - 1]));
                    }
                }
                else
                {
                    // Special case if we have bigger than a 192 bit key
                    if (((col % keyMatrix.Columns) == Constants.StateRows) && (keyMatrix.Columns > 6))
                    {
                        for (int row = 0; row < Constants.StateRows; row++)
                        {
                            allRoundKeys[row, col] =
                                (byte)
                                (allRoundKeys[row, col - keyMatrix.Columns] ^
                                 SubstitutionBox.Value(allRoundKeys[row, col - 1]));
                        }
                    }
                    else
                    {
                        for (int row = 0; row < Constants.StateRows; row++)
                        {
                            allRoundKeys[row, col] =
                                (byte)(allRoundKeys[row, col - keyMatrix.Columns] ^ allRoundKeys[row, col - 1]);
                        }
                    }
                }
            }

            // The actual round keys are just subsets of allRoundKeys (aka "W")
            for (int currentRoundKey = 0; currentRoundKey < roundKeys.Length; currentRoundKey++)
            {
                roundKeys[currentRoundKey] = allRoundKeys.SubMatrix(plaintextBlockSizeColumns * currentRoundKey,
                                                                    plaintextBlockSizeColumns);
            }

            _RoundKeys = roundKeys;

            if (Debugging.IsEnabled)
            {
                Debugging.Trace("Re-keyed Rijndael with {0}-bit key for {1} bit blocks. Key is:", key.Length * Constants.BitsPerByte, plaintextBlockSizeInBytes * Constants.BitsPerByte);
                ByteUtilities.WriteBytes(key);
                Debugging.Trace("");
                Debugging.Trace("There are {0} round keys.", _RoundKeys.Length);

                for (int i = 0; i < _RoundKeys.Length; i++)
                {
                    Debugging.Trace("Round key {0}:", i);
                    Debugging.Trace(_RoundKeys[i].ToString());
                }
            }
        }