private void CompleteUpload(Guid transferId, Salt sessionKey, string location, Hash fullHash)
            {
                // STEP 4: Finalize the transfer
                using (Message req = new Message(TransferState.UploadCompleteRequest, transferId, _publicKey, s => sessionKey))
                {
                    req.Write(location);
                    req.Write(fullHash.ToArray());

                    Stream response = SendPayload(req, location, req.ToStream(_privateKey));
                    using (Message rsp = new Message(response, _privateKey, s => sessionKey))
                    {
                        Check.Assert <InvalidOperationException>(rsp.State == TransferState.UploadCompleteResponse);
                        rsp.VerifySignature(_publicKey);
                    }
                }
            }
            private void TransferBytes(Guid transferId, Salt sessionKey, string location, long offset, byte[] bytes)
            {
                // STEP 3...n: Send a block of bytes
                using (Message req = new Message(TransferState.SendBytesRequest, transferId, _publicKey, s => sessionKey))
                {
                    req.Write(offset);
                    req.Write(bytes);

                    Stream response = SendPayload(req, location, req.ToStream(_privateKey));
                    using (Message rsp = new Message(response, _privateKey, s => sessionKey))
                    {
                        Check.Assert <InvalidOperationException>(rsp.State == TransferState.SendBytesResponse);
                        Check.Assert <InvalidOperationException>(rsp.ReadInt64() == offset);
                        rsp.VerifySignature(_publicKey);
                    }
                }
            }
            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);
            }
            /// <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 byte[] IV(Salt secret, Salt salt)
            {
                // Long story, this has been a little difficult to finally settle upon an algorithm.
                // We know we don't want to the same value each time, and we prefer not to use only
                // the public salt.  My biggest concern is not generating a IV value that interacts
                // with AES in a way that might divulge information unintentionally.  Since we are
                // using the same values (salt+secret) to derive the IV this is a very real risk.
                // To mitigate this risk the primary interaction of secret in the derivation of this
                // value is compressed into a CRC of both the salt and secret.  This value is then
                // masked with computations of salt to produce the 16 IV bytes needed.
                byte[] sbytes = salt.ToArray();
                byte[] result = new byte[16];
                // compute a mask from CRC32(salt + secret)
                int mask = new Crc32(_salt.GetData(secret.ToArray()).ToArray()).Value;

                // xor part of the mask with the sum of two salt bytes
                for (int i = 0; i < 16; i++)
                {
                    result[i] = (byte)((mask >> i) ^ (sbytes[i] + sbytes[i + 16]));
                }

                return(result);
            }
            //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);
            }
Esempio n. 7
0
 /// <summary> Combines the salt with the data provided </summary>
 public SaltedData(Salt salt, Stream data)
     : this(salt, IOStream.ReadAllBytes(data))
 {
 }
Esempio n. 8
0
 /// <summary> Returns a stream that combines the salt and data </summary>
 public static Stream CombineStream(Salt salt, Stream data)
 {
     return(new IO.CombinedStream(salt.ToStream(), data));
 }
Esempio n. 9
0
 /// <summary>
 /// Constructs the Rfc2898DeriveBytes implementation.
 /// </summary>
 public PBKDF2(byte[] password, Salt salt, int iterations)
     : base(password, salt.ToArray(), iterations)
 {
 }
Esempio n. 10
0
 /// <summary> Returns a salted hash for the password </summary>
 public PasswordHash CreateHash(Salt salt)
 {
     return(new PasswordHash(this, salt));
 }
Esempio n. 11
0
 /// <summary> Creates the hash from the given data and salt </summary>
 public PasswordHash(string data, Salt salt)
     : this(true, Password.Encoding.GetBytes(data), salt)
 {
 }
 /// <summary>
 /// Constructs the byte generation routine with the specified key, salt, and iteration count
 /// </summary>
 public HashDerivedBytes(byte[] password, Salt salt, int iterations)
     : this(false, password, salt, iterations)
 {
 }
Esempio n. 13
0
 private LocalHostKey(DataProtectionScope scope, Salt salt)
     : this(scope)
 {
     _salt = salt;
 }
