|
| 1 | +""" |
| 2 | +Copyright [2018] [Mauro Riva <lemariva@mail.com> <lemariva.com>] |
| 3 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +you may not use this file except in compliance with the License. |
| 5 | +You may obtain a copy of the License at |
| 6 | +http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | +Unless required by applicable law or agreed to in writing, software |
| 8 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 9 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 10 | +See the License for the specific language governing permissions and |
| 11 | +limitations under the License. |
| 12 | +The above copyright notice and this permission notice shall be |
| 13 | +included in all copies or substantial portions of the Software. |
| 14 | +
|
| 15 | +
|
| 16 | +based on https://rosettacode.org/wiki/MD5/Implementation#Python |
| 17 | +adapted for MicroPython |
| 18 | +""" |
| 19 | + |
| 20 | +rotate_amounts = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, |
| 21 | + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, |
| 22 | + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, |
| 23 | + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21] |
| 24 | + |
| 25 | +#constants = [int(abs(math.sin(i+1)) * 2**32) & 0xFFFFFFFF for i in range(64)] # precision is not enough |
| 26 | +constants = [3614090360, 3905402710, 606105819, 3250441966, 4118548399, 1200080426, 2821735955, 4249261313, |
| 27 | + 1770035416, 2336552879, 4294925233, 2304563134, 1804603682, 4254626195, 2792965006, 1236535329, |
| 28 | + 4129170786, 3225465664, 643717713, 3921069994, 3593408605, 38016083, 3634488961, 3889429448, |
| 29 | + 568446438, 3275163606, 4107603335, 1163531501, 2850285829, 4243563512, 1735328473, 2368359562, |
| 30 | + 4294588738, 2272392833, 1839030562, 4259657740, 2763975236, 1272893353, 4139469664, 3200236656, |
| 31 | + 681279174, 3936430074, 3572445317, 76029189, 3654602809, 3873151461, 530742520, 3299628645, |
| 32 | + 4096336452, 1126891415, 2878612391, 4237533241, 1700485571, 2399980690, 4293915773, 2240044497, |
| 33 | + 1873313359, 4264355552, 2734768916, 1309151649, 4149444226, 3174756917, 718787259, 3951481745] |
| 34 | + |
| 35 | +init_values = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476] |
| 36 | + |
| 37 | +functions = 16*[lambda b, c, d: (b & c) | (~b & d)] + \ |
| 38 | + 16*[lambda b, c, d: (d & b) | (~d & c)] + \ |
| 39 | + 16*[lambda b, c, d: b ^ c ^ d] + \ |
| 40 | + 16*[lambda b, c, d: c ^ (b | ~d)] |
| 41 | + |
| 42 | +index_functions = 16*[lambda i: i] + \ |
| 43 | + 16*[lambda i: (5*i + 1)%16] + \ |
| 44 | + 16*[lambda i: (3*i + 5)%16] + \ |
| 45 | + 16*[lambda i: (7*i)%16] |
| 46 | + |
| 47 | +def left_rotate(x, amount): |
| 48 | + x &= 0xFFFFFFFF |
| 49 | + return ((x<<amount) | (x>>(32-amount))) & 0xFFFFFFFF |
| 50 | + |
| 51 | +def md5(message): |
| 52 | + message = bytearray(message) #copy our input into a mutable buffer |
| 53 | + orig_len_in_bits = (8 * len(message)) & 0xffffffffffffffff |
| 54 | + message.append(0x80) |
| 55 | + while len(message)%64 != 56: |
| 56 | + message.append(0) |
| 57 | + message += orig_len_in_bits.to_bytes(8, 'little') |
| 58 | + #print (message) |
| 59 | + |
| 60 | + hash_pieces = init_values[:] |
| 61 | + |
| 62 | + for chunk_ofst in range(0, len(message), 64): |
| 63 | + a, b, c, d = hash_pieces |
| 64 | + chunk = message[chunk_ofst:chunk_ofst+64] |
| 65 | + #print(a, b, c, d) |
| 66 | + for i in range(64): |
| 67 | + f = functions[i](b, c, d) |
| 68 | + g = index_functions[i](i) |
| 69 | + #print(constants[i]) |
| 70 | + to_rotate = a + f + constants[i] + int.from_bytes(chunk[4*g:4*g+4], 'little') |
| 71 | + new_b = (b + left_rotate(to_rotate, rotate_amounts[i])) & 0xFFFFFFFF |
| 72 | + a, b, c, d = d, new_b, b, c |
| 73 | + #print(to_rotate) |
| 74 | + |
| 75 | + for i, val in enumerate([a, b, c, d]): |
| 76 | + hash_pieces[i] += val |
| 77 | + hash_pieces[i] &= 0xFFFFFFFF |
| 78 | + return sum(x<<(32*i) for i, x in enumerate(hash_pieces)) |
| 79 | + |
| 80 | +def digest(message): |
| 81 | + digest = md5(message) |
| 82 | + raw = digest.to_bytes(16, 'little') |
| 83 | + return '{:032x}'.format(int.from_bytes(raw, 'big')) |
| 84 | + #return raw |
0 commit comments