• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 24101703016

06 Apr 2026 10:36PM UTC coverage: 89.45% (-0.005%) from 89.455%
24101703016

push

github

web-flow
Merge pull request #5521 from randombit/jack/fix-rollup

Rollup of small fixes

105880 of 118368 relevant lines covered (89.45%)

11539723.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/src/lib/misc/hotp/hotp.cpp
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

13
namespace Botan {
14

15
namespace {
16

17
// Use compile-time constant divisors to ensure the compiler emits a
18
// multiply+shift sequence instead of a variable-time division instruction
19
uint32_t hotp_truncate(uint32_t code, size_t digits) {
6,321✔
20
   switch(digits) {
6,321✔
21
      case 6:
1,979✔
22
         return code % 1000000;
1,979✔
23
      case 7:
390✔
24
         return code % 10000000;
390✔
25
      case 8:
3,952✔
26
         return code % 100000000;
3,952✔
27
      default:
×
28
         BOTAN_ASSERT_UNREACHABLE();
×
29
   }
30
}
31

32
}  // namespace
33

34
HOTP::HOTP(const uint8_t key[], size_t key_len, std::string_view hash_algo, size_t digits) : m_digits(digits) {
40✔
35
   BOTAN_ARG_CHECK(m_digits == 6 || m_digits == 7 || m_digits == 8, "Invalid HOTP digits");
40✔
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") {
40✔
42
      m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-1)");
28✔
43
   } else if(hash_algo == "SHA-256") {
12✔
44
      m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
6✔
45
   } else if(hash_algo == "SHA-512") {
6✔
46
      m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
6✔
47
   } else {
48
      throw Invalid_Argument("Unsupported HOTP hash function");
×
49
   }
50

51
   m_mac->set_key(key, key_len);
40✔
52
}
40✔
53

54
uint32_t HOTP::generate_hotp(uint64_t counter) {
6,321✔
55
   m_mac->update_be(counter);
6,321✔
56
   const secure_vector<uint8_t> mac = m_mac->final();
6,321✔
57

58
   const size_t offset = mac[mac.size() - 1] & 0x0F;
6,321✔
59
   const uint32_t code = load_be<uint32_t>(mac.data() + offset, 0) & 0x7FFFFFFF;
6,321✔
60
   return hotp_truncate(code, m_digits);
6,321✔
61
}
6,321✔
62

63
std::pair<bool, uint64_t> HOTP::verify_hotp(uint32_t otp, uint64_t starting_counter, size_t resync_range) {
136✔
64
   for(size_t i = 0; i <= resync_range; ++i) {
6,296✔
65
      if(generate_hotp(starting_counter + i) == otp) {
6,230✔
66
         return std::make_pair(true, starting_counter + i + 1);
70✔
67
      }
68
   }
69
   return std::make_pair(false, starting_counter);
66✔
70
}
71

72
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc