Botan 3.13.0
Crypto and TLS for C&
totp.cpp
Go to the documentation of this file.
1/*
2* TOTP
3* (C) 2017 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/otp.h>
9
10#include <botan/assert.h>
11#include <botan/internal/calendar.h>
12
13namespace Botan {
14
15TOTP::TOTP(const uint8_t key[], size_t key_len, std::string_view hash_algo, size_t digits, size_t time_step) :
16 m_hotp(key, key_len, hash_algo, digits),
17 m_time_step(time_step),
18 m_unix_epoch(calendar_point(1970, 1, 1, 0, 0, 0).to_std_timepoint()) {
19 /*
20 * Technically any time step except 0 is valid, but 30 is typical
21 * and over 5 minutes seems unlikely.
22 */
23 BOTAN_ARG_CHECK(m_time_step > 0 && m_time_step <= 300, "Invalid TOTP time step");
24}
25
26uint32_t TOTP::generate_totp(std::chrono::system_clock::time_point current_time) {
27 const uint64_t unix_time = std::chrono::duration_cast<std::chrono::seconds>(current_time - m_unix_epoch).count();
28 return this->generate_totp(unix_time);
29}
30
31uint32_t TOTP::generate_totp(uint64_t unix_time) {
32 return m_hotp.generate_hotp(unix_time / m_time_step);
33}
34
35bool TOTP::verify_totp(uint32_t otp, std::chrono::system_clock::time_point current_time, size_t clock_drift_accepted) {
36 const uint64_t unix_time = std::chrono::duration_cast<std::chrono::seconds>(current_time - m_unix_epoch).count();
37 return verify_totp(otp, unix_time, clock_drift_accepted);
38}
39
40bool TOTP::verify_totp(uint32_t otp, uint64_t unix_time, size_t clock_drift_accepted) {
41 /*
42 clock_drift_accepted is denominated in time steps. This bounds the loop to
43 far more iterations than any reasonable clock drift would require. For the
44 almost universally used 30 second time step, this limit is about 3.5 days
45 */
46 BOTAN_ARG_CHECK(clock_drift_accepted <= 10000, "TOTP clock_drift_accepted too large");
47
48 // This was on Sep 9, 2001
49 BOTAN_ARG_CHECK(unix_time >= 1000000000, "TOTP unix_time argument is implausibly small");
50
51 const uint64_t t = unix_time / m_time_step;
52
53 for(size_t i = 0; i <= clock_drift_accepted; ++i) {
54 BOTAN_ASSERT_NOMSG(t >= i);
55 if(m_hotp.generate_hotp(t - i) == otp) {
56 return true;
57 }
58 }
59
60 return false;
61}
62
63} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
uint32_t generate_totp(std::chrono::system_clock::time_point time_point)
Definition totp.cpp:26
BOTAN_FUTURE_EXPLICIT TOTP(const SymmetricKey &key, std::string_view hash_algo="SHA-1", size_t digits=6, size_t time_step=30)
Definition otp.h:78
bool verify_totp(uint32_t otp, std::chrono::system_clock::time_point time, size_t clock_drift_accepted=0)
Definition totp.cpp:35