Botan 3.12.0
Crypto and TLS for C&
hotp.cpp
Go to the documentation of this file.
1/*
2* HOTP
3* (C) 2017,2026 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/exceptn.h>
11#include <botan/internal/loadstor.h>
12
13namespace Botan {
14
15namespace {
16
17// Use compile-time constant divisors to ensure the compiler emits a
18// multiply+shift sequence instead of a variable-time division instruction
19uint32_t hotp_truncate(uint32_t code, size_t digits) {
20 switch(digits) {
21 case 6:
22 return code % 1000000;
23 case 7:
24 return code % 10000000;
25 case 8:
26 return code % 100000000;
27 default:
29 }
30}
31
32} // namespace
33
34HOTP::HOTP(const uint8_t key[], size_t key_len, std::string_view hash_algo, size_t digits) : m_digits(digits) {
35 BOTAN_ARG_CHECK(m_digits == 6 || m_digits == 7 || m_digits == 8, "Invalid HOTP digits");
36
37 /*
38 RFC 4228 only supports SHA-1 but TOTP allows SHA-256 and SHA-512
39 and some HOTP libs support one or both as extensions
40 */
41 if(hash_algo == "SHA-1") {
42 m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-1)");
43 } else if(hash_algo == "SHA-256") {
44 m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
45 } else if(hash_algo == "SHA-512") {
46 m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
47 } else {
48 throw Invalid_Argument("Unsupported HOTP hash function");
49 }
50
51 m_mac->set_key(key, key_len);
52}
53
54uint32_t HOTP::generate_hotp(uint64_t counter) {
55 m_mac->update_be(counter);
56 const secure_vector<uint8_t> mac = m_mac->final();
57
58 const size_t offset = mac[mac.size() - 1] & 0x0F;
59 const uint32_t code = load_be<uint32_t>(mac.data() + offset, 0) & 0x7FFFFFFF;
60 return hotp_truncate(code, m_digits);
61}
62
63std::pair<bool, uint64_t> HOTP::verify_hotp(uint32_t otp, uint64_t starting_counter, size_t resync_range) {
64 for(size_t i = 0; i <= resync_range; ++i) {
65 if(generate_hotp(starting_counter + i) == otp) {
66 return std::make_pair(true, starting_counter + i + 1);
67 }
68 }
69 return std::make_pair(false, starting_counter);
70}
71
72} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:163
uint32_t generate_hotp(uint64_t counter)
Definition hotp.cpp:54
std::pair< bool, uint64_t > verify_hotp(uint32_t otp, uint64_t starting_counter, size_t resync_range=0)
Definition hotp.cpp:63
BOTAN_FUTURE_EXPLICIT HOTP(const SymmetricKey &key, std::string_view hash_algo="SHA-1", size_t digits=6)
Definition otp.h:28
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition mac.cpp:147
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:504