public Message(Stream input, RSAPrivateKey key, Converter <Guid, Salt> sessionSecret)
            {
                (_protected = new MemoryStream(0)).Dispose();
                _hash    = new HashStream(new SHA256Managed(), input);
                _payload = input;

                ReadHeader(_hash, out _version, out _state, out _transferId, out _salt);

                Salt secret;

                if (!UsesSessionKey)
                {
                    // Begin private key decryption
                    _payload = key.Decrypt(input);
                    _hash.ChangeStream(_payload);
                    // Decrypt the aes key used in this package
                    byte[] keybits = IOStream.Read(_hash, 32);
                    secret = Salt.FromBytes(keybits);
                }
                else
                {
                    secret = sessionSecret(_transferId);
                    Check.IsEqual(32, Check.NotNull(secret).Length);
                }

                AESCryptoKey sessionKey = new AESCryptoKey(
                    // Prefix the key with the message's salt and compute a SHA256 hash to be used as the key
                    Hash.SHA256(_salt.GetData(secret.ToArray()).ToStream()).ToArray(),
                    // Compute an IV for this aes key and salt combination
                    IV(secret, _salt)
                    );

                _payload = sessionKey.Decrypt(_payload);
                _hash.ChangeStream(_payload);
            }
            private static Salt SessionSecret(Salt clientKeyBits, byte[] serverKeyBits)
            {
                Salt sessionSecret = Salt.FromBytes(
                    Hash.SHA256(
                        new CombinedStream(
                            clientKeyBits.ToStream(),
                            new MemoryStream(serverKeyBits, false)
                            )
                        ).ToArray()
                    );

                return(sessionSecret);
            }
            private static void ReadHeader(Stream input, out int ver, out TransferState state, out Guid txid, out Salt salt)
            {
                ver = PrimitiveSerializer.Int32.ReadFrom(input);
                Check.Assert <InvalidDataException>(ver == VersionHeader);

                int istate = PrimitiveSerializer.Int32.ReadFrom(input);

                Check.Assert <InvalidDataException>(Enum.IsDefined(typeof(TransferState), istate));
                state = (TransferState)istate;

                byte[] bytes = new byte[16];
                Check.Assert <InvalidDataException>(bytes.Length == input.Read(bytes, 0, bytes.Length));
                txid = new Guid(bytes);

                bytes = new byte[32];
                Check.Assert <InvalidDataException>(bytes.Length == input.Read(bytes, 0, bytes.Length));
                salt = Salt.FromBytes(bytes);
            }