-
Notifications
You must be signed in to change notification settings - Fork 0
/
pymd5.py
337 lines (280 loc) · 11.6 KB
/
pymd5.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
#!/usr/bin/python
#
# Derived from:
#
# MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
#
# Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
# rights reserved.
#
# License to copy and use this software is granted provided that it
# is identified as the "RSA Data Security, Inc. MD5 Message-Digest
# Algorithm" in all material mentioning or referencing this software
# or this function.
#
# License is also granted to make and use derivative works provided
# that such works are identified as "derived from the RSA Data
# Security, Inc. MD5 Message-Digest Algorithm" in all material
# mentioning or referencing the derived work.
#
# RSA Data Security, Inc. makes no representations concerning either
# the merchantability of this software or the suitability of this
# software for any particular purpose. It is provided "as is"
# without express or implied warranty of any kind.
#
# These notices must be retained in any copies of any part of this
# documentation and/or software.
__doc__ = """pymd5 module - The MD5 hash function in pure Python.
md5(string='', state=None, count=0) - Returns a new md5 objects and
processes string. Optional advanced parameters allow you to
resume an earlier computation by setting the internal state of
the function and the counter of message bits processed so far.
Most of the interface matches Python's standard hashlib.
md5 objects have these methods and attributes:
- update(arg): Update the md5 object with the string arg. Repeated calls
are equivalent to a single call with the concatenation of all
the arguments.
- digest(): Return the digest of the strings passed to the update() method
so far. This may contain non-ASCII characters, including
NUL bytes.
- hexdigest(): Like digest() except the digest is returned as a string of
double length, containing only hexadecimal digits.
- digest_size: The size of the resulting hash in bytes (16).
- block_size: The internal block size of the hash algorithm in bytes (64).
For example, to obtain the digest of the string 'Nobody inspects the
spammish repetition':
>>> import pymd5
>>> m = pymd5.md5()
>>> m.update("Nobody inspects")
>>> m.update(" the spammish repetition")
>>> m.digest()
More condensed:
>>> pymd5.md5("Nobody inspects the spammish repetition").hexdigest()
'bb649c83dd1ea5c9d9dec9a18df0ffe9'
The module also exposes two low-level methods to help with crypto
experiments:
- md5_compress(state, block): The MD5 compression function; returns a
new 16-byte state based on the 16-byte
previous state and a 512-byte message
block.
- padding(msg_bits): Generate the padding that should be appended
to the end of a message of the given size to
reach a multiple of the block size.
"""
# Constants for compression function.
S11 = 7
S12 = 12
S13 = 17
S14 = 22
S21 = 5
S22 = 9
S23 = 14
S24 = 20
S31 = 4
S32 = 11
S33 = 16
S34 = 23
S41 = 6
S42 = 10
S43 = 15
S44 = 21
PADDING = "\x80" + 63*"\0"
# F, G, H and I: basic MD5 functions.
def F(x, y, z): return (((x) & (y)) | ((~x) & (z)))
def G(x, y, z): return (((x) & (z)) | ((y) & (~z)))
def H(x, y, z): return ((x) ^ (y) ^ (z))
def I(x, y, z): return((y) ^ ((x) | (~z)))
def ROTATE_LEFT(x, n):
x = x & 0xffffffffL # make shift unsigned
return (((x) << (n)) | ((x) >> (32-(n)))) & 0xffffffffL
# FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
# Rotation is separate from addition to prevent recomputation.
def FF(a, b, c, d, x, s, ac):
a = a + F ((b), (c), (d)) + (x) + (ac)
a = ROTATE_LEFT ((a), (s))
a = a + b
return a # must assign this to a
def GG(a, b, c, d, x, s, ac):
a = a + G ((b), (c), (d)) + (x) + (ac)
a = ROTATE_LEFT ((a), (s))
a = a + b
return a # must assign this to a
def HH(a, b, c, d, x, s, ac):
a = a + H ((b), (c), (d)) + (x) + (ac)
a = ROTATE_LEFT ((a), (s))
a = a + b
return a # must assign this to a
def II(a, b, c, d, x, s, ac):
a = a + I ((b), (c), (d)) + (x) + (ac)
a = ROTATE_LEFT ((a), (s))
a = a + b
return a # must assign this to a
class md5(object):
digest_size = 16 # size of the resulting hash in bytes
block_size = 64 # hash algorithm's internal block size
def __init__(self, string='', state=None, count=0):
"""md5(string='', state=None, count=0) - Return a new md5
hash object, optionally initialized to a given internal state
and count of message bits processed so far, then processes
string.
"""
self.count = 0L
self.buffer = ""
if state is None:
# initial state defined by standard
self.state = (0x67452301L,
0xefcdab89L,
0x98badcfeL,
0x10325476L,)
else:
self.state = _decode(state, md5.digest_size)
if count is not None:
self.count = count
if string:
self.update(string)
def update(self, input):
"""update(input) - Update the md5 object with the string
arg. Repeated calls are equivalent to a single call with the
concatenation of all the arguments.
"""
inputLen = len(input)
index = int(self.count >> 3) & 0x3F
self.count = self.count + (inputLen << 3) # update number of bits
partLen = md5.block_size - index
# apply compression function to as many blocks as we have
if inputLen >= partLen:
self.buffer = self.buffer[:index] + input[:partLen]
self.state = md5_compress(self.state, self.buffer)
i = partLen
while i + 63 < inputLen:
self.state = md5_compress(self.state, input[i:i+md5.block_size])
i = i + md5.block_size
index = 0
else:
i = 0
# buffer remaining output
self.buffer = self.buffer[:index] + input[i:inputLen]
def digest(self):
"""digest() - Return the MD5 hash of the strings passed to the
update() method so far. This is a string of digest_size bytes
which may contain non-ASCII characters, including null bytes.
"""
_buffer, _count, _state = self.buffer, self.count, self.state
self.update(padding(self.count))
result = self.state
self.buffer, self.count, self.state = _buffer, _count, _state
return _encode(result, md5.digest_size)
def hexdigest(self):
"""hexdigest() - Like digest() except the hash value is
returned as a string of hexadecimal digits.
"""
return self.digest().encode("hex")
## end of class
def padding(msg_bits):
"""padding(msg_bits) - Generates the padding that should be
appended to the end of a message of the given size to reach
a multiple of the block size."""
index = int((msg_bits >> 3) & 0x3f)
if index < 56:
padLen = (56 - index)
else:
padLen = (120 - index)
# (the last 8 bytes store the number of bits in the message)
return PADDING[:padLen] + _encode((msg_bits & 0xffffffffL, msg_bits>>32), 8)
def md5_compress(state, block):
"""md5_compress(state, block) - The MD5 compression function.
Outputs a 16-byte state based on a 16-byte previous state and a
512-byte message block.
"""
a, b, c, d = state
x = _decode(block, md5.block_size)
# Round
a = FF (a, b, c, d, x[ 0], S11, 0xd76aa478) # 1
d = FF (d, a, b, c, x[ 1], S12, 0xe8c7b756) # 2
c = FF (c, d, a, b, x[ 2], S13, 0x242070db) # 3
b = FF (b, c, d, a, x[ 3], S14, 0xc1bdceee) # 4
a = FF (a, b, c, d, x[ 4], S11, 0xf57c0faf) # 5
d = FF (d, a, b, c, x[ 5], S12, 0x4787c62a) # 6
c = FF (c, d, a, b, x[ 6], S13, 0xa8304613) # 7
b = FF (b, c, d, a, x[ 7], S14, 0xfd469501) # 8
a = FF (a, b, c, d, x[ 8], S11, 0x698098d8) # 9
d = FF (d, a, b, c, x[ 9], S12, 0x8b44f7af) # 10
c = FF (c, d, a, b, x[10], S13, 0xffff5bb1) # 11
b = FF (b, c, d, a, x[11], S14, 0x895cd7be) # 12
a = FF (a, b, c, d, x[12], S11, 0x6b901122) # 13
d = FF (d, a, b, c, x[13], S12, 0xfd987193) # 14
c = FF (c, d, a, b, x[14], S13, 0xa679438e) # 15
b = FF (b, c, d, a, x[15], S14, 0x49b40821) # 16
# Round 2
a = GG (a, b, c, d, x[ 1], S21, 0xf61e2562) # 17
d = GG (d, a, b, c, x[ 6], S22, 0xc040b340) # 18
c = GG (c, d, a, b, x[11], S23, 0x265e5a51) # 19
b = GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa) # 20
a = GG (a, b, c, d, x[ 5], S21, 0xd62f105d) # 21
d = GG (d, a, b, c, x[10], S22, 0x2441453) # 22
c = GG (c, d, a, b, x[15], S23, 0xd8a1e681) # 23
b = GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8) # 24
a = GG (a, b, c, d, x[ 9], S21, 0x21e1cde6) # 25
d = GG (d, a, b, c, x[14], S22, 0xc33707d6) # 26
c = GG (c, d, a, b, x[ 3], S23, 0xf4d50d87) # 27
b = GG (b, c, d, a, x[ 8], S24, 0x455a14ed) # 28
a = GG (a, b, c, d, x[13], S21, 0xa9e3e905) # 29
d = GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8) # 30
c = GG (c, d, a, b, x[ 7], S23, 0x676f02d9) # 31
b = GG (b, c, d, a, x[12], S24, 0x8d2a4c8a) # 32
# Round 3
a = HH (a, b, c, d, x[ 5], S31, 0xfffa3942) # 33
d = HH (d, a, b, c, x[ 8], S32, 0x8771f681) # 34
c = HH (c, d, a, b, x[11], S33, 0x6d9d6122) # 35
b = HH (b, c, d, a, x[14], S34, 0xfde5380c) # 36
a = HH (a, b, c, d, x[ 1], S31, 0xa4beea44) # 37
d = HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9) # 38
c = HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60) # 39
b = HH (b, c, d, a, x[10], S34, 0xbebfbc70) # 40
a = HH (a, b, c, d, x[13], S31, 0x289b7ec6) # 41
d = HH (d, a, b, c, x[ 0], S32, 0xeaa127fa) # 42
c = HH (c, d, a, b, x[ 3], S33, 0xd4ef3085) # 43
b = HH (b, c, d, a, x[ 6], S34, 0x4881d05) # 44
a = HH (a, b, c, d, x[ 9], S31, 0xd9d4d039) # 45
d = HH (d, a, b, c, x[12], S32, 0xe6db99e5) # 46
c = HH (c, d, a, b, x[15], S33, 0x1fa27cf8) # 47
b = HH (b, c, d, a, x[ 2], S34, 0xc4ac5665) # 48
# Round 4
a = II (a, b, c, d, x[ 0], S41, 0xf4292244) # 49
d = II (d, a, b, c, x[ 7], S42, 0x432aff97) # 50
c = II (c, d, a, b, x[14], S43, 0xab9423a7) # 51
b = II (b, c, d, a, x[ 5], S44, 0xfc93a039) # 52
a = II (a, b, c, d, x[12], S41, 0x655b59c3) # 53
d = II (d, a, b, c, x[ 3], S42, 0x8f0ccc92) # 54
c = II (c, d, a, b, x[10], S43, 0xffeff47d) # 55
b = II (b, c, d, a, x[ 1], S44, 0x85845dd1) # 56
a = II (a, b, c, d, x[ 8], S41, 0x6fa87e4f) # 57
d = II (d, a, b, c, x[15], S42, 0xfe2ce6e0) # 58
c = II (c, d, a, b, x[ 6], S43, 0xa3014314) # 59
b = II (b, c, d, a, x[13], S44, 0x4e0811a1) # 60
a = II (a, b, c, d, x[ 4], S41, 0xf7537e82) # 61
d = II (d, a, b, c, x[11], S42, 0xbd3af235) # 62
c = II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb) # 63
b = II (b, c, d, a, x[ 9], S44, 0xeb86d391) # 64
return (0xffffffffL & (state[0] + a),
0xffffffffL & (state[1] + b),
0xffffffffL & (state[2] + c),
0xffffffffL & (state[3] + d),)
import struct, string
def _encode(input, len):
k = len >> 2
res = apply(struct.pack, ("%iI" % k,) + tuple(input[:k]))
return string.join(res, "")
def _decode(input, len):
k = len >> 2
res = struct.unpack("%iI" % k, input[:len])
return list(res)
def test(input=""):
"""test(input): displays results of input hashed with our md5
function and the standard Python hashlib implementation
"""
print `md5(input).hexdigest()`
import hashlib
print `hashlib.md5(input).hexdigest()`
if __name__=="__main__":
test("crypt")