The md5 Module
The md5 module is used to calculate message signatures (message digests).
The md5 algorithm calculates a strong 128-bit signature. This means that if two strings are different, it's highly likely that their md5 signatures are different as well. To put it another way, given an md5 digest, it's supposed to be nearly impossible to come up with a string that generates that digest. Example 2-35 demonstrates the md5 module.
Example 2-35. Using the md5 Module
File: md5-example-1.py import md5 hash = md5.new() hash.update("spam, spam, and eggs") print repr(hash.digest()) 'L 05J243266355243u`305r203267 20F303'
Note that the checksum is returned as a binary string. Getting a hexadecimal or base64-encoded string is quite easy, though, as Example 2-36 shows.
Example 2-36. Using the md5 Module to Get a Hexadecimal or Base64-Encoded md5 Value
File: md5-example-2.py import md5 import string import base64 hash = md5.new() hash.update("spam, spam, and eggs") value = hash.digest() print string.join(map(lambda v: "%02x" % ord(v), value), "") # in 2.0, the above can be written as # print hash.hexdigest() print base64.encodestring(value) 4c054aa3b6eda37560c57283b71046c3 TAVKo7bto3VgxXKDtxBGww==
Example 2-37 shows how, among other things, the md5 checksum can be used for challenge-response authentication (but see the note on random numbers later).
Example 2-37. Using the md5 Module for Challenge-Response Authentication
File: md5-example-3.py import md5 import string, random def getchallenge(): # generate a 16-byte long random string. (note that the built- # in pseudo-random generator uses a 24-bit seed, so this is not # as good as it may seem...) challenge = map(lambda i: chr(random.randint(0, 255)), range(16)) return string.join(challenge, "") def getresponse(password, challenge): # calculate combined digest for password and challenge m = md5.new() m.update(password) m.update(challenge) return m.digest() # # server/client communication # 1. client connects. server issues challenge. print "client:", "connect" challenge = getchallenge() print "server:", repr(challenge) # 2. client combines password and challenge, and calculates # the response. client_response = getresponse("trustno1", challenge) print "client:", repr(client_response) # 3. server does the same, and compares the result with the # client response. the result is a safe login in which the # password is never sent across the communication channel. server_response = getresponse("trustno1", challenge) if server_response == client_response: print "server:", "login ok" client: connect server: '334352227Z#272273212KG330265 32>311o' client: "l'305240-x245237 35225A254233337225 01" server: login ok
Example 2-38 offers a variation of md5, which can be used to sign messages sent over a public network, so that their integrity can be verified at the receiving end.
Example 2-38. Using the md5 Module for Data Integrity Checks
File: md5-example-4.py import md5 import array class HMAC_MD5: # keyed md5 message authentication def _ _init_ _(self, key): if len(key) > 64: key = md5.new(key).digest() ipad = array.array("B", [0x36] * 64) opad = array.array("B", [0x5C] * 64) for i in range(len(key)): ipad[i] = ipad[i] ^ ord(key[i]) opad[i] = opad[i] ^ ord(key[i]) self.ipad = md5.md5(ipad.tostring()) self.opad = md5.md5(opad.tostring()) def digest(self, data): ipad = self.ipad.copy() opad = self.opad.copy() ipad.update(data) opad.update(ipad.digest()) return opad.digest() # # simulate server end key = "this should be a well-kept secret" message = open("samples/sample.txt").read() signature = HMAC_MD5(key).digest(message) # (send message and signature across a public network) # # simulate client end key = "this should be a well-kept secret" client_signature = HMAC_MD5(key).digest(message) if client_signature == signature: print "this is the original message:" print print message else: print "someone has modified the message!!!"
The copy method takes a snapshot of the internal object state. This allows you to precalculate partial digests (such as the padded key, in Example 2-38).
For details on this algorithm, see HMAC-MD5:Keyed-MD5 for Message Authentication (http://www.research.ibm.com/security/draft-ietf-ipsec-hmac-md5-00.txt) by Krawczyk, et al.
|