Botan 3.13.0
Crypto and TLS for C&
hmac.cpp
Go to the documentation of this file.
1/*
2* HMAC
3* (C) 1999-2007,2014,2020 Jack Lloyd
4* 2007 Yves Jerschow
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/hmac.h>
10
11#include <botan/exceptn.h>
12#include <botan/mem_ops.h>
13#include <botan/internal/ct_utils.h>
14#include <botan/internal/fmt.h>
15
16namespace Botan {
17
18/*
19* Update a HMAC Calculation
20*/
21void HMAC::add_data(std::span<const uint8_t> input) {
23 m_hash->update(input);
24}
25
26/*
27* Finalize a HMAC Calculation
28*/
29void HMAC::final_result(std::span<uint8_t> mac) {
31 m_hash->final(mac);
32 m_hash->update(m_okey);
33 m_hash->update(mac.first(m_hash_output_length));
34 m_hash->final(mac);
35 m_hash->update(m_ikey);
36}
37
38void HMAC::start_msg(std::span<const uint8_t> nonce) {
39 if(!nonce.empty()) {
40 throw Invalid_IV_Length(name(), nonce.size());
41 }
43
44 m_hash->clear();
45 m_hash->update(m_ikey);
46}
47
49 // Support very long lengths for things like PBKDF2 and the TLS PRF
50 return Key_Length_Specification(0, 8192);
51}
52
53size_t HMAC::output_length() const {
54 return m_hash_output_length;
55}
56
58 return !m_okey.empty();
59}
60
61/*
62* HMAC Key Schedule
63*/
64void HMAC::key_schedule(std::span<const uint8_t> key) {
65 const uint8_t ipad = 0x36;
66 const uint8_t opad = 0x5C;
67
68 m_hash->clear();
69
70 m_ikey.resize(m_hash_block_size);
71 m_okey.resize(m_hash_block_size);
72
73 clear_mem(m_ikey.data(), m_ikey.size());
74 clear_mem(m_okey.data(), m_okey.size());
75
76 /*
77 * Sometimes the HMAC key length itself is sensitive, as with PBKDF2 where it
78 * reveals the length of the passphrase. Make some attempt to hide this to
79 * side channels. Clearly if the secret is longer than the block size then the
80 * branch to hash first reveals that. In addition, counting the number of
81 * compression functions executed reveals the size at the granularity of the
82 * hash function's block size.
83 *
84 * The greater concern is for smaller keys; being able to detect when a
85 * passphrase is say 4 bytes may assist choosing weaker targets. Even though
86 * the loop bounds are constant, we can only actually read key[0..length] so
87 * it doesn't seem possible to make this computation truly constant time.
88 *
89 * We don't mind leaking if the length is exactly zero since that's
90 * trivial to simply check.
91 */
92
93 if(key.size() > m_hash_block_size) {
94 m_hash->update(key);
95 m_hash->final(m_ikey.data());
96 } else if(key.size() >= 20) {
97 // For long keys we just leak the length either it is a cryptovariable
98 // or a long enough password that just the length is not a useful signal
99 copy_mem(std::span{m_ikey}.first(key.size()), key);
100 } else if(!key.empty()) {
101 for(size_t i = 0, i_mod_length = 0; i != m_hash_block_size; ++i) {
102 /*
103 access key[i % length] but avoiding division due to variable
104 time computation on some processors.
105 */
106 auto needs_reduction = CT::Mask<size_t>::is_lte(key.size(), i_mod_length);
107 i_mod_length = needs_reduction.select(0, i_mod_length);
108 const uint8_t kb = key[i_mod_length];
109
110 auto in_range = CT::Mask<size_t>::is_lt(i, key.size());
111 m_ikey[i] = static_cast<uint8_t>(in_range.if_set_return(kb));
112 i_mod_length += 1;
113 }
114 }
115
116 for(size_t i = 0; i != m_hash_block_size; ++i) {
117 m_ikey[i] ^= ipad;
118 m_okey[i] = m_ikey[i] ^ ipad ^ opad;
119 }
120
121 m_hash->update(m_ikey);
122}
123
124/*
125* Clear memory of sensitive data
126*/
128 m_hash->clear();
129 zap(m_ikey);
130 zap(m_okey);
131}
132
133/*
134* Return the name of this type
135*/
136std::string HMAC::name() const {
137 return fmt("HMAC({})", m_hash->name());
138}
139
140/*
141* Return a new_object of this object
142*/
143std::unique_ptr<MessageAuthenticationCode> HMAC::new_object() const {
144 return std::make_unique<HMAC>(m_hash->new_object());
145}
146
147/*
148* HMAC Constructor
149*/
150HMAC::HMAC(std::unique_ptr<HashFunction> hash) :
151 m_hash(std::move(hash)),
152 m_hash_output_length(m_hash->output_length()),
153 m_hash_block_size(m_hash->hash_block_size()) {
154 BOTAN_ARG_CHECK(m_hash_output_length >= 8, "HMAC is not compatible with this hash function");
155 BOTAN_ARG_CHECK(m_hash_block_size >= m_hash_output_length, "HMAC is not compatible with this hash function");
156}
157
158} // namespace Botan
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
static constexpr Mask< T > is_lte(T x, T y)
Definition ct_utils.h:463
static constexpr Mask< T > is_lt(T x, T y)
Definition ct_utils.h:450
bool has_keying_material() const override
Definition hmac.cpp:57
size_t output_length() const override
Definition hmac.cpp:53
std::string name() const override
Definition hmac.cpp:136
std::unique_ptr< MessageAuthenticationCode > new_object() const override
Definition hmac.cpp:143
Key_Length_Specification key_spec() const override
Definition hmac.cpp:48
HMAC(std::unique_ptr< HashFunction > hash)
Definition hmac.cpp:150
void clear() override
Definition hmac.cpp:127
void assert_key_material_set() const
Definition sym_algo.h:180
void zap(std::vector< T, Alloc > &vec)
Definition secmem.h:261
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118