Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to hash int/long using hashlib in Python?

I'm developing a set of cryptographic algorithms / protocols for educational purposes. Specifically, I am currently working on OAEP encoding.

OAEP involves use of cryptographic hash functions; therefore I wanted to use the hashlib library, provided in the standard of Python3.

Let's say, I have a 128-bit integer, for which I want to get the SHA256 digest of. How can I do this in Python? All I could found was how to hash strings (or b-strings) with hashlib.sha256().

like image 424
Oran Can Ören Avatar asked Jan 21 '18 12:01

Oran Can Ören


1 Answers

Hashes work on bytes, a sequence of integer values in the range 0-255; this is independent of the implementation language. You'd have to convert your 128-bit integer into a series of bytes representing that value. That's why the hashlib module only accepts bytes objects ("b values").

How you do this is entirely dependent on the use case; you'd need to see how the specific OAEP standard specifies how such an integer is represented.

For example, you could take the string representation of the decimal integer value; a sequence of ASCII digits; this is not a very efficient method as that can take up to 39 bytes:

>>> import hashlib
>>> 2 ** 128 - 1  # largest 128-bit value
340282366920938463463374607431768211455
>>> len(str(2 ** 128 - 1))
39
>>> str(2 ** 128 - 1).encode('ASCII')  # ascii bytes
b'340282366920938463463374607431768211455'
>>> hashlib.sha256(str(2 ** 128 - 1).encode('ASCII')).hexdigest()
'f315ff319bf588e202110ab686fb8c3dbca12b4df9fbd844615b566a2fff3e75'

A much more efficient method would be to take those 128 bits, divide them into 16 bytes and hash those. You then need to decide on byte order (little or big endian). If you need to hash multiple integer values, then the Python struct module can help with producing the bytes, but only for integer values up to 8 bytes (you'd have to split up your larger numbers first). For single values, just use the int.to_bytes() method:

>>> (2 ** 128 - 1).to_bytes(16, 'little', signed=False)
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
>>> hashlib.sha256((2 ** 128 - 1).to_bytes(16, 'little', signed=False)).hexdigest()
'5ac6a5945f16500911219129984ba8b387a06f24fe383ce4e81a73294065461b'
like image 134
Martijn Pieters Avatar answered Oct 13 '22 19:10

Martijn Pieters