internal static bool TrySolve(ulong challenge, byte difficulty, ulong maxIterations, out ulong additionsRequired)
        {
            additionsRequired = 0;
            ulong iterations   = 0;
            ulong workingValue = HashProvider.GetStableHash64(challenge + additionsRequired);

            while (difficulty > 0 && ((workingValue << ((sizeof(ulong) * 8) - difficulty)) >> ((sizeof(ulong) * 8) - difficulty)) != 0 && iterations < maxIterations)
            {
                ++iterations;
                ++additionsRequired;
                workingValue = HashProvider.GetStableHash64(challenge + additionsRequired);
            }

            return(Validate(challenge, additionsRequired, difficulty));
        }
예제 #2
0
        internal void HandleChallengeRequest(ulong challenge, byte difficulty)
        {
            _stateLock.EnterReadLock();

            try
            {
                if (State == ConnectionState.RequestingConnection)
                {
                    LastMessageIn = NetTime.Now;

                    ulong additionsRequired = 0;
                    ulong workingValue      = challenge;

                    // Solve the hashcash
                    // TODO: Solve thread
                    while (difficulty > 0 && ((workingValue << ((sizeof(ulong) * 8) - difficulty)) >> ((sizeof(ulong) * 8) - difficulty)) != 0)
                    {
                        additionsRequired++;
                        workingValue = HashProvider.GetStableHash64(challenge + additionsRequired);
                    }

                    ConnectionChallenge = challenge;
                    ChallengeDifficulty = difficulty;
                    ChallengeAnswer     = additionsRequired;

                    // Set resend values
                    HandshakeResendAttempts = 0;
                    HandshakeStarted        = NetTime.Now;
                    HandshakeLastSendTime   = NetTime.Now;
                    State = ConnectionState.SolvingChallenge;

                    // Send the response
                    SendChallengeResponse();
                }
            }
            finally
            {
                _stateLock.ExitReadLock();
            }
        }
예제 #3
0
        private void CheckConnectionResends()
        {
            _stateLock.EnterReadLock();

            try
            {
                switch (State)
                {
                case ConnectionState.RequestingConnection:
                {
                    if ((!Config.TimeBasedConnectionChallenge || PreConnectionChallengeSolved) && (NetTime.Now - HandshakeLastSendTime).TotalMilliseconds > Config.ConnectionRequestMinResendDelay && HandshakeResendAttempts <= Config.MaxConnectionRequestResends)
                    {
                        HandshakeResendAttempts++;
                        HandshakeLastSendTime = NetTime.Now;

                        // Calculate the minimum size we can fit the packet in
                        int minSize = 1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (Config.TimeBasedConnectionChallenge ? sizeof(ulong) * 3 : 0);

                        // Calculate the actual size with respect to amplification padding
                        int size = Math.Max(minSize, (int)Config.AmplificationPreventionHandshakePadding);

                        // Allocate memory
                        HeapMemory memory = MemoryManager.AllocHeapMemory((uint)size);

                        // Write the header
                        memory.Buffer[0] = HeaderPacker.Pack((byte)MessageType.ConnectionRequest);

                        // Copy the identification token
                        Buffer.BlockCopy(Constants.RUFFLES_PROTOCOL_IDENTIFICATION, 0, memory.Buffer, 1, Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length);

                        if (Config.TimeBasedConnectionChallenge)
                        {
                            // Write the response unix time
                            for (byte x = 0; x < sizeof(ulong); x++)
                            {
                                memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + x] = ((byte)(PreConnectionChallengeTimestamp >> (x * 8)));
                            }

                            // Write counter
                            for (byte x = 0; x < sizeof(ulong); x++)
                            {
                                memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + sizeof(ulong) + x] = ((byte)(PreConnectionChallengeCounter >> (x * 8)));
                            }

                            // Write IV
                            for (byte x = 0; x < sizeof(ulong); x++)
                            {
                                memory.Buffer[1 + Constants.RUFFLES_PROTOCOL_IDENTIFICATION.Length + (sizeof(ulong) * 2) + x] = ((byte)(PreConnectionChallengeIV >> (x * 8)));
                            }

                            // Print debug
                            if (Logging.CurrentLogLevel <= LogLevel.Debug)
                            {
                                Logging.LogInfo("Resending ConnectionRequest with challenge [Counter=" + PreConnectionChallengeCounter + "] [IV=" + PreConnectionChallengeIV + "] [Time=" + PreConnectionChallengeTimestamp + "] [Hash=" + HashProvider.GetStableHash64(PreConnectionChallengeTimestamp, PreConnectionChallengeCounter, PreConnectionChallengeIV) + "]");
                            }
                        }
                        else
                        {
                            // Print debug
                            if (Logging.CurrentLogLevel <= LogLevel.Debug)
                            {
                                Logging.LogInfo("Resending ConnectionRequest");
                            }
                        }

                        SendInternal(new ArraySegment <byte>(memory.Buffer, 0, (int)memory.VirtualCount), true);

                        // Release memory
                        MemoryManager.DeAlloc(memory);
                    }
                }
                break;

                case ConnectionState.RequestingChallenge:
                {
                    if ((NetTime.Now - HandshakeLastSendTime).TotalMilliseconds > Config.HandshakeResendDelay && HandshakeResendAttempts <= Config.MaxHandshakeResends)
                    {
                        // Resend challenge request
                        SendChallengeRequest();
                    }
                }
                break;

                case ConnectionState.SolvingChallenge:
                {
                    if ((NetTime.Now - HandshakeLastSendTime).TotalMilliseconds > Config.HandshakeResendDelay && HandshakeResendAttempts <= Config.MaxHandshakeResends)
                    {
                        // Resend response
                        SendChallengeResponse();
                    }
                }
                break;

                case ConnectionState.Connected:
                {
                    if (!HailStatus.HasAcked && (NetTime.Now - HailStatus.LastAttempt).TotalMilliseconds > Config.HandshakeResendDelay && HailStatus.Attempts <= Config.MaxHandshakeResends)
                    {
                        // Resend hail
                        SendHail();
                    }
                }
                break;
                }
            }
            finally
            {
                _stateLock.ExitReadLock();
            }
        }
 internal static bool Validate(ulong challenge, ulong additionsRequired, byte difficulty)
 {
     return(difficulty == 0 || ((HashProvider.GetStableHash64(challenge + additionsRequired) << ((sizeof(ulong) * 8) - difficulty)) >> ((sizeof(ulong) * 8) - difficulty)) == 0);
 }
