Danger

This is a “Hazardous Materials” module. You should ONLY use it if you’re 100% absolutely sure that you know what you’re doing because this module is full of land mines, dragons, and dinosaurs with laser guns.

Two-factor authentication

This module contains algorithms related to two-factor authentication.

Currently, it contains an algorithm for generating and verifying one time password values based on Hash-based message authentication codes (HMAC).

class cryptography.hazmat.primitives.twofactor.InvalidToken[source]

This is raised when the verify method of a one time password function’s computed token does not match the expected token.

cryptography.hazmat.primitives.twofactor.hotp.HOTPHashTypes

New in version 40.0.0.

Type alias: A union of supported hash algorithm types: SHA1, SHA256 or SHA512.

class cryptography.hazmat.primitives.twofactor.hotp.HOTP(key, length, algorithm, *, enforce_key_length=True)[source]

New in version 0.3.

HOTP objects take a key, length and algorithm parameter. The key should be randomly generated bytes and is recommended to be 160 bits in length. The length parameter controls the length of the generated one time password and must be >= 6 and <= 8.

This is an implementation of RFC 4226.

>>> import os
>>> from cryptography.hazmat.primitives.twofactor.hotp import HOTP
>>> from cryptography.hazmat.primitives.hashes import SHA1
>>> key = os.urandom(20)
>>> hotp = HOTP(key, 6, SHA1())
>>> hotp_value = hotp.generate(0)
>>> hotp.verify(hotp_value, 0)
Parameters:
  • key (bytes-like) – Per-user secret key. This value must be kept secret and be at least 128 bits. It is recommended that the key be 160 bits.

  • length (int) – Length of generated one time password as int.

  • algorithm (cryptography.hazmat.primitives.hashes.HashAlgorithm) – A hashes instance (must match HOTPHashTypes).

  • enforce_key_length

    A boolean flag defaulting to True that toggles whether a minimum key length of 128 bits is enforced. This exists to work around the fact that as documented in Issue #2915, the Google Authenticator PAM module by default generates 80 bit keys. If this flag is set to False, the application developer should implement additional checks of the key length before passing it into HOTP.

    New in version 1.5.

Raises:
  • ValueError – This is raised if the provided key is shorter than 128 bits or if the length parameter is not 6, 7 or 8.

  • TypeError – This is raised if the provided algorithm is not SHA1(), SHA256() or SHA512() or if the length parameter is not an integer.

generate(counter)[source]
Parameters:

counter (int) – The counter value used to generate the one time password.

Return bytes:

A one time password value.

verify(hotp, counter)[source]
Parameters:
  • hotp (bytes) – The one time password value to validate.

  • counter (int) – The counter value to validate against.

Raises:

cryptography.hazmat.primitives.twofactor.InvalidToken – This is raised when the supplied HOTP does not match the expected HOTP.

get_provisioning_uri(account_name, counter, issuer)[source]

New in version 1.0.

Parameters:
  • account_name (str) – The display name of account, such as 'Alice Smith' or 'alice@example.com'.

  • issuer (str or None) – The optional display name of issuer. This is typically the provider or service the user wants to access using the OTP token.

  • counter (int) – The current value of counter.

Returns:

A URI string.

Throttling

Due to the fact that the HOTP algorithm generates rather short tokens that are 6 - 8 digits long, brute force attacks are possible. It is highly recommended that the server that validates the token implement a throttling scheme that locks out the account for a period of time after a number of failed attempts. The number of allowed attempts should be as low as possible while still ensuring that usability is not significantly impacted.

Re-synchronization of the counter

The server’s counter value should only be incremented on a successful HOTP authentication. However, the counter on the client is incremented every time a new HOTP value is requested. This can lead to the counter value being out of synchronization between the client and server.

Due to this, it is highly recommended that the server sets a look-ahead window that allows the server to calculate the next x HOTP values and check them against the supplied HOTP value. This can be accomplished with something similar to the following code.

def verify(hotp, counter, look_ahead):
    assert look_ahead >= 0
    correct_counter = None

    otp = HOTP(key, 6)
    for count in range(counter, counter + look_ahead):
        try:
            otp.verify(hotp, count)
            correct_counter = count
        except InvalidToken:
            pass

    return correct_counter
class cryptography.hazmat.primitives.twofactor.totp.TOTP(key, length, algorithm, time_step, *, enforce_key_length=True)[source]

TOTP objects take a key, length, algorithm and time_step parameter. The key should be randomly generated bytes and is recommended to be as long as your hash function’s output (e.g 256-bit for SHA256). The length parameter controls the length of the generated one time password and must be >= 6 and <= 8.

This is an implementation of RFC 6238.

>>> import os
>>> import time
>>> from cryptography.hazmat.primitives.twofactor.totp import TOTP
>>> from cryptography.hazmat.primitives.hashes import SHA1
>>> key = os.urandom(20)
>>> totp = TOTP(key, 8, SHA1(), 30)
>>> time_value = time.time()
>>> totp_value = totp.generate(time_value)
>>> totp.verify(totp_value, time_value)
Parameters:
  • key (bytes-like) – Per-user secret key. This value must be kept secret and be at least 128 bits. It is recommended that the key be 160 bits.

  • length (int) – Length of generated one time password as int.

  • algorithm (cryptography.hazmat.primitives.hashes.HashAlgorithm) – A hashes instance.

  • time_step (int) – The time step size. The recommended size is 30.

  • enforce_key_length

    A boolean flag defaulting to True that toggles whether a minimum key length of 128 bits is enforced. This exists to work around the fact that as documented in Issue #2915, the Google Authenticator PAM module by default generates 80 bit keys. If this flag is set to False, the application develop should implement additional checks of the key length before passing it into TOTP.

    New in version 1.5.

Raises:
  • ValueError – This is raised if the provided key is shorter than 128 bits or if the length parameter is not 6, 7 or 8.

  • TypeError – This is raised if the provided algorithm is not SHA1(), SHA256() or SHA512() or if the length parameter is not an integer.

generate(time)[source]
Parameters:

time (int) – The time value used to generate the one time password.

Return bytes:

A one time password value.

verify(totp, time)[source]
Parameters:
  • totp (bytes) – The one time password value to validate.

  • time (int) – The time value to validate against.

Raises:

cryptography.hazmat.primitives.twofactor.InvalidToken – This is raised when the supplied TOTP does not match the expected TOTP.

get_provisioning_uri(account_name, issuer)[source]

New in version 1.0.

Parameters:
  • account_name (str) – The display name of account, such as 'Alice Smith' or 'alice@example.com'.

  • issuer (str or None) – The optional display name of issuer. This is typically the provider or service the user wants to access using the OTP token.

Returns:

A URI string.

Provisioning URI

The provisioning URI of HOTP and TOTP is a feature of Google Authenticator and not actually part of the HOTP or TOTP RFCs. However, it is widely supported by web sites and mobile applications which are using Two-Factor authentication.

For generating a provisioning URI you can use the get_provisioning_uri method of HOTP/TOTP instances.

counter = 5
account_name = 'alice@example.com'
issuer_name = 'Example Inc'

hotp_uri = hotp.get_provisioning_uri(account_name, counter, issuer_name)
totp_uri = totp.get_provisioning_uri(account_name, issuer_name)

A common usage is encoding the provisioning URI into QR code and guiding users to scan it with Two-Factor authentication applications in their mobile devices.