Example #1
0
        private void InitializeChannel(IChannel channel, EncryptionHandshakeRole role, NodeId remoteId = null, string remoteHost = null, int?remotePort = null)
        {
            var        connectionType = remoteId == null ? ClientConnectionType.In : ClientConnectionType.Out;
            P2PSession p2PSession     = new P2PSession(
                LocalNodeId,
                _localPort,
                _serializationService,
                _synchronizationManager,
                _logManager)
            {
                ClientConnectionType = connectionType
            };

            //This is the first moment we get confirmed publicKey of remote node in case of outgoing connections
            if (connectionType == ClientConnectionType.Out)
            {
                if (_logger.IsInfoEnabled)
                {
                    _logger.Info($"Initializing {connectionType.ToString().ToUpper()} channel{(connectionType == ClientConnectionType.Out ? $": {remoteId}@{remoteHost}:{remoteId}" : string.Empty)}");
                }

                p2PSession.RemoteNodeId = remoteId;
                p2PSession.RemoteHost   = remoteHost;
                p2PSession.RemotePort   = remotePort;
                ConnectionInitialized?.Invoke(this, new ConnectionInitializedEventArgs(p2PSession, connectionType));
            }

            var handshakeHandler = new NettyHandshakeHandler(_encryptionHandshakeService, p2PSession, role, remoteId, _logger);

            handshakeHandler.HandshakeInitialized += (s, e) =>
            {
                //This is the first moment we get confirmed publicKey of remote node in case of incoming connections
                if (connectionType == ClientConnectionType.In)
                {
                    if (_logger.IsInfoEnabled)
                    {
                        _logger.Info($"Initializing {connectionType.ToString().ToUpper()} channel {p2PSession.RemoteNodeId}@{p2PSession.RemoteHost}:{p2PSession.RemotePort}");
                    }

                    ConnectionInitialized?.Invoke(this, new ConnectionInitializedEventArgs(p2PSession, connectionType));
                }
            };

            IChannelPipeline pipeline = channel.Pipeline;

            pipeline.AddLast(new LoggingHandler(connectionType.ToString().ToUpper(), DotNetty.Handlers.Logging.LogLevel.TRACE));
            pipeline.AddLast("enc-handshake-dec", new LengthFieldBasedFrameDecoder(ByteOrder.BigEndian, ushort.MaxValue, 0, 2, 0, 0, true));
            pipeline.AddLast("enc-handshake-handler", handshakeHandler);

            channel.CloseCompletion.ContinueWith(async x =>
            {
                if (_logger.IsInfoEnabled)
                {
                    _logger.Info($"Channel disconnection: {p2PSession.RemoteNodeId}");
                }
                await p2PSession.DisconnectAsync(DisconnectReason.ClientQuitting, DisconnectType.Remote);
            });
        }
        private void SetSecrets(EncryptionHandshake handshake, EncryptionHandshakeRole encryptionHandshakeRole)
        {
            byte[] ephemeralSharedSecret = BouncyCrypto.Agree(handshake.EphemeralPrivateKey, handshake.RemoteEphemeralPublicKey);
            byte[] nonceHash             = Keccak.Compute(Bytes.Concat(handshake.RecipientNonce, handshake.InitiatorNonce)).Bytes;
            byte[] sharedSecret          = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, nonceHash)).Bytes;
            byte[] token     = Keccak.Compute(sharedSecret).Bytes;
            byte[] aesSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, sharedSecret)).Bytes;
            Array.Clear(sharedSecret, 0, sharedSecret.Length);                   // TODO: it was passed in the concat for Keccak so not good enough
            byte[] macSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, aesSecret)).Bytes;
            Array.Clear(ephemeralSharedSecret, 0, ephemeralSharedSecret.Length); // TODO: it was passed in the concat for Keccak so not good enough
            handshake.Secrets           = new EncryptionSecrets();
            handshake.Secrets.Token     = token;
            handshake.Secrets.AesSecret = aesSecret;
            handshake.Secrets.MacSecret = macSecret;

            KeccakDigest mac1 = new KeccakDigest(MacBitsSize);

            mac1.BlockUpdate(macSecret.Xor(handshake.RecipientNonce), 0, macSecret.Length);
            mac1.BlockUpdate(handshake.AuthPacket.Data, 0, handshake.AuthPacket.Data.Length);

            KeccakDigest mac2 = new KeccakDigest(MacBitsSize);

            mac2.BlockUpdate(macSecret.Xor(handshake.InitiatorNonce), 0, macSecret.Length);
            mac2.BlockUpdate(handshake.AckPacket.Data, 0, handshake.AckPacket.Data.Length);

            if (encryptionHandshakeRole == EncryptionHandshakeRole.Initiator)
            {
                handshake.Secrets.EgressMac  = mac1;
                handshake.Secrets.IngressMac = mac2;
            }
            else
            {
                handshake.Secrets.EgressMac  = mac2;
                handshake.Secrets.IngressMac = mac1;
            }

            _logger.Info($"Agreed secrets with {handshake.RemoteNodeId}");
            #if DEBUG
            if (_logger.IsDebugEnabled)
            {
                _logger.Debug($"{handshake.RemoteNodeId} ephemeral private key {handshake.EphemeralPrivateKey}");
                _logger.Debug($"{handshake.RemoteNodeId} initiator nonce {new Hex(handshake.InitiatorNonce)}");
                _logger.Debug($"{handshake.RemoteNodeId} recipient nonce {new Hex(handshake.RecipientNonce)}");
                _logger.Debug($"{handshake.RemoteNodeId} remote ephemeral public key {handshake.RemoteEphemeralPublicKey}");
                _logger.Debug($"{handshake.RemoteNodeId} remote public key {handshake.RemoteNodeId}");
                _logger.Debug($"{handshake.RemoteNodeId} auth packet {new Hex(handshake.AuthPacket.Data)}");
                _logger.Debug($"{handshake.RemoteNodeId} ack packet {new Hex(handshake.AckPacket.Data)}");
            }
            #endif
        }
Example #3
0
 public NettyHandshakeHandler(
     IEncryptionHandshakeService service,
     IP2PSession p2PSession,
     EncryptionHandshakeRole role,
     NodeId remoteId,
     ILogger logger)
 {
     _handshake.RemoteNodeId = remoteId;
     _role                 = role;
     _remoteId             = remoteId;
     _logger               = logger;
     _service              = service;
     _p2PSession           = p2PSession;
     _initCompletionSource = new TaskCompletionSource <object>();
 }