예제 #5
0
        internal void HandleChallengeResponse(ulong proposedSolution)
        {
            _stateLock.EnterUpgradeableReadLock();

            try
            {
                if (State == ConnectionState.RequestingChallenge)
                {
                    ulong claimedCollision = ConnectionChallenge + proposedSolution;

                    // Check if it is solved
                    bool isCollided = ChallengeDifficulty == 0 || ((HashProvider.GetStableHash64(claimedCollision) << ((sizeof(ulong) * 8) - ChallengeDifficulty)) >> ((sizeof(ulong) * 8) - ChallengeDifficulty)) == 0;

                    if (isCollided)
                    {
                        // Success, they completed the hashcash challenge

                        if (Logging.CurrentLogLevel <= LogLevel.Debug)
                        {
                            Logging.LogInfo("Client " + EndPoint + " successfully completed challenge of difficulty " + ChallengeDifficulty);
                        }

                        // Assign the channels
                        for (byte i = 0; i < Config.ChannelTypes.Length; i++)
                        {
                            Channels[i] = Socket.ChannelPool.GetChannel(Config.ChannelTypes[i], i, this, Config, MemoryManager);
                        }

                        // Reset hail status
                        HailStatus = new MessageStatus()
                        {
                            Attempts    = 0,
                            HasAcked    = false,
                            LastAttempt = NetTime.MinValue
                        };


                        _stateLock.EnterWriteLock();

                        try
                        {
                            // Change state to connected
                            State = ConnectionState.Connected;
                        }
                        finally
                        {
                            _stateLock.ExitWriteLock();
                        }

                        // Save time
                        ConnectionCompleted = NetTime.Now;

                        // Print connected
                        if (Logging.CurrentLogLevel <= LogLevel.Info)
                        {
                            Logging.LogInfo("Client " + EndPoint + " successfully connected");
                        }

                        // Send hail
                        SendHail();

                        // Send to userspace
                        Socket.PublishEvent(new NetworkEvent()
                        {
                            Connection        = this,
                            Socket            = Socket,
                            Type              = NetworkEventType.Connect,
                            AllowUserRecycle  = false,
                            ChannelId         = 0,
                            Data              = new ArraySegment <byte>(),
                            InternalMemory    = null,
                            SocketReceiveTime = NetTime.Now,
                            MemoryManager     = MemoryManager,
                            EndPoint          = EndPoint
                        });
                    }
                    else
                    {
                        // Failed, disconnect them
                        if (Logging.CurrentLogLevel <= LogLevel.Warning)
                        {
                            Logging.LogWarning("Client " + EndPoint + " failed the challenge");
                        }
                    }
                }
            }
            finally
            {
                _stateLock.ExitUpgradeableReadLock();
            }
        }