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