Skip to main content

Observable Timing Discrepancy in hmac Module

PY005
observable_timing_discrepancy
CWE-208
⛔️ Error

Do not use Python's == operator to compare HMAC digests. The == operator is not designed to be used for cryptographic comparisons, and it can be vulnerable to timing attacks. Instead, use the hmac.compare_digest() function to compare HMAC digests.

The == operator works by comparing the length and contents of two objects. However, this can be a problem for HMAC digests, because the length of an HMAC digest is not necessarily unique. For example, two different messages with the same key will have the same HMAC digest.

A timing attack is a type of attack that exploits the time it takes to execute a piece of code. In the case of HMAC digests, a timing attack could be used to determine whether two messages have the same HMAC digest. This could be used to break the security of an HMAC-protected system.

The hmac.compare_digest() function is designed to be used for cryptographic comparisons. It works by comparing the binary representations of two HMAC digests. This makes it more resistant to timing attacks.

Example

import hmac


received_digest = (
b"\xe2\x93\x08\x19T8\xdc\x80\xef\x87\x90m\x1f\x9d\xf7\xf2"
"\xf5\x10>\xdbf\xa2\xaf\xf7x\xcdX\xdf"
)

key = b"my-secret-key"
password = b"pass"
digest = hmac.digest(key, password, digest="sha224")

print(digest == received_digest)

Remediation

The recommendation is to replace the == operator with the function compare_digest.

import hmac


received_digest = (
b"\xe2\x93\x08\x19T8\xdc\x80\xef\x87\x90m\x1f\x9d\xf7\xf2"
"\xf5\x10>\xdbf\xa2\xaf\xf7x\xcdX\xdf"
)

key = b"my-secret-key"
password = b"pass"
digest = hmac.digest(key, password, digest="sha224")

print(hmac.compare_digest(digest, received_digest))

False Positives

In the case of a false positive the rule can be suppressed. Simply add a trailing or preceding comment line with either the rule ID (PY005) or rule category name (observable_timing_discrepancy).

Fix Iconfix
import hmac


received_digest = (
b"\xe2\x93\x08\x19T8\xdc\x80\xef\x87\x90m\x1f\x9d\xf7\xf2"
"\xf5\x10>\xdbf\xa2\xaf\xf7x\xcdX\xdf"
)

key = b"my-secret-key"
password = b"pass"
digest = hmac.digest(key, password, digest="sha224")

# suppress: PY005
print(digest == received_digest)

See also