Live data from Hacker News

UDP for games – encryption and DDoS protection

ithare.com

31–40 of 47 posts

Re: UDP for games – encryption and DDoS protection

#31
post #21

If you encode each packet in a QUIC stream with it's own stream ID, and close QUIC streams after a timeout, you can use QUIC for unreliable unordered transports as well.

Good idea, THANKS A LOT! It has crossed my mind too, but I've discarded without giving it enough thought. The reason why it MIGHT work, is because of the implicit stream creation in QUIC (no handshake, nothing, just single UDP packet). There will still be some overhead, but probably it won't be "too bad".

Re: UDP for games – encryption and DDoS protection

#32
post #17

Can someone please explain me as if I was 5 years old how the proof of work is performed ?

Like Bitcoin, you can ask clients to find a hash of a string (in the format of, say, 'server_key' + 'random_number' + 'client_adjusted_nonce') with the value of the last four bytes being higher than say 50,000. You can increase the value until 0xFFFFFFFE, where only 1 in 4294967296 hashes would 'pass' the test. Your client will basically be working on passing the test for a predictable amount of time, dependent on th…

Sorry, my age may be lower than five. I don't understand. You explain that a hash is computed over a string that is the concatenation of a server key, a random number and a client adjusted nonce. you then lost me with the four bytes. I thought that we were talking about a string of chars, not an array of bytes. The nonce is an integer value ? The client then increases the nonce value I guess. But how does the client know it has finished the work ? In the article it is said that the hash value should start with a number of 0 bits. But this occurence is random by definition of the hash. It could never occur with the nonce tested. So sorry, I still don't understand it.

Re: UDP for games – encryption and DDoS protection

#33
post #32

Earlier quoted context omitted.

Like Bitcoin, you can ask clients to find a hash of a string (in the format of, say, 'server_key' + 'random_number' + 'client_adjusted_nonce') with the value of the last four bytes being higher than say 50,000. You can increase the value until 0xFFFFFFFE, where only 1 in 4294967296 hashes would 'pass' the test. Your client will basically be working on passing the test for a predictable amount of time, dependent on th…

Sorry, my age may be lower than five. I don't understand. You explain that a hash is computed over a string that is the concatenation of a server key, a random number and a client adjusted nonce. you then lost me with the four bytes. I thought that we were talking about a string of chars, not an array of bytes. The nonce is an integer value ? The client then increases the nonce value I guess. But how does the client…

> The nonce is an integer value?

An array of bytes is an integer value - just an arbitrarily large one. You could also just tack the bytes of a 64-bit uint onto the end of the nonce instead of incrementing the nonce (I'm not sure if that is secure, it's just an explanation).

A real example of this is RSA. The length of the key is in bits (and therefore bytes) but is still a representation of a really big integer.

> how does the client know it has finished the work ?

Let's remove hashing from the equation. I, as the server, say to you I've got the following equation:

    Y = (5 + X) * 10
Please solve it so that the last 3 digits of Y are greater than 100 and tell me what you used for X. The simplicity of this equation means that you can easily solve for Y and respond with `12335`. With that response I can just plug X into the equation and see that you've done the work. Now, imagine that there is no such thing as division. Being unable to solve the equation, you'd be forced to brute force each value of X - but proving that you've found X only requires that you run the equation once because we can still multiply:

    Y = (5 + 12335) * 10
With POW, you say that you are looking for a specific pattern of bits or bytes. The pattern can be quite arbitrary: "I want the last 8 bytes to be a 64-bit integer larger than 12345" or even just "the last 64 bits must all be 0." The client will have to try multiple values of X to see which satisfies that constraint. Once the client knows X you no longer need to go through the effort of finding out the value for yourself, you just need to plug X into the equation and see that they found a valid value for X:

    POW = HASH(NONCE & X)
It's like salting a password, but requiring that a portion of the final result has a specific pattern. This forces the client to do a lot of work in a way that is cheap to verify from a computational standpoint.

Re: UDP for games – encryption and DDoS protection

#34
post #32

Earlier quoted context omitted.

Like Bitcoin, you can ask clients to find a hash of a string (in the format of, say, 'server_key' + 'random_number' + 'client_adjusted_nonce') with the value of the last four bytes being higher than say 50,000. You can increase the value until 0xFFFFFFFE, where only 1 in 4294967296 hashes would 'pass' the test. Your client will basically be working on passing the test for a predictable amount of time, dependent on th…

