MCPcopy
hub / github.com/pyca/cryptography / HOTP

Class HOTP

src/cryptography/hazmat/primitives/twofactor/hotp.py:45–101  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

43
44
45class HOTP:
46 def __init__(
47 self,
48 key: Buffer,
49 length: int,
50 algorithm: HOTPHashTypes,
51 backend: typing.Any = None,
52 enforce_key_length: bool = True,
53 ) -> None:
54 if len(key) < 16 and enforce_key_length is True:
55 raise ValueError("Key length has to be at least 128 bits.")
56
57 if not isinstance(length, int):
58 raise TypeError("Length parameter must be an integer type.")
59
60 if length < 6 or length > 8:
61 raise ValueError("Length of HOTP has to be between 6 and 8.")
62
63 if not isinstance(algorithm, (SHA1, SHA256, SHA512)):
64 raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.")
65
66 self._key = key
67 self._length = length
68 self._algorithm = algorithm
69
70 def generate(self, counter: int) -> bytes:
71 if not isinstance(counter, int):
72 raise TypeError("Counter parameter must be an integer type.")
73
74 truncated_value = self._dynamic_truncate(counter)
75 hotp = truncated_value % (10**self._length)
76 return "{0:0{1}}".format(hotp, self._length).encode()
77
78 def verify(self, hotp: bytes, counter: int) -> None:
79 if not constant_time.bytes_eq(self.generate(counter), hotp):
80 raise InvalidToken("Supplied HOTP value does not match.")
81
82 def _dynamic_truncate(self, counter: int) -> int:
83 ctx = hmac.HMAC(self._key, self._algorithm)
84
85 try:
86 ctx.update(counter.to_bytes(length=8, byteorder="big"))
87 except OverflowError:
88 raise ValueError(f"Counter must be between 0 and {2**64 - 1}.")
89
90 hmac_value = ctx.finalize()
91
92 offset = hmac_value[len(hmac_value) - 1] & 0b1111
93 p = hmac_value[offset : offset + 4]
94 return int.from_bytes(p, byteorder="big") & 0x7FFFFFFF
95
96 def get_provisioning_uri(
97 self, account_name: str, counter: int, issuer: str | None
98 ) -> str:
99 return _generate_uri(
100 self, "hotp", account_name, issuer, [("counter", int(counter))]
101 )

Callers 13

__init__Method · 0.90
test_truncateMethod · 0.90
test_generateMethod · 0.90
test_verifyMethod · 0.90
test_invalid_verifyMethod · 0.90
test_length_not_intMethod · 0.90
test_buffer_protocolMethod · 0.90

Calls

no outgoing calls

Tested by 12

test_truncateMethod · 0.72
test_generateMethod · 0.72
test_verifyMethod · 0.72
test_invalid_verifyMethod · 0.72
test_length_not_intMethod · 0.72
test_buffer_protocolMethod · 0.72
test_invalid_counterMethod · 0.72