public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { Validate.AnArray(inputBuffer, inputOffset, inputCount); // Extract the MAC and ciphered from the input byte[] macMessageAONT = new byte[moMAC.HashSize / 8]; byte[] messageAONT = new byte[inputCount - macMessageAONT.Length]; Buffer.BlockCopy(inputBuffer, inputOffset, macMessageAONT, 0, macMessageAONT.Length); Buffer.BlockCopy(inputBuffer, inputOffset + macMessageAONT.Length, messageAONT, 0, messageAONT.Length); // Decrypt the head of the AONT message byte[] plaintextHeadOfMessageAONT = moCipher.CreateDecryptor().TransformFinalBlock(messageAONT, 0, mKey.Length); // Replace the encrypted head with the plaintext head Buffer.BlockCopy(plaintextHeadOfMessageAONT, 0, messageAONT, 0, plaintextHeadOfMessageAONT.Length); // Verify the MAC of the AONT message byte[] calcMacMessageAONT = moMAC.ComputeHash(messageAONT); if (!calcMacMessageAONT.SequenceEqual(macMessageAONT)) { // Throw not authenticated exception throw new Exception("Authentication check failed"); } // Inverse the AONT of the AONT message byte[] plaintext = moAONT.Decode(messageAONT, 0, messageAONT.Length); return(plaintext); }
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { #region Validation Validate.AnArray(inputBuffer, inputOffset, inputCount); #endregion // Check the ciphertext is large enough, Encrypt-then-MAC sig + MAC bits + at least 2 * miTotalPairsCount bytes if (moMAC.HashSize / 8 + 2 * (miTotalPairsCount / 8) + (2 * miTotalPairsCount) > inputCount) { // TODO throw new Exception("Ciphertext too short"); } // Extract the Encrypt-then-MAC signature byte[] EtM = new byte[moMAC.HashSize / 8]; Buffer.BlockCopy(inputBuffer, inputOffset, EtM, 0, EtM.Length); // Calculate the Encrypt-then-MAC signature byte[] calcEtM = moMAC.ComputeHash(inputBuffer, inputOffset + EtM.Length, inputCount - EtM.Length); // Compare if (!calcEtM.SequenceEqual(EtM)) { // Throw not authenticated exception throw new Exception("Authentication check failed"); } // Extract the HMAC seed byte[] seedMAC = new byte[miTotalPairsCount / 8]; Buffer.BlockCopy(inputBuffer, inputOffset + EtM.Length, seedMAC, 0, seedMAC.Length); // Extract the MAC bits byte[] bitsMAC = new byte[miTotalPairsCount / 8]; Buffer.BlockCopy(inputBuffer, inputOffset + EtM.Length + seedMAC.Length, bitsMAC, 0, bitsMAC.Length); // Allocate space for the encodedMessage byte[] encodedMessage = new byte[inputCount - EtM.Length - seedMAC.Length - bitsMAC.Length]; // If the encodedMessage is odd in length copy the last byte from the ciphertext to the encodedMessage int encodedMessageLength = encodedMessage.Length; if (encodedMessage.Length % 2 != 0) { encodedMessage[encodedMessage.Length - 1] = inputBuffer[inputOffset + (inputCount - 1)]; encodedMessageLength = encodedMessage.Length - 1; } // Determine the size of each message part (except for perhaps the last int partSize = getMaxPartSize(encodedMessageLength, 2 * miTotalPairsCount); // 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); int offset = 0; // Offset into the where we are writing the unswapped encoded message int encodedMsgOffset = inputOffset + EtM.Length + seedMAC.Length + bitsMAC.Length; // Offset into inputBuffer to read the swapped encoded message for (int i = 0; i < miTotalPairsCount; i++) { bufferHMAC[seedMAC.Length] = (byte)i; // Calculate the MAC of the 2 parts, unswapped and swapped // 1st unswapped Buffer.BlockCopy(inputBuffer, encodedMsgOffset, bufferHMAC, seedMAC.Length + 1, 2 * partSize); byte[] oMACUnswapped = moMAC.ComputeHash(bufferHMAC); // then swapped Buffer.BlockCopy(inputBuffer, encodedMsgOffset, bufferHMAC, seedMAC.Length + 1 + partSize, partSize); Buffer.BlockCopy(inputBuffer, encodedMsgOffset + partSize, bufferHMAC, seedMAC.Length + 1, partSize); byte[] oMACSwapped = moMAC.ComputeHash(bufferHMAC); // Find the location of the first bit difference bool bFound = false; byte[] correctPair = new byte[2 * partSize]; 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) { // Get the value of the bit byte bitValue = (byte)((bitsMAC[i / 8] >> (7 - (i % 8))) & 1); if ((bitValue == 1) == bUnSwappedBitSet) { Buffer.BlockCopy(inputBuffer, encodedMsgOffset, correctPair, 0, 2 * partSize); } else if ((bitValue == 1) == bSwappedBitSet) { Buffer.BlockCopy(inputBuffer, encodedMsgOffset + partSize, correctPair, 0, partSize); Buffer.BlockCopy(inputBuffer, encodedMsgOffset, correctPair, partSize, partSize); } bFound = true; break; } } } if (bFound) { break; } } if (!bFound) { // Likely the parts are identical, so swapping then and calculating the hash yields the same hash. // Just set the unswapped version Buffer.BlockCopy(inputBuffer, encodedMsgOffset, correctPair, 0, 2 * partSize); } // Copy to correctly ordered pair to the encoded message Buffer.BlockCopy(correctPair, 0, encodedMessage, offset, 2 * partSize); offset += (2 * partSize); encodedMsgOffset += (2 * partSize); partSize = getNextPartSize(encodedMessageLength, offset, (i + 1) * 2, 256); // 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]; } } // Reverse All Or Nothing Transform the message byte[] paddedMessage = moAONT.Decode(encodedMessage); //string hex = BitConverter.ToString(encodedMessage); //Console.WriteLine("Deco Message: " + hex.Replace("-", "") + " (length = " + encodedMessage.Length + ")"); // Remove padding int paddingBytes = paddedMessage[paddedMessage.Length - 1]; // Check all the padding bytes are correct for (int i = 0; i < paddingBytes; i++) { if (paddedMessage[paddedMessage.Length - 1 - i] != paddingBytes) { throw new Exception("Padding error found"); } } byte[] message = new byte[paddedMessage.Length - paddingBytes]; Buffer.BlockCopy(paddedMessage, 0, message, 0, message.Length); return(message); }