/// <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 + " ***]")); }
/// <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))); }