Esempio n. 14
0
 /// <summary> Creates the hash from the given data and salt </summary>
 public PasswordHash(SecureString data, Salt salt)
     : this(true, SecureStringUtils.ToByteArray(data, Password.Encoding), salt)
 {
 }
            private bool Download(string location, StreamCache output)
            {
                int  maxMessageLength;
                long fileLength, bytesReceived = 0;
                Guid transferId = Guid.NewGuid();

                byte[] serverKeyBits;
                byte[] nonce  = GetNonce(transferId, location, out serverKeyBits);
                Hash   hnonce = Hash.SHA256(nonce);

                //STEP 2: Create and send session key
                Salt clientKeyBits = new Salt(Salt.Size.b256);
                Salt sessionKey    = SessionSecret(clientKeyBits, serverKeyBits);

                using (Message req = new Message(TransferState.DownloadRequest, transferId, _publicKey, NoSession))
                {
                    req.Write(hnonce.ToArray());
                    req.Write(location);
                    req.Write(clientKeyBits.ToArray());

                    Stream response = SendPayload(req, location, req.ToStream(_privateKey));
                    using (Message rsp = new Message(response, _privateKey, s => sessionKey))
                    {
                        Check.Assert <InvalidOperationException>(rsp.State == TransferState.DownloadResponse);
                        maxMessageLength = Check.InRange(rsp.ReadInt32(), 0, int.MaxValue);
                        fileLength       = Check.InRange(rsp.ReadInt64(), 0, 0x00FFFFFFFFFFFFFFL);
                        byte[] bytes = rsp.ReadBytes(100 * 1000 * 1024);
                        rsp.VerifySignature(_publicKey);

                        using (Stream io = output.Open(FileAccess.Write))
                        {
                            io.SetLength(fileLength);
                            if (bytes.Length > 0)
                            {
                                io.Seek(0, SeekOrigin.Begin);
                                io.Write(bytes, 0, bytes.Length);
                                bytesReceived += bytes.Length;
                            }
                        }
                    }
                }
                //STEP 3...n: Continue downloading other chunks of the file
                if (bytesReceived < fileLength)
                {
                    bool[] failed = new bool[1];
                    using (WorkQueue queue = new WorkQueue(LimitThreads))
                    {
                        queue.OnError += (o, e) => { failed[0] = true; };
                        while (bytesReceived < fileLength && !failed[0] && !_abort.WaitOne(0, false))
                        {
                            int         len  = (int)Math.Min(fileLength - bytesReceived, maxMessageLength);
                            BytesToRead task = new BytesToRead(
                                this, LimitThreads, transferId, sessionKey, location, output, bytesReceived, len);
                            queue.Enqueue(task.Send);
                            OnProgressChanged(location, bytesReceived, fileLength);
                            bytesReceived += len;
                        }

                        queue.Complete(true, failed[0] ? 5000 : 7200000);
                    }

                    if (_abort.WaitOne(0, false))
                    {
                        return(false);
                    }
                    Check.Assert <InvalidDataException>(failed[0] == false);

                    // STEP 4: Complete the transfer
                    using (Message req = new Message(TransferState.DownloadCompleteRequest, transferId, _publicKey, s => sessionKey))
                    {
                        SendPayload(req, location, req.ToStream(_privateKey)).Dispose();
                    }
                }
                OnProgressChanged(location, fileLength, fileLength);
                return(true);
            }
 private Salt SessionKey(Guid transferId)
 {
     return(Salt.FromString(ReadState(transferId, "session-key")));
 }
Esempio n. 17
0
 /// <summary> Creates the password from the given bytes and salt </summary>
 public PasswordKey(IPasswordDerivedBytes derivedBytes, Salt salt)
 {
     _derivedBytes = derivedBytes;
     _salt         = salt;
     _iv           = null;
 }
 /// <summary>
 /// Constructs the byte generation routine with the specified key, salt, and iteration count
 /// </summary>
 public HashDerivedBytes(Stream password, Salt salt, int iterations)
     : this(Create(), password, salt, iterations)
 {
 }
 /// <summary>
 /// Constructs the byte generation routine with the specified key, salt, and iteration count
 /// </summary>
 public HashDerivedBytes(THash algo, Stream password, Salt salt, int iterations)
     : this((HMAC)algo, password, salt, iterations)
 {
 }
Esempio n. 20
0
 /// <summary> Combines the salt with the data provided </summary>
 public SaltedData(Salt salt, byte[] data)
 {
     _salt = salt;
     _data = (byte[])data.Clone();
 }
Esempio n. 21
0
 /// <summary> Creates a salted hash from the given bytes and salt </summary>
 public PasswordHash(Stream bytes, Salt salt)
 {
     using (bytes)
         using (HashDerivedBytes <HMACSHA256> hashBytes = new HashDerivedBytes <HMACSHA256>(bytes, salt, StandardIterations))
             _hash = new SaltedData(salt, hashBytes.GetBytes(32));
 }
Esempio n. 22
0
 private LocalHostKey(DataProtectionScope scope)
 {
     _scope = scope;
     _salt  = null;
 }
Esempio n. 23
0
 /// <summary> Creates a salted hash from the given password and salt </summary>
 public PasswordHash(Password bytes, Salt salt)
     : this(bytes.ReadBytes(), salt)
 {
 }
Esempio n. 24
0
 /// <summary>
 /// Sets or changes the salt for this encryption key
 /// </summary>
 public LocalHostKey WithSalt(Salt salt)
 {
     return(new LocalHostKey(_scope, salt));
 }
Esempio n. 25
0
 /// <summary> Creates the password from the given bytes and salt </summary>
 public PasswordKey(bool clear, byte[] bytes, Salt salt)
     : this(new HashDerivedBytes <HMACSHA256>(clear, Check.NotEmpty(bytes), salt, DefaultIterations), salt)
 {
 }