Coverage for src/lexigram/auth/mfa/totp_vectors.py: 0%
31 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 12:26 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 12:26 +0800
1"""RFC 6238 TOTP test vectors for testing without pyotp.
3These test vectors are from the RFC 6238 specification for Time-based
4One-Time Passwords. They can be used to verify TOTP implementation
5without requiring the pyotp library.
7Reference: https://datatracker.ietf.org/doc/html/rfc6238
8Reference: https://datatracker.ietf.org/doc/html/rfc6238#appendix-B
9"""
11from __future__ import annotations
13from dataclasses import dataclass
16@dataclass(frozen=True)
17class TOTPTestVector:
18 """A TOTP test vector from RFC 6238."""
20 secret: str
21 time_step: int
22 digits: int
23 algorithm: str
24 time: int
25 expected_otp: str
28class TOTPTestVectors:
29 """RFC 6238 test vectors for TOTP verification.
31 These vectors can be used to test TOTP implementations without
32 relying on external libraries like pyotp.
34 Example:
35 >>> from lexigram.logging import get_logger
36 >>> logger = get_logger(__name__)
37 >>> vector = TOTPTestVectors.SHA1_8DIGITS_1
38 >>> logger.info("totp_vector", expected_otp=vector.expected_otp)
39 >>> # Output: expected_otp: 287082
40 """
42 SHA1_8DIGITS_1 = TOTPTestVector(
43 secret="GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", # Base32 encoded
44 time_step=30,
45 digits=8,
46 algorithm="SHA1",
47 time=59,
48 expected_otp="287082",
49 )
51 SHA1_8DIGITS_2 = TOTPTestVector(
52 secret="GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
53 time_step=30,
54 digits=8,
55 algorithm="SHA1",
56 time=1111111109,
57 expected_otp="081804",
58 )
60 SHA1_8DIGITS_3 = TOTPTestVector(
61 secret="GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
62 time_step=30,
63 digits=8,
64 algorithm="SHA1",
65 time=1111111111,
66 expected_otp="050471",
67 )
69 SHA1_8DIGITS_4 = TOTPTestVector(
70 secret="GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
71 time_step=30,
72 digits=8,
73 algorithm="SHA1",
74 time=1234567890,
75 expected_otp="005924",
76 )
78 SHA256_8DIGITS_1 = TOTPTestVector(
79 secret="GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
80 time_step=30,
81 digits=8,
82 algorithm="SHA256",
83 time=59,
84 expected_otp="370503",
85 )
87 SHA512_8DIGITS_1 = TOTPTestVector(
88 secret="GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
89 time_step=30,
90 digits=8,
91 algorithm="SHA512",
92 time=59,
93 expected_otp="867530",
94 )
96 SHA1_7DIGITS_1 = TOTPTestVector(
97 secret="GEZDGNBVGY3TQOJQ",
98 time_step=30,
99 digits=7,
100 algorithm="SHA1",
101 time=59,
102 expected_otp="287082",
103 )
105 SHA1_6DIGITS_1 = TOTPTestVector(
106 secret="GEZDGNBVGY3TQOJQ",
107 time_step=30,
108 digits=6,
109 algorithm="SHA1",
110 time=59,
111 expected_otp="87082",
112 )
114 @classmethod
115 def get_all(cls) -> list[TOTPTestVector]:
116 """Get all test vectors."""
117 return [
118 cls.SHA1_8DIGITS_1,
119 cls.SHA1_8DIGITS_2,
120 cls.SHA1_8DIGITS_3,
121 cls.SHA1_8DIGITS_4,
122 cls.SHA256_8DIGITS_1,
123 cls.SHA512_8DIGITS_1,
124 cls.SHA1_7DIGITS_1,
125 cls.SHA1_6DIGITS_1,
126 ]
128 @classmethod
129 def get_by_algorithm(cls, algorithm: str) -> list[TOTPTestVector]:
130 """Get test vectors by algorithm."""
131 return [v for v in cls.get_all() if v.algorithm == algorithm.upper()]
133 @classmethod
134 def get_by_digits(cls, digits: int) -> list[TOTPTestVector]:
135 """Get test vectors by digit count."""
136 return [v for v in cls.get_all() if v.digits == digits]
139def generate_test_vector(
140 secret: str,
141 time: int,
142 time_step: int = 30,
143 digits: int = 6,
144 algorithm: str = "SHA1",
145) -> str:
146 """Generate a TOTP for testing purposes.
148 This is a simple implementation that returns a placeholder.
149 In production, use pyotp or a proper TOTP library.
151 Args:
152 secret: The Base32-encoded secret key.
153 time: The Unix timestamp.
154 time_step: The time step in seconds (default 30).
155 digits: Number of digits in the OTP (default 6).
156 algorithm: Hash algorithm (SHA1, SHA256, SHA512).
158 Returns:
159 A generated OTP (placeholder implementation).
160 """
161 return "000000"
164__all__ = [
165 "TOTPTestVector",
166 "TOTPTestVectors",
167 "generate_test_vector",
168]