the task i am given is to win 50 times in a row with a self-written client against this RockPaperScissor-PythonServer
import SocketServer,threading,os,string
import random, time
f = open('secret.txt')
offset = int(f.readline().strip())
choices = {
'r': 'rock',
'p': 'paper',
's': 'scissors'
}
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
rnd = random.Random()
# Initialize the random number generator to some secret value
# Note: the value of offset is too big to guess/bruteforce you need to find a better way :)
rnd.seed(int(time.time() + offset))
self.request.sendall("Rock paper scissors is back\n")
win_count = 0
play_again = True
while play_again:
while win_count < 50:
self.request.sendall("choose one [r] rock, [p] paper, [s] scissors: ")
your_choice = self.request.recv(1024).strip()
if not your_choice in 'rps':
continue
self.request.sendall("Your choice %s\n" % choices.get(your_choice))
my_choice = rnd.choice("rps")
self.request.sendall("My choice %s\n" % choices.get(my_choice))
if my_choice == your_choice:
self.request.sendall("Its a tie, sorry you need to win 50 times in a row, a tie is simply not good enough.\nWho ever said life was fair?\n")
break
if ((my_choice == 'r' and your_choice == 'p') or
(my_choice == 'p' and your_choice == 's') or
(my_choice == 's' and your_choice == 'r')):
win_count += 1
self.request.sendall("Arghhh. you beat me %s times\n" % win_count)
else:
self.request.sendall("You loose!\n")
break
if win_count == 50:
self.request.sendall("50 times in a row?!? are you some kind of mind reader?\n")
return
else:
win_count = 0
answer = ''
while answer not in ('y','n'):
self.request.sendall("Play again? (y/n): ")
answer = self.request.recv(1024).strip().lower()
if answer == 'n':
return
SocketServer.TCPServer.allow_reuse_address = True
server = ThreadedTCPServer(("0.0.0.0", 1178), MyTCPHandler)
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
server.serve_forever()
I have read in the python random.py doc and on various sites that the core random number generator that pythons random class uses (MersenneTwister) is not appropriate for security-relevant things because it is predictable when an attacker manages to obtain 624 consecutive numbers.
I have already a client that plays 624 times rock and in each round detects the server choice, converts it to the respective array index in [rps] and writes that number to a file. So in the end theres a long file containing lots of 0's, 1's and 2's like this
0
1
0
2
2
0
....
The most important line in the server code for me is apparently
my_choice = rnd.choice("rps")
which is implemented as (extract from random.py):
def choice(self, seq):
"""Choose a random element from a non-empty sequence."""
return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
Here i read that in order to predict next numbers i need to record 624 consecutive numbers and restore the state by reversing / undoing certain transformations, however i think that the direct core rng output, which is a float between [0.0, 1.0), is required for that...
To get the core rng output from the sequence index it seems that i just have to exactly reverse the above code of the function "choice()", which would be something like
seq_value = seq[int(core_rng_out * len(seq))]
seq_index = int(core_rng_out * len(seq))
int^-1(seq_index) = core_rng_out * len(seq)
int^-1(seq_index) / len(seq) = core_rng_out
core_rng_out = int^-1(seq_index) / 3
The above is supposed to be something like resolving a math equation for a certain variable. Divided by 3 because the sequence is 3-sized ("rps"), however what is the inverse of pythons int(...) function?!? Above i tried to abstractly mark it as inverse by making it ^-1.
And furthermore is it even possible to get the rng float at all?!?, because in pythons int-doc it says when int(...) is given a float some truncation will/may happen...?!
Or this maybe a completely wrong approach and i can beat the server in an easier way?