public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
        {
            Validate.AnArray(inputBuffer, inputOffset, inputCount);

            // AONT the message
            byte[] messageAONT = moAONT.Encode(inputBuffer, inputOffset, inputCount);

            // Get MAC of the output of the AONT
            byte[] macMessageAONT = moMAC.ComputeHash(messageAONT);

            // Encrypt the head of the AONT message using the Symmetric Cipher
            moCipher.BlockSize = macMessageAONT.Length * 8;
            moCipher.IV        = macMessageAONT;
            byte[] cipheredHeadOfMessageAONT = moCipher.CreateEncryptor().TransformFinalBlock(messageAONT, 0, mKey.Length);
            // Replace the head of the AONT message with the encrypted head
            Buffer.BlockCopy(cipheredHeadOfMessageAONT, 0, messageAONT, 0, cipheredHeadOfMessageAONT.Length);

            // Copy the MAC and ciphered data to the ciphertext
            byte[] ciphertext = new byte[macMessageAONT.Length + messageAONT.Length];
            Buffer.BlockCopy(macMessageAONT, 0, ciphertext, 0, macMessageAONT.Length);
            Buffer.BlockCopy(messageAONT, 0, ciphertext, macMessageAONT.Length, messageAONT.Length);

            return(ciphertext);
        }