Sorry, my age may be lower than five. I don't understand. You explain that a hash is computed over a string that is the concatenation of a server key, a random number and a client adjusted nonce. you then lost me with the four bytes. I thought that we were talking about a string of chars, not an array of bytes. The nonce is an integer value ? The client then increases the nonce value I guess. But how does the client…

The basic idea is: The client has to create a hash that satisfies a certain condition: Like the first n-digits must be 0, or maybe "the last bytes (when interpreted as a single 32 number) must be larger than x".

So the client does this:

    from itertools import count
    import hashlib

    for i in count():
        h = hashlib.md5("some-nonce:%d" % i).hexdigest()
        if h.startswith("000000"):
            print i
            break
The value "some-nonce" is provided by the server. It also provides the difficulty by saying: I need you to find i which generates a hash that starts with 6 zeros.

So the client calculates hashes for a while, and then submits the value 2652076 to the server. The server can the trivially check if the client did its work correctly:

    $ echo -en "some-nonce:2652076" | md5sum
    00000066adb2fb37a8460da553721c39 # ok, the first 6 digits are 0
The server can simply increase the difficulty by requiring the client to return more leading zeros. Or, if it should be more finegrained, a value below a certain threshold.

Re: UDP for games – encryption and DDoS protection

#35
post #28

>As a side bonus, with proper encryption you can be sure that network errors which corrupt your packets are not going undetected Shouldn't you be verifying a MAC before decrypting anyways? Relying on decrypting scrambled data, especially for a bitflip, seems like a bad idea. >Potential attack here is about attacker modifying the (unencrypted/unsigned) data coming to the victim’s Client, So establish a session key, an…

BTW, when I've wrote about those "undetected network errors", I've meant those-network-errors-which-arise-in-UNENCRYPTED-packets (as 16-bit UDP checksum is certainly not enough for this purpose). And DTLS etc. take care of packet corruption themselves (actually, they consider it an attack).

The UDP checksum is twice unreliable since it's optional.

Re: UDP for games – encryption and DDoS protection

#37
post #18
post #10

Earlier quoted context omitted.

Here's a really simple proof of work system: during connection, the server tells the client some randomly generated bytes and a number of bits, and then the client has to come up with a string whose MD5 hash (or whatever algorithm you want to use) has its first N bits match the first N bits of the bytestring that the server gave. It's easy for the server to adjust the difficulty of the proof-of-work: it just needs to…

How is the client expected to proceed ? Should it try a,b, ... aa, ab, ... ? Couldn't a rainbow table allow to cheat with such algorithm ? It seam that the computation of a MAC or an encryption where the key serves as salt could prevent such cheating. But this computations are now hardcoded in the cpu which won't be the same proof of work for everybody.

Its not possible to maintain a rainbow table because the server would specify the string to start with.

Server sends "randomstringthatalsoreferencescurrenttime"

Client needs to add strings to this such that the MD5 hash of the result has the first N bits as 0 where N specifies the difficulty. The client is expected to send what it added to the server's string and the server verifies the proof of work.

Re: UDP for games – encryption and DDoS protection

#38
post #28

Earlier quoted context omitted.

BTW, when I've wrote about those "undetected network errors", I've meant those-network-errors-which-arise-in-UNENCRYPTED-packets (as 16-bit UDP checksum is certainly not enough for this purpose). And DTLS etc. take care of packet corruption themselves (actually, they consider it an attack).

The UDP checksum is twice unreliable since it's optional.

Since IPv6 it is mandatory, but it still sucks :-(

Re: UDP for games – encryption and DDoS protection

#39
post #32

Earlier quoted context omitted.

Sorry, my age may be lower than five. I don't understand. You explain that a hash is computed over a string that is the concatenation of a server key, a random number and a client adjusted nonce. you then lost me with the four bytes. I thought that we were talking about a string of chars, not an array of bytes. The nonce is an integer value ? The client then increases the nonce value I guess. But how does the client…

The basic idea is: The client has to create a hash that satisfies a certain condition: Like the first n-digits must be 0, or maybe "the last bytes (when interpreted as a single 32 number) must be larger than x". So the client does this: from itertools import count import hashlib for i in count(): h = hashlib.md5("some-nonce:%d" % i).hexdigest() if h.startswith("000000"): print i break The value "some-nonce" is provid…

Your explanation is fine but this summary will confuse people:

> The client has to create a hash that satisfies a certain condition

What you really want is to create a string whose hash matches the PoW challenge hash.

Post reply on HN