/// <inheritdoc />
        protected override void FinishItem(PayloadItem item, CipherStream encryptor, MacStream authenticator)
        {
            if (Writing)
            {
                if (item.ExternalLength > 0 && encryptor.BytesIn != item.ExternalLength)
                {
                    throw new InvalidDataException("Length written is not equal to predefined item external length.");
                }
            }
            else
            {
                if (encryptor.BytesIn != item.InternalLength)
                {
                    throw new InvalidDataException("Length read is not equal to item internal length.");
                }
                if (encryptor.BytesOut != item.ExternalLength)
                {
                    throw new InvalidDataException("Demultiplexed and decrypted length is not equal to specified item external length.");
                }
                encryptor.Close();
            }

            if (Writing)
            {
                // Commit the determined internal length to item in payload manifest
                item.InternalLength = encryptor.BytesOut;
                EmitTrailer(authenticator);
            }
            else
            {
                ConsumeTrailer(authenticator);
            }

            // Final stages of Encrypt-then-MAC authentication scheme
            PayloadItem itemDto = item.CreateAuthenticatibleClone();

            byte[] itemDtoAuthBytes = itemDto.SerialiseDto();

            Debug.Print(DebugUtility.CreateReportString("FabricPayloadMux", "FinishItem", "Item DTO length",
                                                        itemDtoAuthBytes.Length));

            if (Writing)
            {
                authenticator.Update(itemDtoAuthBytes, 0, itemDtoAuthBytes.Length);
                authenticator.Close();
                // Commit the MAC to item in payload manifest
                item.AuthenticationVerifiedOutput = authenticator.Mac.DeepCopy();
            }
            else
            {
                authenticator.Update(itemDtoAuthBytes, 0, itemDtoAuthBytes.Length);
                authenticator.Close();
                // Verify the authenticity of the item ciphertext and configuration
                if (authenticator.Mac.SequenceEqual_ConstantTime(item.AuthenticationVerifiedOutput) == false)
                {
                    // Verification failed!
                    throw new CiphertextAuthenticationException("Payload item not authenticated.");
                }
            }


            // Release the item's resources (implicitly - no references remain)
            _activeItemResources.Remove(item.Identifier);

            // Mark the item as completed in the register
            ItemCompletionRegister[Index] = true;
            ItemsCompleted++;
            // Close the source/destination
            item.StreamBinding.Close();

            Debug.Print(DebugUtility.CreateReportString("FabricPayloadMux", "FinishItem", "[*** END OF ITEM",
                                                        Index + " ***]"));
        }
Exemple #2
0
        /// <summary>
        ///     Close the item decorator, check lengths, authenticate the item (emit or verify),
        ///     and if writing, commit the authentication value to the payload item DTO.
        /// </summary>
        /// <param name="item">Payload item to finish.</param>
        /// <param name="encryptor">Item encryptor/cipher.</param>
        /// <param name="authenticator">Item authenticator/MAC.</param>
        protected override void FinishItem(PayloadItem item, CipherStream encryptor, MacStream authenticator)
        {
            try {
                encryptor.Close();
            } catch (Exception e) {
                throw new Exception("Unknown error when finalising/closing cipher.", e);
            }

            try {
                if (Writing)
                {
                    EmitTrailer(authenticator);
                }
                else
                {
                    ConsumeTrailer(authenticator);
                }
            } catch (Exception e) {
                throw new Exception(String.Format("Unknown error when {0} item trailer.", Writing ? "emitting" : "consuming"), e);
            }

            // Length checks & commits
            if (Writing)
            {
                // Check if pre-stated length matches what was actually written
                if (item.ExternalLength > 0 && encryptor.BytesIn != item.ExternalLength)
                {
                    throw new InvalidDataException(
                              "Mismatch between stated item external length and actual input length.");
                }
                // Commit the determined internal length to item in payload manifest
                item.InternalLength = encryptor.BytesOut;
            }
            else
            {
                if (encryptor.BytesIn != item.InternalLength)
                {
                    throw new InvalidOperationException("Probable decorator stack malfunction.");
                }
                if (encryptor.BytesOut != item.ExternalLength)
                {
                    throw new InvalidDataException(
                              "Mismatch between stated item external length and actual output length.");
                }
            }

            // Final stages of Encrypt-then-MAC authentication scheme
            PayloadItem itemDto = item.CreateAuthenticatibleClone();

            byte[] itemDtoAuthBytes = itemDto.SerialiseDto();
#if PRINT_DTO_LENGTH
            Debug.Print(DebugUtility.CreateReportString("SimplePayloadMux", "FinishItem", "Payload item DTO length",
                                                        itemDtoAuthBytes.Length));
#endif
            authenticator.Update(itemDtoAuthBytes, 0, itemDtoAuthBytes.Length);
            authenticator.Close();

            // Authentication
            if (Writing)
            {
                // Commit the MAC to item in payload manifest
                item.AuthenticationVerifiedOutput = authenticator.Mac.DeepCopy();
            }
            else
            {
                // Verify the authenticity of the item ciphertext and configuration
                if (authenticator.Mac.SequenceEqual_ConstantTime(item.AuthenticationVerifiedOutput) == false)
                {
                    // Verification failed!
                    throw new CiphertextAuthenticationException("Payload item not authenticated.");
                }
            }

            // Close the source/destination
            item.StreamBinding.Close();

            // Mark the item as completed in the register
            ItemCompletionRegister[Index] = true;
            ItemsCompleted++;

            Debug.Print(DebugUtility.CreateReportString("SimplePayloadMux", "ExecuteOperation",
                                                        "[*** END OF ITEM", String.Format("{0} ({1}) ***]", Index, item.Identifier)));
        }