Esempio n. 2
0
        public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
        {
            #region Validation
            Validate.AnArray(inputBuffer, inputOffset, inputCount);
            #endregion

            // Set the padding to always be 1 byte
            byte[] padding = new byte[] { 1 };
            // Increase the padding if the input if AONT message length isn't enough to create 1 byte parts
            if (moAONT.outputLengthForInputLength(inputCount) < (2 * miTotalPairsCount))
            {
                int paddingBytes = (2 * miTotalPairsCount) - moAONT.outputLengthForInputLength(inputCount);
                if (paddingBytes > 255)
                {
                    throw new Exception("Unable to pad message as parameters have caused more than 255 padding bytes to be required");
                }
                padding = new byte[paddingBytes];
                for (int i = 0; i < paddingBytes; i++)
                {
                    padding[i] = (byte)paddingBytes;
                }
            }


            // If the message length is odd, then set a flag to copy the last byte of AONT(m) straight to the ciphertext
            bool bMsgLengthOdd = false;
            if ((inputCount + padding.Length) % 2 != 0)
            {
                bMsgLengthOdd = true;
            }

            // Copy the message + padding
            byte[] message = new byte[inputCount + padding.Length];
            Buffer.BlockCopy(inputBuffer, inputOffset, message, 0, inputCount);
            Buffer.BlockCopy(padding, 0, message, inputCount, padding.Length);

            // All Or Nothing Transform the message
            byte[] encodedMessage = moAONT.Encode(message);
            //string hex = BitConverter.ToString(encodedMessage);
            //Console.WriteLine("AONT Message: " + hex.Replace("-", "") + " (length = " + encodedMessage.Length + ")");

            // For an odd length message we will copy the last byte straight to the ciphertext, so for the purpose of processing we ignore this byte
            int encodedMessageLength = bMsgLengthOdd ? encodedMessage.Length - 1 : encodedMessage.Length;

            // Determine the size of each message part (except for perhaps the last
            int partSize = getMaxPartSize(encodedMessageLength, 2 * miTotalPairsCount);

            // Generate the MAC seed
            byte[] seedMAC = new byte[miTotalPairsCount / 8];
            (new RNGCryptoServiceProvider()).GetBytes(seedMAC);

            // Allocate space for a buffer to calculate the HMAC on
            byte[] bufferHMAC = new byte[seedMAC.Length + 1 + 2 * partSize];    // We will HMAC the HMAC seed, the index and the 2 parts

            // Copy the HMAC seed to the HMAC buffer
            Buffer.BlockCopy(seedMAC, 0, bufferHMAC, 0, seedMAC.Length);

            // Allocate space for the MAC bits
            byte[] bitsMAC = new byte[miTotalPairsCount / 8];

            // Allocate space for the ciphertext = Length of Encrypt-then MAC + HMAC seed + MAC bits + encoded message length
            byte[] ciphertext = new byte[moMAC.HashSize / 8 + seedMAC.Length + bitsMAC.Length + encodedMessageLength + (bMsgLengthOdd?1:0)];
            // For an odd length message copy the last encoded byte directly to the ciphertext
            if (bMsgLengthOdd)
            {
                ciphertext[ciphertext.Length - 1] = encodedMessage[encodedMessage.Length - 1];
            }

            // Note where to write the swapped parts
            int ciphertextOffset = moMAC.HashSize / 8 + seedMAC.Length + bitsMAC.Length;
            // Offset into the encodedMessage
            int offset = 0;

            for (int i = 0; i < miTotalPairsCount; i++)
            {
                bufferHMAC[seedMAC.Length] = (byte)i;
                // Make a copy of the 2 parts in the correct order
                Buffer.BlockCopy(encodedMessage, offset, bufferHMAC, seedMAC.Length + 1, 2 * partSize);
                // Calculate the MAC of the 2 parts in the correct order
                byte[] oMACUnswapped = moMAC.ComputeHash(bufferHMAC);
                // Make a copy of the 2 parts in the swapped order
                Buffer.BlockCopy(encodedMessage, offset + partSize, bufferHMAC, seedMAC.Length + 1, partSize);
                Buffer.BlockCopy(encodedMessage, offset, bufferHMAC, seedMAC.Length + 1 + partSize, partSize);
                // Calculate the MAC of the 2 parts in the swapped order
                byte[] oMACSwapped = moMAC.ComputeHash(bufferHMAC);

                // Find the location of the first bit difference of the MACs
                bool found = false;
                for (byte j = 0; j < oMACUnswapped.Length; j++)
                {
                    if (oMACSwapped[j] != oMACUnswapped[j])
                    {
                        for (byte k = 0; k < 8; k++)
                        {
                            Boolean bUnSwappedBitSet = ((oMACUnswapped[j] & ((byte)1 << k)) > 0);
                            Boolean bSwappedBitSet   = ((oMACSwapped[j] & ((byte)1 << k)) > 0);
                            if (bUnSwappedBitSet != bSwappedBitSet)
                            {
                                // Record the value of the bit from the unswapped MAC
                                byte bitValue = bUnSwappedBitSet ? (byte)1 : (byte)0;
                                bitsMAC[i / 8] |= (byte)(bitValue << (7 - (i % 8)));
                                found           = true;
                                break;
                            }
                        }
                    }
                    if (found)
                    {
                        break;
                    }
                }
                if (!found)
                {
                    // Either the parts were identical, or we found a hash collision(!).  We allow this case under the assumption that it won't happen
                    // very often and that although it reduces the overall security, it won't reduce it much.
                }

                // Copy to ciphertext
                Buffer.BlockCopy(moRandOrd.Swap(encodedMessage, offset, 2 * partSize), 0, ciphertext, ciphertextOffset, 2 * partSize);
                ciphertextOffset += (2 * partSize);

                offset += (2 * partSize);

                partSize = getNextPartSize(encodedMessageLength, offset, (i + 1) * 2, 2 * miTotalPairsCount);

                // If the partSize changes we need to alter the size of bufferHMAC
                if (bufferHMAC.Length != (seedMAC.Length + 1 + 2 * partSize))
                {
                    bufferHMAC = new byte[seedMAC.Length + 1 + 2 * partSize];
                }
            }

            // Prepend the HMAC seed
            Buffer.BlockCopy(seedMAC, 0, ciphertext, moMAC.HashSize / 8, seedMAC.Length);

            // Prepend the bits from the MACs
            Buffer.BlockCopy(bitsMAC, 0, ciphertext, moMAC.HashSize / 8 + seedMAC.Length, bitsMAC.Length);

            // Prepend Encrypt-then-MAC construction to the beginning of the ciphertext
            byte[] EtM = moMAC.ComputeHash(ciphertext, moMAC.HashSize / 8, ciphertext.Length - (moMAC.HashSize / 8));
            Buffer.BlockCopy(EtM, 0, ciphertext, 0, EtM.Length);

            return(ciphertext);
        }