TupleHash128

TupleHash128 is a variable-lengh hash function for tuples of byte strings, derived from SHA-3, and standardized in NIST SP 800-185.

TupleHash128 provides a robust way to hash a sequence of byte strings, while maintaining the semantics of each single string, and with a security strength of 128 bits.

For example, let’s assume that a banking application combines the following strings to validate a money transfer: deposit, amount (e.g., 100), and username (e.g., joe). The application uses SHA256 and naively concatenates the strings to obtain a credential to authorize the operation:

SHA256("deposit100joe")

A malicious user could register a second user 000joe, so that the system computes, for the same small transfer:

SHA256("deposit100000joe")

which is also the same credential that authorizes a much larger transfer to the other user joe.

TupleHash128 makes the composition of all strings into a digest more robust by ensuring that the size of each individual byte string is considered. Each byte string is submitted in its entirety via the update() method.

This is an example showing how to generate a TupleHash128 for the 3 bytes strings above:

>>> from Crypto.Hash import TupleHash128
>>>
>>> hd = TupleHash128.new(digest_bytes=16)
>>> hd.update(b'deposit')
>>> hd.update(b'100')
>>> hd.update(b'joe')
>>> print(hd.hexdigest())
4c095be894c21cfe7076a7d0fe3f70ed

Multiple byte strings can be submitted. Each argument is a separate element in the tuple:

>>> from Crypto.Hash import TupleHash128
>>>
>>> hd = TupleHash128.new(digest_bytes=16)
>>> hd.update(b'deposit', b'100', b'joe')
>>> print(hd.hexdigest())
4c095be894c21cfe7076a7d0fe3f70ed

Any or even all the byte strings in the sequence can be empty. An empty byte string is significant: calling update(b'') will still contribute to and modify the final digest.

An application can select the length of the digest by means of the initialization parameters digest_bytes or digest_bits. For instance, while the traditional SHA256 can only produce 32-byte tags, with TupleHash128 you can produce a 16-byte tag (see the example above) but also a 33-byte tag:

>>> from Crypto.Hash import TupleHash128
>>>
>>> hd = TupleHash128.new(digest_bytes=33)
>>> hd.update(b'deposit')
>>> hd.update(b'100')
>>> hd.update(b'joe')
>>> print(hd.hexdigest())
23339e4f61527ade355f11e0496766bf929435eaff1ad20ad9bf9e01fddbe307

Note how the 16-byte digest is NOT just the truncated version of the 33-byte digest: they are cryptographically uncorrelated.

class Crypto.Hash.TupleHash128.TupleHash(custom, cshake, digest_size)

A Tuple hash object. Do not instantiate directly. Use the new() function.

digest()

Return the binary (non-printable) digest of the tuple of byte strings.

Returns:

The hash digest. Binary form.

Return type:

byte string

hexdigest()

Return the printable digest of the tuple of byte strings.

Returns:

The hash digest. Hexadecimal encoded.

Return type:

string

new(**kwargs)

Return a new instance of a TupleHash object. See new().

update(*data)

Authenticate the next tuple of byte strings. TupleHash guarantees the logical separation between each byte string.

Parameters:

data (bytes/bytearray/memoryview) – One or more items to hash.

Crypto.Hash.TupleHash128.new(**kwargs)

Create a new TupleHash128 object.

Parameters:
  • digest_bytes (integer) – Optional. The size of the digest, in bytes. Default is 64. Minimum is 8.

  • digest_bits (integer) – Optional and alternative to digest_bytes. The size of the digest, in bits (and in steps of 8). Default is 512. Minimum is 64.

  • custom (bytes) – Optional. A customization bytestring (S in SP 800-185).

Return:

A TupleHash object