Example #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Session"/> class.
        /// </summary>
        protected Session()
        {
            _id = Crypto8.GenerateNonce();
#if DEBUG
            _ident = InternalUtils.BytesToString(_id);
#endif
        }
        public override Message ProcessIncoming(MessageHeader header, byte[] chiper, ref byte[] plaintext)
        {
            var messageDirection = Message.GetMessageDirection(header.ID);
            // Message instance that we will return to the caller.
            var message = MessageFactory.Create(header.ID);

            // Unencrypted byte array.
            plaintext = null;
            lock (_lock)
            {
                // Handshaking.
                if (_state <= 1)
                {
                    // Handshakes are sent unencrypted.
                    // First message by both ends is always sent unencrypted.
                    plaintext = (byte[])chiper.Clone();

                    // Use the first message direction to configure the processor.
                    if (_state == 0)
                    {
                        _clientCrypto = new Crypto8(GetOppositeDirection(messageDirection), _keyPair);
                    }
                    if (_state == 1)
                    {
                        _serverCrypto = new Crypto8(GetOppositeDirection(messageDirection), Crypto8.GenerateKeyPair());
                    }
                }

                if (_state == 4)
                {
                    _clientCrypto.UpdateNonce((byte[])_serverNonce.Clone(), UpdateNonceType.Encrypt);
                    _clientCrypto.UpdateNonce((byte[])_clientNonce.Clone(), UpdateNonceType.Decrypt);
                    _clientCrypto.UpdateSharedKey(_serverCrypto.SharedKey);
                }

                // _state == 1 means we are the server.
                // Usually processing 10101 - LoginRequestMessage.
                if (_state == 2)
                {
                    _serverCrypto.UpdateSharedKey(Crypto8.SupercellPublicKey);

                    // -> Pre-Encryption.
                    // Copies the public key appended to the beginning of the message.
                    var publicKey = new byte[CoCKeyPair.KeyLength];
                    Buffer.BlockCopy(chiper, 0, publicKey, 0, CoCKeyPair.KeyLength);

                    Debug.WriteLine($"Public-Key from {header.ID}: {ToHexString(publicKey)}");

                    // Copies the remaining bytes into the plaintext buffer
                    var plaintextLen = header.Length - CoCKeyPair.KeyLength;
                    plaintext = new byte[plaintextLen];
                    Buffer.BlockCopy(chiper, CoCKeyPair.KeyLength, plaintext, 0, plaintextLen);

                    // Crypto8 will take publicKey & _keyPair.PublicKey and generate a blake2b nonce
                    _clientCrypto.UpdateSharedKey(publicKey);
                    // Then use _keyPair.PrivateKey, publicKey and nonce to decrypt.
                    _clientCrypto.Decrypt(ref plaintext);

                    // -> Post-Encryption.
                    _sessionKey  = new byte[CoCKeyPair.NonceLength];
                    _clientNonce = new byte[CoCKeyPair.NonceLength];

                    // Copy the SessionKey and the ClientNonce.
                    Buffer.BlockCopy(plaintext, 0, _sessionKey, 0, CoCKeyPair.NonceLength);
                    Buffer.BlockCopy(plaintext, CoCKeyPair.NonceLength, _clientNonce, 0, CoCKeyPair.NonceLength);

                    Debug.WriteLine($"Session-key from {header.ID}: {ToHexString(_sessionKey)}");
                    Debug.WriteLine($"Client-nonce from {header.ID}: {ToHexString(_clientNonce)}");

                    var actualMessage = new byte[plaintext.Length - (CoCKeyPair.NonceLength * 2)];
                    Buffer.BlockCopy(plaintext, CoCKeyPair.NonceLength * 2, actualMessage, 0, actualMessage.Length);

                    plaintext = actualMessage;
                }
                else if (_state == 3)
                {
                    _clientCrypto.UpdateNonce(_clientNonce, UpdateNonceType.Blake);
                    _serverCrypto.UpdateNonce(_clientNonce, UpdateNonceType.Blake);
                    _serverCrypto.Decrypt(ref chiper);

                    // Post-Encryption
                    // Copies the public key appended to the beginning of the message.
                    _serverNonce = new byte[CoCKeyPair.NonceLength];
                    Buffer.BlockCopy(chiper, 0, _serverNonce, 0, CoCKeyPair.NonceLength);

                    var publicKey = new byte[CoCKeyPair.KeyLength];
                    Buffer.BlockCopy(chiper, CoCKeyPair.NonceLength, publicKey, 0, CoCKeyPair.KeyLength);

                    _serverCrypto.UpdateNonce((byte[])_serverNonce.Clone(), UpdateNonceType.Decrypt);
                    _serverCrypto.UpdateNonce((byte[])_clientNonce.Clone(), UpdateNonceType.Encrypt);
                    _serverCrypto.UpdateSharedKey(publicKey);

                    Debug.WriteLine($"Server-Nonce from {header.ID}: {ToHexString(_serverNonce)}");
                    Debug.WriteLine($"New Public-Key from {header.ID}: {ToHexString(publicKey)}");

                    // Copies the remaining bytes into the plaintext buffer.
                    var plaintextLen = chiper.Length - CoCKeyPair.KeyLength - CoCKeyPair.NonceLength;
                    plaintext = new byte[plaintextLen];

                    Buffer.BlockCopy(chiper, CoCKeyPair.KeyLength + CoCKeyPair.NonceLength, plaintext, 0, plaintextLen);
                }
                else if (_state > 3)
                {
                    if (messageDirection == MessageDirection.Client)
                    {
                        _serverCrypto.Decrypt(ref chiper);
                    }

                    if (messageDirection == MessageDirection.Server)
                    {
                        _clientCrypto.Decrypt(ref chiper);
                    }

                    plaintext = chiper;
                }

                _state++;
            }
            try
            {
                using (var reader = new MessageReader(new MemoryStream(plaintext)))
                    message.ReadMessage(reader);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Ex: " + ex);
            }
            return(message);
        }
