1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
.. hazmat::
Two-factor authentication
=========================
.. currentmodule:: cryptography.hazmat.primitives.twofactor
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).
.. currentmodule:: cryptography.hazmat.primitives.twofactor.hotp
.. class:: HOTP(key, length, algorithm, backend)
.. versionadded:: 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`.
.. doctest::
>>> import os
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.twofactor.hotp import HOTP
>>> from cryptography.hazmat.primitives.hashes import SHA1
>>> key = os.urandom(16)
>>> hotp = HOTP(key, 6, SHA1(), backend=default_backend())
>>> hotp_value = hotp.generate(0)
>>> hotp.verify(hotp_value, 0)
:param bytes key: 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.
:param int length: Length of generated one time password as ``int``.
:param HashAlgorithm algorithm: A
:class:`~cryptography.hazmat.primitives.hashes`
provider.
:param backend: A
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
provider.
: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.
:raises TypeError: This is raised if the provided ``algorithm`` is not
:class:`~cryptography.hazmat.primitives.hashes.SHA1()`,
:class:`~cryptography.hazmat.primitives.hashes.SHA256()` or
:class:`~cryptography.hazmat.primitives.hashes.SHA512()` or if the
``length`` parameter is not an integer.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
.. method:: generate(counter)
:param int counter: The counter value used to generate the one time
password.
:return bytes: A one time password value.
.. method:: verify(hotp, counter)
:param bytes hotp: The one time password value to validate.
:param int counter: The counter value to validate against.
:raises cryptography.exceptions.InvalidToken: This is raised when the
supplied HOTP does not match the expected HOTP.
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.
.. code-block:: python
def verify(hotp, counter, look_ahead):
assert look_ahead >= 0
correct_counter = None
otp = HOTP(key, 6, default_backend())
for count in range(counter, counter + look_ahead):
try:
otp.verify(hotp, count)
correct_counter = count
except InvalidToken:
pass
return correct_counter
.. currentmodule:: cryptography.hazmat.primitives.twofactor.totp
.. class:: TOTP(key, length, algorithm, time_step, backend)
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`.
.. doctest::
>>> import os
>>> import time
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.twofactor.totp import TOTP
>>> from cryptography.hazmat.primitives.hashes import SHA1
>>> key = os.urandom(16)
>>> totp = TOTP(key, 8, SHA1(), 30, backend=default_backend())
>>> time_value = time.time()
>>> totp_value = totp.generate(time_value)
>>> totp.verify(totp_value, time_value)
:param bytes key: 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.
:param int length: Length of generated one time password as ``int``.
:param HashAlgorithm algorithm: A
:class:`~cryptography.hazmat.primitives.hashes`
provider.
:param int time_step: The time step size. The recommended size is 30.
:param backend: A
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
provider.
: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.
:raises TypeError: This is raised if the provided ``algorithm`` is not
:class:`~cryptography.hazmat.primitives.hashes.SHA1()`,
:class:`~cryptography.hazmat.primitives.hashes.SHA256()` or
:class:`~cryptography.hazmat.primitives.hashes.SHA512()` or if the
``length`` parameter is not an integer.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
.. method:: generate(time)
:param int time: The time value used to generate the one time password.
:return bytes: A one time password value.
.. method:: verify(totp, time)
:param bytes totp: The one time password value to validate.
:param int time: The time value to validate against.
:raises cryptography.exceptions.InvalidToken: This is raised when the
supplied TOTP does not match the expected TOTP.
|