Class to contain the entire pipeline for SHA1 hashing algorithm >>> SHA1Hash(bytes('Allan', 'utf-8')).final_hash() '872af2d8ac3d8695387e7c804bf0e02c18df9e6e'
| 32 | |
| 33 | |
| 34 | class SHA1Hash: |
| 35 | """ |
| 36 | Class to contain the entire pipeline for SHA1 hashing algorithm |
| 37 | >>> SHA1Hash(bytes('Allan', 'utf-8')).final_hash() |
| 38 | '872af2d8ac3d8695387e7c804bf0e02c18df9e6e' |
| 39 | """ |
| 40 | |
| 41 | def __init__(self, data): |
| 42 | """ |
| 43 | Initiates the variables data and h. h is a list of 5 8-digit hexadecimal |
| 44 | numbers corresponding to |
| 45 | (1732584193, 4023233417, 2562383102, 271733878, 3285377520) |
| 46 | respectively. We will start with this as a message digest. 0x is how you write |
| 47 | hexadecimal numbers in Python |
| 48 | """ |
| 49 | self.data = data |
| 50 | self.h = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0] |
| 51 | |
| 52 | @staticmethod |
| 53 | def rotate(n, b): |
| 54 | """ |
| 55 | Static method to be used inside other methods. Left rotates n by b. |
| 56 | >>> SHA1Hash('').rotate(12,2) |
| 57 | 48 |
| 58 | """ |
| 59 | return ((n << b) | (n >> (32 - b))) & 0xFFFFFFFF |
| 60 | |
| 61 | def padding(self): |
| 62 | """ |
| 63 | Pads the input message with zeros so that padded_data has 64 bytes or 512 bits |
| 64 | """ |
| 65 | padding = b"\x80" + b"\x00" * (63 - (len(self.data) + 8) % 64) |
| 66 | padded_data = self.data + padding + struct.pack(">Q", 8 * len(self.data)) |
| 67 | return padded_data |
| 68 | |
| 69 | def split_blocks(self): |
| 70 | """ |
| 71 | Returns a list of bytestrings each of length 64 |
| 72 | """ |
| 73 | return [ |
| 74 | self.padded_data[i : i + 64] for i in range(0, len(self.padded_data), 64) |
| 75 | ] |
| 76 | |
| 77 | # @staticmethod |
| 78 | def expand_block(self, block): |
| 79 | """ |
| 80 | Takes a bytestring-block of length 64, unpacks it to a list of integers and |
| 81 | returns a list of 80 integers after some bit operations |
| 82 | """ |
| 83 | w = list(struct.unpack(">16L", block)) + [0] * 64 |
| 84 | for i in range(16, 80): |
| 85 | w[i] = self.rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1) |
| 86 | return w |
| 87 | |
| 88 | def final_hash(self): |
| 89 | """ |
| 90 | Calls all the other methods to process the input. Pads the data, then splits |
| 91 | into blocks and then does a series of operations for each block (including |
no outgoing calls