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(); }
/// <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); }
public void TestHashStreamDisposed() { using(HashStream hs = new HashStream(new SHA256Managed())) { hs.Close(); hs.Close(); //<- fails, already closed and/or disposed } }
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()); } }
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; }