Example #3
0
        public void Connect(EndPoint endPoint)
        {
            if (endPoint == null)
            {
                throw new ArgumentNullException(nameof(endPoint));
            }

            _socket.Connect(endPoint);
            _networkManager = new NetworkManagerAsync(_socket, s_settings, new MessageProcessorNaCl(Crypto8.GenerateKeyPair(), Crypto8.SupercellPublicKey));
            _networkManager.MessageReceived += OnMessageReceived;
            _networkManager.Disconnected    += OnDisconnected;
        }
        private byte[] ProcessOutgoingData(MessageDirection direction, byte[] plaintext)
        {
            var chiper = (byte[])null;

            // Handshaking
            if (_outgoingState == 0)
            {
                chiper = (byte[])plaintext.Clone();

                _direction = direction;
                if (_crypto == null)
                {
                    _crypto = new Crypto8(direction, _keyPair);
                }
            }

            if (direction != _direction)
            {
                throw new InvalidOperationException("Tried to process an outgoing message coming from a different direction."); // -> Protocol Exception?
            }
            // _outgoingState == 2 means we're the server.
            // Usually processing 20104 - LoginSuccessMessage.
            if (_outgoingState == 2)
            {
                Debug.Assert(_remoteNonce != null);
                Debug.Assert(_localNonce == null);

                var key         = Crypto8.GenerateKeyPair();
                var localNonce  = Crypto8.GenerateNonce();
                var remoteNonce = _remoteNonce;

                var tmpChiper = new byte[plaintext.Length + KeyPair.NonceLength + KeyPair.KeyLength];
                Buffer.BlockCopy(localNonce, 0, tmpChiper, 0, KeyPair.NonceLength);
                Buffer.BlockCopy(key.PublicKey, 0, tmpChiper, KeyPair.NonceLength, KeyPair.KeyLength);
                Buffer.BlockCopy(plaintext, 0, tmpChiper, KeyPair.NonceLength + KeyPair.KeyLength, plaintext.Length);

                _crypto.Encrypt(ref tmpChiper);

                Debug.WriteLine($"Server-nonce: {ToHexString(localNonce)}");
                Debug.WriteLine($"Shared-key: {ToHexString(key.PublicKey)}");

                _crypto.UpdateNonce(localNonce, UpdateNonceType.Encrypt);
                _crypto.UpdateSharedKey(key.PublicKey);

                _localNonce = localNonce;
                chiper      = tmpChiper;
                //_key = key;
            }
            // _outgoingState == 3 means we're the client.
            // Usually processing 10101 - LoginRequestMessage.
            else if (_outgoingState == 3)
            {
                var serverKey  = _serverKey;
                var sessionKey = _sessionKey;
                Debug.Assert(serverKey != null, "Server key was null.");
                Debug.Assert(sessionKey != null, "Session key was null.");

                // Generate a ClientNonce.
                var localNonce = Crypto8.GenerateNonce();

                Debug.WriteLine($"Generated ClientNonce: {ToHexString(localNonce)}");

                // Craft the new packet which is
                // tmpChiper = sessionKey + localNonce + plaintext.
                var tmpChiper = new byte[plaintext.Length + KeyPair.NonceLength * 2];
                Buffer.BlockCopy(sessionKey, 0, tmpChiper, 0, KeyPair.NonceLength);
                Buffer.BlockCopy(localNonce, 0, tmpChiper, KeyPair.NonceLength, KeyPair.NonceLength);
                Buffer.BlockCopy(plaintext, 0, tmpChiper, KeyPair.NonceLength * 2, plaintext.Length);

                // Use our specified from the constructor _keyPair.PublicKey and specified _serverKey from the constructor
                // to generate the blake2b nonce and encrypt using _keyPair.PrivateKey and the generated blake2b nonce.
                _crypto.UpdateSharedKey(serverKey);
                _crypto.Encrypt(ref tmpChiper);

                // Craft another new packet which is
                // chiper = _keyPair.PublicKey + tmpChiper.
                chiper = new byte[tmpChiper.Length + KeyPair.KeyLength];
                Buffer.BlockCopy(_crypto.KeyPair.PublicKey, 0, chiper, 0, KeyPair.KeyLength);
                Buffer.BlockCopy(tmpChiper, 0, chiper, KeyPair.KeyLength, tmpChiper.Length);

                _localNonce = localNonce;
            }
            // Messages after the previous states are processed the same way.
            else if (_outgoingState > (int)_direction)
            {
                var tmpChiper = (byte[])plaintext.Clone();

                _crypto.Encrypt(ref tmpChiper);
                chiper = tmpChiper;
            }

            return(chiper);
        }
        private byte[] ProcessIncomingData(MessageDirection direction, MessageHeader header, BufferStream stream)
        {
            var plaintext = (byte[])null;
            var chiper    = new byte[header.Length];

            stream.Read(chiper, 0, header.Length);

            // Handshaking.
            if (_incommingState == 0)
            {
                // Handshakes are sent unencrypted.
                // First message by both ends is always sent unencrypted.
                plaintext = new byte[header.Length];
                Buffer.BlockCopy(chiper, 0, plaintext, 0, header.Length);

                // Use the first message direction to configure the processor.
                // If message is coming in, then the going out is opposite direction.
                _direction = GetOppositeDirection(direction);
                // If we're the client then we must have a serverkey.
                if (_direction == MessageDirection.Server && _serverKey == null)
                {
                    throw new InvalidOperationException("Public key of server was not specified.");
                }

                if (_crypto == null)
                {
                    _crypto = new Crypto8(_direction, _keyPair);
                }

                Debug.WriteLine($"Initialized Crypto8 {_direction} with private-key: {ToHexString(_keyPair.PrivateKey)}, public-key {_keyPair.PublicKey}");
            }

            // If somehow the incoming message to process comes from the same direction.
            // The MessageProcessor can only process message going in One Direction. ;]
            if (GetOppositeDirection(direction) != _direction)
            {
                throw new InvalidOperationException("Tried to process an incoming data from a message coming from the same direction."); // -> Protocol Exception?
            }
            // _incomingState == 2 means we are the server.
            // Usually processing 10101 - LoginRequestMessage.
            if (_incommingState == 2)
            {
                // -> Post-Encryption.
                // Copies the public key appended to the beginning of the message
                // sent of message 20100.
                var publicKey = new byte[KeyPair.KeyLength];
                Buffer.BlockCopy(chiper, 0, publicKey, 0, KeyPair.KeyLength);

                Debug.WriteLine($"Public-Key from {header.Id}: {ToHexString(publicKey)}");

                // Copies the remaining bytes into the postChiper buffer which
                // will be decrypted by _crypto.
                var tmpPlaintextLen = header.Length - KeyPair.KeyLength;
                var tmpPlaintext    = new byte[tmpPlaintextLen];
                Buffer.BlockCopy(chiper, KeyPair.KeyLength, tmpPlaintext, 0, tmpPlaintextLen);

                // Crypto8 will take the client's publicKey & _keyPair.PublicKey and generate a blake2b nonce
                _crypto.UpdateSharedKey(publicKey);
                // Then use _keyPair.PrivateKey, publicKey and nonce to decrypt.
                _crypto.Decrypt(ref tmpPlaintext);

                // -> Pre-Encryption.
                var sessionKey  = new byte[KeyPair.NonceLength];
                var remoteNonce = new byte[KeyPair.NonceLength];

                // Copy the SessionKey and the ClientNonce.
                Buffer.BlockCopy(tmpPlaintext, 0, sessionKey, 0, KeyPair.NonceLength);
                Buffer.BlockCopy(tmpPlaintext, KeyPair.NonceLength, remoteNonce, 0, KeyPair.NonceLength);

                Debug.WriteLine($"Session-key from {header.Id}: {ToHexString(sessionKey)}");
                Debug.WriteLine($"Client-nonce from {header.Id}: {ToHexString(remoteNonce)}");

                // Copies the plaintext without the session key and the remote/client nonce.
                var plaintextLen = tmpPlaintext.Length - (KeyPair.NonceLength * 2);
                plaintext = new byte[plaintextLen];
                Buffer.BlockCopy(tmpPlaintext, KeyPair.NonceLength * 2, plaintext, 0, plaintextLen);

                _crypto.UpdateNonce(remoteNonce, UpdateNonceType.Decrypt);
                _crypto.UpdateNonce(remoteNonce, UpdateNonceType.Blake);
                _sessionKey  = sessionKey;
                _remoteNonce = remoteNonce;

                _nstate = States.Authentifying;
            }
            // _incomingState == 3 means we are the client.
            // Usually processing 20104 - LoginSuccessMessage.
            else if (_incommingState == 3)
            {
                // -> Might want to generate random nonce here for the
                // client nonce.
                Debug.Assert(_localNonce != null);

                var tmpPlaintext = (byte[])chiper.Clone();

                // _crypto will use this nonce after the second key is passed to it
                // using _crypto.UpdateSharedKey.
                var localNonce = _localNonce;
                _crypto.UpdateNonce(localNonce, UpdateNonceType.Encrypt);
                _crypto.UpdateNonce(localNonce, UpdateNonceType.Blake);
                _crypto.Decrypt(ref tmpPlaintext);

                // -> Post-Encryption
                var remoteNonce = new byte[KeyPair.NonceLength];
                var key         = new byte[KeyPair.KeyLength];

                // Copies the ServerNonce and the new second secret key.
                Buffer.BlockCopy(tmpPlaintext, 0, remoteNonce, 0, KeyPair.NonceLength);
                Buffer.BlockCopy(tmpPlaintext, KeyPair.NonceLength, key, 0, KeyPair.KeyLength);

                Debug.WriteLine($"Shared-key from {header.Id}: {ToHexString(key)}");
                Debug.WriteLine($"Server-nonce from {header.Id}: {ToHexString(remoteNonce)}");

                // Copies the plaintext without the server nonce and the new second secret key.
                var plaintextLen = tmpPlaintext.Length - KeyPair.NonceLength - KeyPair.KeyLength;
                plaintext = new byte[plaintextLen];
                Buffer.BlockCopy(tmpPlaintext, KeyPair.NonceLength + KeyPair.KeyLength, plaintext, 0, plaintextLen);

                _crypto.UpdateNonce(remoteNonce, UpdateNonceType.Decrypt);
                _crypto.UpdateSharedKey(key);

                _remoteNonce = remoteNonce;
                _key         = key;

                _nstate = States.Authentified;
            }
            // Messages after the previous states are processed the same way.
            else if (_incommingState > (int)_direction)
            {
                _nstate = States.Completed;

                plaintext = (byte[])chiper.Clone();
                _crypto.Decrypt(ref plaintext);
            }

            return(plaintext);
        }