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