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 Message()
 {
     //EmptyMessage:
     _version = 0;
     _state = 0;
     _transferId = Guid.Empty;
     _salt = null;
     (_protected = new MemoryStream()).Dispose();
     _payload = _protected;
     (_hash = new HashStream(new SHA256Managed())).Dispose();
 }
 private Message()
 {
     //EmptyMessage:
     _version    = 0;
     _state      = 0;
     _transferId = Guid.Empty;
     _salt       = null;
     (_protected = new MemoryStream()).Dispose();
     _payload = _protected;
     (_hash = new HashStream(new SHA256Managed())).Dispose();
 }
            /// <summary>
            /// Called to send a specific length of bytes to a server identified by serverKey.  The transfer
            /// is a blocking call and returns on success or raises an exception.  If Abort() is called durring
            /// the transfer, or if a ProgressChanged event handler raises the OperationCanceledException, the
            /// transfer is silently terminated and the method will return false.
            /// </summary>
            /// <param name="location">A string of up to 1024 bytes in length</param>
            /// <param name="length">The length in bytes to send from the stream</param>
            /// <param name="rawInput">The stream to read the data from</param>
            /// <returns>True if the file was successfully received by the server</returns>
            public bool Upload(string location, long length, Stream rawInput)
            {
                Guid transferId = Guid.NewGuid();
                int  maxMessageLength;
                // STEP 1: Send a NonceRequest, Create
                Salt sessionKey = BeginUpload(transferId, location, length, out maxMessageLength);

                // STEP 2: Send the data
                Hash fullHash;

                bool[] failed = new bool[1];

                using (HashStream input = new HashStream(new SHA256Managed(), rawInput))
                    using (WorkQueue queue = new WorkQueue(LimitThreads))
                    {
                        queue.OnError += (o, e) => { failed[0] = true; };
                        long pos = 0;
                        while (pos < length && !failed[0] && !_abort.WaitOne(0, false))
                        {
                            int    len    = (int)Math.Min(length - pos, maxMessageLength);
                            byte[] buffer = new byte[len];
                            IOStream.Read(input, buffer, len);
                            BytesToSend task = new BytesToSend(this, LimitThreads, transferId, sessionKey, location, pos, buffer);
                            queue.Enqueue(task.Send);
                            OnProgressChanged(location, pos, length);
                            pos += len;
                        }

                        queue.Complete(true, failed[0] ? 5000 : 300000);
                        fullHash = input.FinalizeHash();//hash of all data transferred
                    }
                if (_abort.WaitOne(0, false))
                {
                    return(false);
                }
                Check.Assert <InvalidDataException>(failed[0] == false);

                // STEP 4: Complete the transfer
                CompleteUpload(transferId, sessionKey, location, fullHash);
                OnProgressChanged(location, length, length);
                return(true);
            }
            //private bool _verified; /* this is a debugging aid used to ensure all messages are signed or verified */

            public Message(TransferState state, Guid transferId, RSAPublicKey key, Converter <Guid, Salt> sessionSecret)
            {
                _version    = VersionHeader;
                _state      = state;
                _transferId = transferId;
                _salt       = new Salt(Salt.Size.b256);
                _protected  = new MemoryStream();
                _payload    = new NonClosingStream(_protected);
                _hash       = new HashStream(new SHA256Managed());
                WriteHeader(_hash);
                Salt secret;

                if (!UsesSessionKey)
                {
                    // Outer encryption is straight PKI based on the remote public key
                    _payload = key.Encrypt(_payload);
                    _hash.ChangeStream(_payload);
                    // Preceed the message with a new, AES key
                    secret = new Salt(Salt.Size.b256);
                    _hash.Write(secret.ToArray(), 0, 32);
                }
                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.Encrypt(_payload);
                _hash.ChangeStream(_payload);
            }
            //private bool _verified; /* this is a debugging aid used to ensure all messages are signed or verified */

            public Message(TransferState state, Guid transferId, RSAPublicKey key, Converter<Guid, Salt> sessionSecret)
            {
                _version = VersionHeader;
                _state = state;
                _transferId = transferId;
                _salt = new Salt(Salt.Size.b256);
                _protected = new MemoryStream();
                _payload = new NonClosingStream(_protected);
                _hash = new HashStream(new SHA256Managed());
                WriteHeader(_hash);
                Salt secret;

                if (!UsesSessionKey)
                {
                    // Outer encryption is straight PKI based on the remote public key
                    _payload = key.Encrypt(_payload);
                    _hash.ChangeStream(_payload);
                    // Preceed the message with a new, AES key
                    secret = new Salt(Salt.Size.b256);
                    _hash.Write(secret.ToArray(), 0, 32);
                }
                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.Encrypt(_payload);
                _hash.ChangeStream(_payload);
            }
            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);
            }
Example #8
0
		public void TestHashStreamDisposed()
		{
			using(HashStream hs = new HashStream(new SHA256Managed()))
			{
				hs.Close();
				hs.Close(); //<- fails, already closed and/or disposed
			}
		}
