/// <summary> /// is executed by receiver thread /// </summary> void ProcessRegisterPow1RequestPacket(IPEndPoint requesterEndpoint, byte[] udpData) { var packet = new RegisterPow1RequestPacket(udpData); if (!PassPow1filter(requesterEndpoint, packet)) { if (Configuration.VisionChannel?.GetAttentionTo(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide) <= AttentionLevel.needsAttention) { Configuration.VisionChannel?.Emit(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide, AttentionLevel.needsAttention, $"pow1 filter rejected request from {requesterEndpoint}"); } return; } // create Pow2 request state var pow2RequestState = _pow2RequestsTable.GenerateOrGetExistingPow2(requesterEndpoint); var response = new RegisterPow1ResponsePacket { ProofOfWork2Request = pow2RequestState.ProofOfWork2Request, StatusCode = RegisterPow1ResponseStatusCode.succeeded_Pow2Challenge, Pow1RequestId = packet.Pow1RequestId }; SendPacket(response.Encode(), requesterEndpoint); }
/// <summary> /// performs PoW#1 (stateless proof of work) /// </summary> RegisterPow1RequestPacket GenerateRegisterPow1RequestPacket(byte[] clientPublicIp, uint timeSec32UTC) { var packet = new RegisterPow1RequestPacket(); packet.Timestamp32S = timeSec32UTC; packet.ProofOfWork1 = new byte[64]; var rnd = new Random(_insecureRandom.Next()); for (; ;) { rnd.NextBytes(packet.ProofOfWork1); if (Pow1IsOK(packet, clientPublicIp)) { break; } } packet.Pow1RequestId = (uint)rnd.Next(); return(packet); }
bool Pow1IsOK(RegisterPow1RequestPacket packet, byte[] clientPublicIP) { var ms = new MemoryStream(sizeof(uint) + packet.ProofOfWork1.Length + clientPublicIP.Length); using (var writer = new BinaryWriter(ms)) { writer.Write(packet.Timestamp32S); writer.Write(packet.ProofOfWork1); writer.Write(clientPublicIP); ms.Position = 0; var hash = _cryptoLibrary.GetHashSHA512(ms); if (hash[4] != 7 || (hash[5] != 7 && hash[5] != 8)) { return(false); } else { return(true); } } }
/// <summary> /// sends responses /// executed by receiver thread /// </summary> bool PassPow1filter(IPEndPoint requesterEndpoint, RegisterPow1RequestPacket packet) { // verify size of Pow1 data if (packet.ProofOfWork1.Length != 64) { if (Configuration.VisionChannel?.GetAttentionTo(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide) <= AttentionLevel.needsAttention) { Configuration.VisionChannel?.Emit(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide, AttentionLevel.needsAttention, $"pow1 filter rejected request from {requesterEndpoint}: invalid pow1 length"); } return(false); } var localTimeSec32 = Timestamp32S; var timeDifferenceSec = Math.Abs((int)unchecked (localTimeSec32 - packet.Timestamp32S)); if (timeDifferenceSec > Configuration.RegisterPow1_MaxTimeDifferenceS) { if (Configuration.VisionChannel?.GetAttentionTo(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide) <= AttentionLevel.needsAttention) { Configuration.VisionChannel?.Emit(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide, AttentionLevel.needsAttention, $"pow1 filter rejected request from {requesterEndpoint}: invalid timestamp"); } // respond with error "try again with valid clock" - legitimate user has to get valid clock from some time server and synchronize itself with the server if (Configuration.RespondToRegisterPow1Errors) { RespondToRegisterPow1withError(requesterEndpoint, RegisterPow1ResponseStatusCode.rejected_badtimestamp, packet.Pow1RequestId); } return(false); } if (!Pow1IsOK(packet, requesterEndpoint.Address.GetAddressBytes())) { if (Configuration.VisionChannel?.GetAttentionTo(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide) <= AttentionLevel.needsAttention) { Configuration.VisionChannel?.Emit(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide, AttentionLevel.needsAttention, $"pow1 filter rejected request from {requesterEndpoint}: invalid pow1"); } OnReceivedBadRegisterReqPow1(requesterEndpoint); // no response return(false); } if (_recentUniquePow1Data != null) { // check if pow1 data is unique var dataIsUnique = _recentUniquePow1Data.TryInputData(packet.ProofOfWork1, localTimeSec32); if (dataIsUnique) { return(true); } else { if (Configuration.VisionChannel?.GetAttentionTo(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide) <= AttentionLevel.needsAttention) { Configuration.VisionChannel?.Emit(Configuration.VisionChannelSourceId, VisionChannelModuleName_reg_epSide, AttentionLevel.needsAttention, $"pow1 filter rejected request from {requesterEndpoint}: pow1 data is not unique"); } // respond with error "try again with unique PoW data" if (Configuration.RespondToRegisterPow1Errors) { RespondToRegisterPow1withError(requesterEndpoint, RegisterPow1ResponseStatusCode.rejected_tryagainRightNowWithThisServer, packet.Pow1RequestId); } return(false); } } return(true); }