blob: e4dc6e5e336b1a4f7b610fffb4ea8cf588c753ff (
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
62
63
|
/*
* 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)
{
uint8_t counter8[8] = { 0 };
store_be(counter, counter8);
m_mac->update(counter8, sizeof(counter8));
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);
}
}
|