Example #9
0
		public void TestHashStreamWrite()
		{
			Random r = new Random();
			byte[][] test =
			new byte[][]
				{
					new byte[300], 
					new byte[1], 
					new byte[500], 
					new byte[11],
					new byte[1], 
					new byte[1000], 
				};
            using (HashStream hs = new HashStream(new SHA256Managed()))
            using (MemoryStream ms = new MemoryStream())
            using (HashStream hsWrap = new HashStream(new SHA256Managed(), ms))
			{
				Assert.IsTrue(hs.CanWrite);
                long len = 0;
				foreach (byte[] bytes in test)
				{
                    len += bytes.Length;
					r.NextBytes(bytes);
                    hsWrap.Write(bytes, 0, bytes.Length);
					hs.Write(bytes, 0, bytes.Length);
				}
                for (int i = 0; i < 5; i++)
                {
                    len += 1;
                    byte val = (byte)r.Next(255);
                    hsWrap.WriteByte(val);
                    hs.WriteByte(val);
                }

			    Assert.AreEqual(len, ms.Position);
				Hash expect = Hash.SHA256(ms.ToArray());
				Hash actual = hs.Close();

				Assert.AreEqual(expect, actual);
				Assert.AreEqual(expect.ToArray(), actual.ToArray());
				Assert.AreEqual(expect.ToString(), actual.ToString());

                //wrapped test
                actual = hsWrap.FinalizeHash();
                Assert.AreEqual(expect, actual);
                Assert.AreEqual(expect.ToArray(), actual.ToArray());
                Assert.AreEqual(expect.ToString(), actual.ToString());
			}
		}
Example #10
0
        public void TestHashStreamRead()
        {
            Random r = new Random();
            byte[] bytes = new byte[1000];
            r.NextBytes(bytes);

            using (HashStream hs = new HashStream(new SHA256Managed(), new MemoryStream(bytes)))
            {
                for (int i = 0; i < 5; i++)
                
                while (hs.Position < hs.Length)
                {
                    hs.ReadByte();
                    int amt = r.Next(255);
                    byte[] tmp = new byte[amt];
                    hs.Read(tmp, 0, tmp.Length);
                }

                Hash expect = Hash.SHA256(bytes);
                Hash actual = hs.FinalizeHash();

                Assert.AreEqual(expect, actual);
                Assert.AreEqual(expect.ToArray(), actual.ToArray());
                Assert.AreEqual(expect.ToString(), actual.ToString());

                //still valid after FinalizeHash(); however, hash is restarted
                hs.Position = 0;
                IOStream.Read(hs, bytes.Length);
                actual = hs.FinalizeHash();

                Assert.AreEqual(expect, actual);
                Assert.AreEqual(expect.ToArray(), actual.ToArray());
                Assert.AreEqual(expect.ToString(), actual.ToString());
            }
        }
            /// <summary>
            /// Called to send a specific length of bytes to a server identified by serverKey.  The transfer
            /// is a blocking call and returns on success or raises an exception.  If Abort() is called durring
            /// the transfer, or if a ProgressChanged event handler raises the OperationCanceledException, the
            /// transfer is silently terminated and the method will return false.
            /// </summary>
            /// <param name="location">A string of up to 1024 bytes in length</param>
            /// <param name="length">The length in bytes to send from the stream</param>
            /// <param name="rawInput">The stream to read the data from</param>
            /// <returns>True if the file was successfully received by the server</returns>
            public bool Upload(string location, long length, Stream rawInput)
            {
                Guid transferId = Guid.NewGuid();
                int maxMessageLength;
                // STEP 1: Send a NonceRequest, Create
                Salt sessionKey = BeginUpload(transferId, location, length, out maxMessageLength);

                // STEP 2: Send the data
                Hash fullHash;
                bool[] failed = new bool[1];

                using (HashStream input = new HashStream(new SHA256Managed(), rawInput))
                using (WorkQueue queue = new WorkQueue(LimitThreads))
                {
                    queue.OnError += (o, e) => { failed[0] = true; };
                    long pos = 0;
                    while (pos < length && !failed[0] && !_abort.WaitOne(0, false))
                    {
                        int len = (int)Math.Min(length - pos, maxMessageLength);
                        byte[] buffer = new byte[len];
                        IOStream.Read(input, buffer, len);
                        BytesToSend task = new BytesToSend(this, LimitThreads, transferId, sessionKey, location, pos, buffer);
                        queue.Enqueue(task.Send);
                        OnProgressChanged(location, pos, length);
                        pos += len;
                    }

                    queue.Complete(true, failed[0] ? 5000 : 300000);
                    fullHash = input.FinalizeHash();//hash of all data transferred
                }
                if (_abort.WaitOne(0, false))
                    return false;
                Check.Assert<InvalidDataException>(failed[0] == false);

                // STEP 4: Complete the transfer
                CompleteUpload(transferId, sessionKey, location, fullHash);
                OnProgressChanged(location, length, length);
                return true;
            }