--- /dev/null
+"""\r
+Challenge-Response authentication algorithm over channels: the client sends the\r
+username, recvs a challenge, generates a response based on the challenge and \r
+password, sends it back to the server, which also calculates the expected response.\r
+the server returns "WRONG" or "OKAY". this way the password is never sent over\r
+the wire.\r
+\r
+* servers should call the accept function over a channel, with a dict of \r
+(username, password) pairs.\r
+* clients should call login over a channel, with the username and password\r
+"""\r
+import md5\r
+import random\r
+\r
+def get_bytes(num_bytes):\r
+ ret = []\r
+ for n in xrange(num_bytes):\r
+ ret.append( chr(random.randint(0,255)) )\r
+ return ''.join(ret)\r
+\r
+def accept(chan, users):\r
+ username = chan.recv()\r
+ challenge = get_bytes(16)\r
+ chan.send(challenge)\r
+ response = chan.recv()\r
+ if username not in users:\r
+ chan.send("WRONG")\r
+ return False\r
+ expected_response = md5.new(users[username] + challenge).digest()\r
+ if response != expected_response:\r
+ chan.send("WRONG")\r
+ return False\r
+ chan.send("OKAY")\r
+ return True\r
+\r
+def login(chan, username, password):\r
+ chan.send(username)\r
+ challenge = chan.recv()\r
+ response = md5.new(password + challenge).digest()\r
+ chan.send(response)\r
+ return chan.recv() == "OKAY"\r
+\r