github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/third_party/pypy/_md5.py (about) 1 #!/usr/bin/env python 2 # -*- coding: iso-8859-1 -*- 3 4 # Note that PyPy contains also a built-in module 'md5' which will hide 5 # this one if compiled in. 6 7 """A sample implementation of MD5 in pure Python. 8 9 This is an implementation of the MD5 hash function, as specified by 10 RFC 1321, in pure Python. It was implemented using Bruce Schneier's 11 excellent book "Applied Cryptography", 2nd ed., 1996. 12 13 Surely this is not meant to compete with the existing implementation 14 of the Python standard library (written in C). Rather, it should be 15 seen as a Python complement that is more readable than C and can be 16 used more conveniently for learning and experimenting purposes in 17 the field of cryptography. 18 19 This module tries very hard to follow the API of the existing Python 20 standard library's "md5" module, but although it seems to work fine, 21 it has not been extensively tested! (But note that there is a test 22 module, test_md5py.py, that compares this Python implementation with 23 the C one of the Python standard library. 24 25 BEWARE: this comes with no guarantee whatsoever about fitness and/or 26 other properties! Specifically, do not use this in any production 27 code! License is Python License! 28 29 Special thanks to Aurelian Coman who fixed some nasty bugs! 30 31 Dinu C. Gherman 32 """ 33 34 35 __date__ = '2004-11-17' 36 __version__ = 0.91 # Modernised by J. Hall�n and L. Creighton for Pypy 37 38 __metaclass__ = type # or genrpy won't work 39 40 import _struct as struct 41 import copy 42 43 44 # ====================================================================== 45 # Bit-Manipulation helpers 46 # ====================================================================== 47 48 def _bytelist2long(list): 49 "Transform a list of characters into a list of longs." 50 51 imax = len(list) // 4 52 hl = [0] * imax 53 54 j = 0 55 i = 0 56 while i < imax: 57 b0 = ord(list[j]) 58 b1 = ord(list[j + 1]) << 8 59 b2 = ord(list[j + 2]) << 16 60 b3 = ord(list[j + 3]) << 24 61 hl[i] = b0 | b1 | b2 | b3 62 i = i + 1 63 j = j + 4 64 65 return hl 66 67 68 def _rotateLeft(x, n): 69 "Rotate x (32 bit) left n bits circularly." 70 71 return (x << n) | (x >> (32 - n)) 72 73 74 # ====================================================================== 75 # The real MD5 meat... 76 # 77 # Implemented after "Applied Cryptography", 2nd ed., 1996, 78 # pp. 436-441 by Bruce Schneier. 79 # ====================================================================== 80 81 # F, G, H and I are basic MD5 functions. 82 83 def F(x, y, z): 84 return (x & y) | ((~x) & z) 85 86 87 def G(x, y, z): 88 return (x & z) | (y & (~z)) 89 90 91 def H(x, y, z): 92 return x ^ y ^ z 93 94 95 def I(x, y, z): 96 return y ^ (x | (~z)) 97 98 99 def XX(func, a, b, c, d, x, s, ac): 100 """Wrapper for call distribution to functions F, G, H and I. 101 102 This replaces functions FF, GG, HH and II from "Appl. Crypto." 103 Rotation is separate from addition to prevent recomputation 104 (now summed-up in one function). 105 """ 106 107 res = 0 108 res = res + a + func(b, c, d) 109 res = res + x 110 res = res + ac 111 res = res & 0xffffffff 112 res = _rotateLeft(res, s) 113 res = res & 0xffffffff 114 res = res + b 115 116 return res & 0xffffffff 117 118 119 class MD5Type(object): 120 "An implementation of the MD5 hash function in pure Python." 121 122 digest_size = digestsize = 16 123 block_size = 64 124 125 def __init__(self): 126 "Initialisation." 127 128 # Initial message length in bits(!). 129 self.length = 0 130 self.count = [0, 0] 131 132 # Initial empty message as a sequence of bytes (8 bit characters). 133 self.input = [] 134 135 # Call a separate init function, that can be used repeatedly 136 # to start from scratch on the same object. 137 self.init() 138 139 def init(self): 140 "Initialize the message-digest and set all fields to zero.code" 141 142 self.length = 0 143 self.count = [0, 0] 144 self.input = [] 145 146 # Load magic initialization constants. 147 self.A = 0x67452301 148 self.B = 0xefcdab89 149 self.C = 0x98badcfe 150 self.D = 0x10325476 151 152 def _transform(self, inp): 153 """Basic MD5 step transforming the digest based on the input. 154 155 Note that if the Mysterious Constants are arranged backwards 156 in little-endian order and decrypted with the DES they produce 157 OCCULT MESSAGES! 158 """ 159 160 a, b, c, d = A, B, C, D = self.A, self.B, self.C, self.D 161 162 # Round 1. 163 164 S11, S12, S13, S14 = 7, 12, 17, 22 165 166 a = XX(F, a, b, c, d, inp[0], S11, 0xD76AA478) # 1 167 d = XX(F, d, a, b, c, inp[1], S12, 0xE8C7B756) # 2 168 c = XX(F, c, d, a, b, inp[2], S13, 0x242070DB) # 3 169 b = XX(F, b, c, d, a, inp[3], S14, 0xC1BDCEEE) # 4 170 a = XX(F, a, b, c, d, inp[4], S11, 0xF57C0FAF) # 5 171 d = XX(F, d, a, b, c, inp[5], S12, 0x4787C62A) # 6 172 c = XX(F, c, d, a, b, inp[6], S13, 0xA8304613) # 7 173 b = XX(F, b, c, d, a, inp[7], S14, 0xFD469501) # 8 174 a = XX(F, a, b, c, d, inp[8], S11, 0x698098D8) # 9 175 d = XX(F, d, a, b, c, inp[9], S12, 0x8B44F7AF) # 10 176 c = XX(F, c, d, a, b, inp[10], S13, 0xFFFF5BB1) # 11 177 b = XX(F, b, c, d, a, inp[11], S14, 0x895CD7BE) # 12 178 a = XX(F, a, b, c, d, inp[12], S11, 0x6B901122) # 13 179 d = XX(F, d, a, b, c, inp[13], S12, 0xFD987193) # 14 180 c = XX(F, c, d, a, b, inp[14], S13, 0xA679438E) # 15 181 b = XX(F, b, c, d, a, inp[15], S14, 0x49B40821) # 16 182 183 # Round 2. 184 185 S21, S22, S23, S24 = 5, 9, 14, 20 186 187 a = XX(G, a, b, c, d, inp[1], S21, 0xF61E2562) # 17 188 d = XX(G, d, a, b, c, inp[6], S22, 0xC040B340) # 18 189 c = XX(G, c, d, a, b, inp[11], S23, 0x265E5A51) # 19 190 b = XX(G, b, c, d, a, inp[0], S24, 0xE9B6C7AA) # 20 191 a = XX(G, a, b, c, d, inp[5], S21, 0xD62F105D) # 21 192 d = XX(G, d, a, b, c, inp[10], S22, 0x02441453) # 22 193 c = XX(G, c, d, a, b, inp[15], S23, 0xD8A1E681) # 23 194 b = XX(G, b, c, d, a, inp[4], S24, 0xE7D3FBC8) # 24 195 a = XX(G, a, b, c, d, inp[9], S21, 0x21E1CDE6) # 25 196 d = XX(G, d, a, b, c, inp[14], S22, 0xC33707D6) # 26 197 c = XX(G, c, d, a, b, inp[3], S23, 0xF4D50D87) # 27 198 b = XX(G, b, c, d, a, inp[8], S24, 0x455A14ED) # 28 199 a = XX(G, a, b, c, d, inp[13], S21, 0xA9E3E905) # 29 200 d = XX(G, d, a, b, c, inp[2], S22, 0xFCEFA3F8) # 30 201 c = XX(G, c, d, a, b, inp[7], S23, 0x676F02D9) # 31 202 b = XX(G, b, c, d, a, inp[12], S24, 0x8D2A4C8A) # 32 203 204 # Round 3. 205 206 S31, S32, S33, S34 = 4, 11, 16, 23 207 208 a = XX(H, a, b, c, d, inp[5], S31, 0xFFFA3942) # 33 209 d = XX(H, d, a, b, c, inp[8], S32, 0x8771F681) # 34 210 c = XX(H, c, d, a, b, inp[11], S33, 0x6D9D6122) # 35 211 b = XX(H, b, c, d, a, inp[14], S34, 0xFDE5380C) # 36 212 a = XX(H, a, b, c, d, inp[1], S31, 0xA4BEEA44) # 37 213 d = XX(H, d, a, b, c, inp[4], S32, 0x4BDECFA9) # 38 214 c = XX(H, c, d, a, b, inp[7], S33, 0xF6BB4B60) # 39 215 b = XX(H, b, c, d, a, inp[10], S34, 0xBEBFBC70) # 40 216 a = XX(H, a, b, c, d, inp[13], S31, 0x289B7EC6) # 41 217 d = XX(H, d, a, b, c, inp[0], S32, 0xEAA127FA) # 42 218 c = XX(H, c, d, a, b, inp[3], S33, 0xD4EF3085) # 43 219 b = XX(H, b, c, d, a, inp[6], S34, 0x04881D05) # 44 220 a = XX(H, a, b, c, d, inp[9], S31, 0xD9D4D039) # 45 221 d = XX(H, d, a, b, c, inp[12], S32, 0xE6DB99E5) # 46 222 c = XX(H, c, d, a, b, inp[15], S33, 0x1FA27CF8) # 47 223 b = XX(H, b, c, d, a, inp[2], S34, 0xC4AC5665) # 48 224 225 # Round 4. 226 227 S41, S42, S43, S44 = 6, 10, 15, 21 228 229 a = XX(I, a, b, c, d, inp[0], S41, 0xF4292244) # 49 230 d = XX(I, d, a, b, c, inp[7], S42, 0x432AFF97) # 50 231 c = XX(I, c, d, a, b, inp[14], S43, 0xAB9423A7) # 51 232 b = XX(I, b, c, d, a, inp[5], S44, 0xFC93A039) # 52 233 a = XX(I, a, b, c, d, inp[12], S41, 0x655B59C3) # 53 234 d = XX(I, d, a, b, c, inp[3], S42, 0x8F0CCC92) # 54 235 c = XX(I, c, d, a, b, inp[10], S43, 0xFFEFF47D) # 55 236 b = XX(I, b, c, d, a, inp[1], S44, 0x85845DD1) # 56 237 a = XX(I, a, b, c, d, inp[8], S41, 0x6FA87E4F) # 57 238 d = XX(I, d, a, b, c, inp[15], S42, 0xFE2CE6E0) # 58 239 c = XX(I, c, d, a, b, inp[6], S43, 0xA3014314) # 59 240 b = XX(I, b, c, d, a, inp[13], S44, 0x4E0811A1) # 60 241 a = XX(I, a, b, c, d, inp[4], S41, 0xF7537E82) # 61 242 d = XX(I, d, a, b, c, inp[11], S42, 0xBD3AF235) # 62 243 c = XX(I, c, d, a, b, inp[2], S43, 0x2AD7D2BB) # 63 244 b = XX(I, b, c, d, a, inp[9], S44, 0xEB86D391) # 64 245 246 A = (A + a) & 0xffffffff 247 B = (B + b) & 0xffffffff 248 C = (C + c) & 0xffffffff 249 D = (D + d) & 0xffffffff 250 251 self.A, self.B, self.C, self.D = A, B, C, D 252 253 # Down from here all methods follow the Python Standard Library 254 # API of the md5 module. 255 256 def update(self, inBuf): 257 """Add to the current message. 258 259 Update the md5 object with the string arg. Repeated calls 260 are equivalent to a single call with the concatenation of all 261 the arguments, i.e. m.update(a); m.update(b) is equivalent 262 to m.update(a+b). 263 264 The hash is immediately calculated for all full blocks. The final 265 calculation is made in digest(). This allows us to keep an 266 intermediate value for the hash, so that we only need to make 267 minimal recalculation if we call update() to add moredata to 268 the hashed string. 269 """ 270 271 leninBuf = len(inBuf) 272 273 # Compute number of bytes mod 64. 274 index = (self.count[0] >> 3) & 0x3F 275 276 # Update number of bits. 277 self.count[0] = self.count[0] + (leninBuf << 3) 278 if self.count[0] < (leninBuf << 3): 279 self.count[1] = self.count[1] + 1 280 self.count[1] = self.count[1] + (leninBuf >> 29) 281 282 partLen = 64 - index 283 284 if leninBuf >= partLen: 285 self.input[index:] = list(inBuf[:partLen]) 286 self._transform(_bytelist2long(self.input)) 287 i = partLen 288 while i + 63 < leninBuf: 289 self._transform(_bytelist2long(list(inBuf[i:i + 64]))) 290 i = i + 64 291 else: 292 self.input = list(inBuf[i:leninBuf]) 293 else: 294 i = 0 295 self.input = self.input + list(inBuf) 296 297 def digest(self): 298 """Terminate the message-digest computation and return digest. 299 300 Return the digest of the strings passed to the update() 301 method so far. This is a 16-byte string which may contain 302 non-ASCII characters, including null bytes. 303 """ 304 305 A = self.A 306 B = self.B 307 C = self.C 308 D = self.D 309 input = [] + self.input 310 count = [] + self.count 311 312 index = (self.count[0] >> 3) & 0x3f 313 314 if index < 56: 315 padLen = 56 - index 316 else: 317 padLen = 120 - index 318 319 padding = [b'\200'] + [b'\000'] * 63 320 self.update(padding[:padLen]) 321 322 # Append length (before padding). 323 bits = _bytelist2long(self.input[:56]) + count 324 325 self._transform(bits) 326 327 # Store state in digest. 328 digest = struct.pack("<IIII", self.A, self.B, self.C, self.D) 329 330 self.A = A 331 self.B = B 332 self.C = C 333 self.D = D 334 self.input = input 335 self.count = count 336 337 return digest 338 339 def hexdigest(self): 340 """Terminate and return digest in HEX form. 341 342 Like digest() except the digest is returned as a string of 343 length 32, containing only hexadecimal digits. This may be 344 used to exchange the value safely in email or other non- 345 binary environments. 346 """ 347 348 return ''.join([('0' + hex(ord(c))[2:])[-2:] for c in self.digest()]) 349 350 def copy(self): 351 """Return a clone object. 352 353 Return a copy ('clone') of the md5 object. This can be used 354 to efficiently compute the digests of strings that share 355 a common initial substring. 356 """ 357 if 0: # set this to 1 to make the flow space crash 358 return copy.deepcopy(self) 359 clone = self.__class__() 360 clone.length = self.length 361 clone.count = [] + self.count[:] 362 clone.input = [] + self.input 363 clone.A = self.A 364 clone.B = self.B 365 clone.C = self.C 366 clone.D = self.D 367 return clone 368 369 370 # ====================================================================== 371 # Mimic Python top-level functions from standard library API 372 # for consistency with the _md5 module of the standard library. 373 # ====================================================================== 374 375 digest_size = 16 376 377 378 def new(arg=None): 379 """Return a new md5 crypto object. 380 If arg is present, the method call update(arg) is made. 381 """ 382 383 crypto = MD5Type() 384 if arg: 385 crypto.update(arg) 386 387 return crypto