aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/misc/hotp/hotp.cpp
blob: c4c0c7770c818ec1d1552f7c9b5367ccbacc6052 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
* HOTP
* (C) 2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/hotp.h>
#include <botan/exceptn.h>

namespace Botan {

HOTP::HOTP(const SymmetricKey& key, const std::string& hash_algo, size_t digits)
   {
   BOTAN_ARG_CHECK(digits == 6 || digits == 7 || digits == 8, "Invalid HOTP digits");

   if(digits == 6)
      m_digit_mod = 1000000;
   else if(digits == 7)
      m_digit_mod = 10000000;
   else if(digits == 8)
      m_digit_mod = 100000000;

   /*
   RFC 4228 only supports SHA-1 but TOTP allows SHA-256 and SHA-512
   and some HOTP libs support one or both as extensions
   */
   if(hash_algo == "SHA-1")
      m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-1)");
   else if(hash_algo == "SHA-256")
      m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
   else if(hash_algo == "SHA-512")
      m_mac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
   else
      throw Invalid_Argument("Unsupported HOTP hash function");

   m_mac->set_key(key);
   }

uint32_t HOTP::generate_hotp(uint64_t counter)
   {
   m_mac->update_be(counter);
   const secure_vector<uint8_t> mac = m_mac->final();

   const size_t offset = mac[mac.size()-1] & 0x0F;
   const uint32_t code = load_be<uint32_t>(mac.data() + offset, 0) & 0x7FFFFFFF;
   return code % m_digit_mod;
   }

std::pair<bool,uint64_t> HOTP::verify_hotp(uint32_t otp, uint64_t starting_counter, size_t resync_range)
   {
   for(size_t i = 0; i <= resync_range; ++i)
      {
      if(generate_hotp(starting_counter + i) == otp)
         return std::make_pair(true, starting_counter + i + 1);
      }
   return std::make_pair(false, starting_counter);
   }

}