/// <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); }
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); }