private void NegotiateAuthentication(string streamPassword, bool client)
        {
            int oldReadTimeout = baseStream.ReadTimeout;

                baseStream.ReadTimeout = 5000;

                RSACryptoServiceProvider localKeys;
                RSACryptoServiceProvider remoteKey;

                // Generate and send public key
                {
                    localKeys = new RSACryptoServiceProvider();
                    byte[] publicBlob = localKeys.ExportCspBlob(false);
                    baseStream.Write(BitConverter.GetBytes(publicBlob.Length), 0, 4);
                    baseStream.Write(publicBlob, 0, publicBlob.Length);
                }

                // Receive remote public key
                try
                {
                    byte[] blobLen = new byte[4];
                    StreamHelper.ForceReadAll(baseStream, blobLen, 0, 4);

                    byte[] remoteBlob = new byte[BitConverter.ToInt32(blobLen, 0)];
                    StreamHelper.ForceReadAll(baseStream, remoteBlob, 0, remoteBlob.Length);

                    remoteKey = new RSACryptoServiceProvider();
                    remoteKey.ImportCspBlob(remoteBlob);
                } catch (Exception) {
                    throw new EncryptedNetworkStreamException(EncryptedNetworkStreamException.Reason.NetworkError);
                }

                rsaStream = new RSAStream(baseStream, localKeys, remoteKey);

                AesCryptoServiceProvider aesKey = new AesCryptoServiceProvider();
                aesKey.KeySize = 256;

                // Authenticate client/server
                byte[] passwordHash = MD5.Create().ComputeHash(ASCIIEncoding.UTF8.GetBytes(streamPassword));

                if (client)
                {
                    // If we're the client, send the password hash (encrypted)
                    rsaStream.Write(passwordHash, 0, 16);

                    // Read AES key
                    byte[] lenBuffer = new byte[4];
                    StreamHelper.ForceReadAll(rsaStream, lenBuffer, 0, 4);

                    byte[] aesKeyBuffer = new Byte[BitConverter.ToInt32(lenBuffer, 0)];
                    StreamHelper.ForceReadAll(rsaStream, aesKeyBuffer, 0, aesKeyBuffer.Length);

                    StreamHelper.ForceReadAll(rsaStream, lenBuffer, 0, 4);

                    byte[] aesIVBuffer = new Byte[BitConverter.ToInt32(lenBuffer, 0)];
                    StreamHelper.ForceReadAll(rsaStream, aesIVBuffer, 0, aesIVBuffer.Length);

                    aesKey.Key = aesKeyBuffer;
                    aesKey.IV = aesIVBuffer;

                } else {
                    // If we're the server, wait for them to send the password (encrypted)
                    byte[] receivedPasswordHash = new byte[16];
                    StreamHelper.ForceReadAll(rsaStream, receivedPasswordHash, 0, 16);

                    if (! passwordHash.SequenceEqual(receivedPasswordHash))
                        throw new EncryptedNetworkStreamException(EncryptedNetworkStreamException.Reason.InvalidAuthentication);

                    // Generate/send AES key
                    aesKey.GenerateKey();
                    aesKey.GenerateIV();

                    // Group length and key togeather to lower overhead

                    byte[] keyDataBuffer = SerializedArray.ToNetworkBytes(aesKey.Key);
                    rsaStream.Write(keyDataBuffer, 0, keyDataBuffer.Length);

                    byte[] keyIVBuffer = SerializedArray.ToNetworkBytes(aesKey.IV);
                    rsaStream.Write(keyIVBuffer, 0, keyIVBuffer.Length);
                }

                aesStream = new AESStream(baseStream, aesKey);

                baseStream.ReadTimeout = oldReadTimeout;
        }
Exemple #2
0
        private void NegotiateAuthentication(string streamPassword, bool client)
        {
            int oldReadTimeout = baseStream.ReadTimeout;

            baseStream.ReadTimeout = 5000;


            RSACryptoServiceProvider localKeys;
            RSACryptoServiceProvider remoteKey;

            // Generate and send public key
            {
                localKeys = new RSACryptoServiceProvider();
                byte[] publicBlob = localKeys.ExportCspBlob(false);
                baseStream.Write(BitConverter.GetBytes(publicBlob.Length), 0, 4);
                baseStream.Write(publicBlob, 0, publicBlob.Length);
            }

            // Receive remote public key
            try
            {
                byte[] blobLen = new byte[4];
                StreamHelper.ForceReadAll(baseStream, blobLen, 0, 4);

                byte[] remoteBlob = new byte[BitConverter.ToInt32(blobLen, 0)];
                StreamHelper.ForceReadAll(baseStream, remoteBlob, 0, remoteBlob.Length);

                remoteKey = new RSACryptoServiceProvider();
                remoteKey.ImportCspBlob(remoteBlob);
            } catch (Exception) {
                throw new EncryptedNetworkStreamException(EncryptedNetworkStreamException.Reason.NetworkError);
            }

            rsaStream = new RSAStream(baseStream, localKeys, remoteKey);

            AesCryptoServiceProvider aesKey = new AesCryptoServiceProvider();

            aesKey.KeySize = 256;

            // Authenticate client/server
            byte[] passwordHash = MD5.Create().ComputeHash(ASCIIEncoding.UTF8.GetBytes(streamPassword));

            if (client)
            {
                // If we're the client, send the password hash (encrypted)
                rsaStream.Write(passwordHash, 0, 16);

                // Read AES key
                byte[] lenBuffer = new byte[4];
                StreamHelper.ForceReadAll(rsaStream, lenBuffer, 0, 4);

                byte[] aesKeyBuffer = new Byte[BitConverter.ToInt32(lenBuffer, 0)];
                StreamHelper.ForceReadAll(rsaStream, aesKeyBuffer, 0, aesKeyBuffer.Length);

                StreamHelper.ForceReadAll(rsaStream, lenBuffer, 0, 4);

                byte[] aesIVBuffer = new Byte[BitConverter.ToInt32(lenBuffer, 0)];
                StreamHelper.ForceReadAll(rsaStream, aesIVBuffer, 0, aesIVBuffer.Length);

                aesKey.Key = aesKeyBuffer;
                aesKey.IV  = aesIVBuffer;
            }
            else
            {
                // If we're the server, wait for them to send the password (encrypted)
                byte[] receivedPasswordHash = new byte[16];
                StreamHelper.ForceReadAll(rsaStream, receivedPasswordHash, 0, 16);


                if (!passwordHash.SequenceEqual(receivedPasswordHash))
                {
                    throw new EncryptedNetworkStreamException(EncryptedNetworkStreamException.Reason.InvalidAuthentication);
                }

                // Generate/send AES key
                aesKey.GenerateKey();
                aesKey.GenerateIV();

                // Group length and key togeather to lower overhead

                byte[] keyDataBuffer = SerializedArray.ToNetworkBytes(aesKey.Key);
                rsaStream.Write(keyDataBuffer, 0, keyDataBuffer.Length);

                byte[] keyIVBuffer = SerializedArray.ToNetworkBytes(aesKey.IV);
                rsaStream.Write(keyIVBuffer, 0, keyIVBuffer.Length);
            }

            aesStream = new AESStream(baseStream, aesKey);

            baseStream.ReadTimeout = oldReadTimeout;
        }