Botan 3.5.0
Crypto and TLS for C&
sp800_56c_one_step.cpp
Go to the documentation of this file.
1/*
2* KDF defined in NIST SP 800-56a revision 2 (Single-step key-derivation function)
3* or in NIST SP 800-56C revision 2 (Section 4 - One-Step KDM)
4*
5* (C) 2017 Ribose Inc. Written by Krzysztof Kwiatkowski.
6* (C) 2024 Fabian Albert - Rohde & Schwarz Cybersecurity
7*
8* Botan is released under the Simplified BSD License (see license.txt)
9*/
10
11#include <botan/internal/sp800_56c_one_step.h>
12
13#include <botan/exceptn.h>
14#include <botan/internal/bit_ops.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/kmac.h>
17
18#include <functional>
19
20namespace Botan {
21
22namespace {
23template <typename T>
24concept hash_or_mac_type = std::is_same_v<T, HashFunction> || std::is_same_v<T, MessageAuthenticationCode>;
25
26/**
27 * @brief One-Step Key Derivation as defined in SP800-56Cr2 Section 4
28 */
29template <hash_or_mac_type HashOrMacType>
30void kdm_internal(std::span<uint8_t> output_buffer,
31 std::span<const uint8_t> z,
32 std::span<const uint8_t> fixed_info,
33 HashOrMacType& hash_or_mac,
34 const std::function<void(HashOrMacType&)>& init_h_callback) {
35 size_t l = output_buffer.size() * 8;
36 // 1. If L > 0, then set reps = ceil(L / H_outputBits); otherwise,
37 // output an error indicator and exit this process without
38 // performing the remaining actions (i.e., omit steps 2 through 8).
39 BOTAN_ARG_CHECK(l > 0, "Zero KDM output length");
40 size_t reps = ceil_division(l, hash_or_mac.output_length() * 8);
41
42 // 2. If reps > (2^32 āˆ’ 1), then output an error indicator and exit this
43 // process without performing the remaining actions
44 // (i.e., omit steps 3 through 8).
45 BOTAN_ARG_CHECK(reps <= 0xFFFFFFFF, "Too large KDM output length");
46
47 // 3. Initialize a big-endian 4-byte unsigned integer counter as
48 // 0x00000000, corresponding to a 32-bit binary representation of
49 // the number zero.
50 uint32_t counter = 0;
51
52 // 4. If counter || Z || FixedInfo is more than max_H_inputBits bits
53 // long, then output an error indicator and exit this process
54 // without performing any of the remaining actions (i.e., omit
55 // steps 5 through 8). => SHA3 and KMAC are unlimited
56
57 // 5. Initialize Result(0) as an empty bit string
58 // (i.e., the null string).
60
61 // 6. For i = 1 to reps, do the following:
62 for(size_t i = 1; i <= reps; i++) {
63 // 6.1. Increment counter by 1.
64 counter++;
65 // Reset the hash/MAC object. For MAC, also set the key (salt) and IV.
66 hash_or_mac.clear();
67 init_h_callback(hash_or_mac);
68
69 // 6.2 Compute K(i) = H(counter || Z || FixedInfo).
70 hash_or_mac.update_be(counter);
71 hash_or_mac.update(z);
72 hash_or_mac.update(fixed_info);
73 auto k_i = hash_or_mac.final();
74
75 // 6.3. Set Result(i) = Result(iāˆ’1) || K(i).
76 result.insert(result.end(), k_i.begin(), k_i.end());
77 }
78
79 // 7. Set DerivedKeyingMaterial equal to the leftmost L bits of Result(reps).
80 copy_mem(output_buffer, std::span(result).subspan(0, output_buffer.size()));
81}
82
83} // namespace
84
86 size_t key_len,
87 const uint8_t secret[],
88 size_t secret_len,
89 const uint8_t salt[],
90 size_t salt_len,
91 const uint8_t label[],
92 size_t label_len) const {
93 BOTAN_UNUSED(salt);
94 BOTAN_ARG_CHECK(salt_len == 0, "SP800_56A_Hash does not support a non-empty salt");
95
96 kdm_internal<HashFunction>(
97 {key, key_len}, {secret, secret_len}, {label, label_len}, *m_hash, [](HashFunction&) { /* NOP */ });
98}
99
100std::string SP800_56C_One_Step_Hash::name() const {
101 return fmt("SP800-56A({})", m_hash->name());
102}
103
104std::unique_ptr<KDF> SP800_56C_One_Step_Hash::new_object() const {
105 return std::make_unique<SP800_56C_One_Step_Hash>(m_hash->new_object());
106}
107
108SP800_56C_One_Step_HMAC::SP800_56C_One_Step_HMAC(std::unique_ptr<MessageAuthenticationCode> mac) :
109 m_mac(std::move(mac)) {
110 // TODO: we need a MessageAuthenticationCode::is_hmac
111 if(!m_mac->name().starts_with("HMAC(")) {
112 throw Algorithm_Not_Found("Only HMAC can be used with SP800_56A_HMAC");
113 }
114}
115
117 size_t key_len,
118 const uint8_t secret[],
119 size_t secret_len,
120 const uint8_t salt[],
121 size_t salt_len,
122 const uint8_t label[],
123 size_t label_len) const {
124 kdm_internal<MessageAuthenticationCode>(
125 {key, key_len}, {secret, secret_len}, {label, label_len}, *m_mac, [&](MessageAuthenticationCode& kdf_mac) {
126 // 4.1 Option 2 and 3 - An implementation dependent byte string, salt,
127 // whose (non-null) value may be optionally provided in
128 // OtherInput, serves as the HMAC# key ..
129
130 // SP 800-56Cr2 specifies if the salt is empty then a block of zeros
131 // equal to the hash's underlying block size are used. However for HMAC
132 // this is equivalent to setting a zero-length key, so the same call
133 // works for either case.
134 kdf_mac.set_key(std::span{salt, salt_len});
135 });
136}
137
138std::string SP800_56C_One_Step_HMAC::name() const {
139 return fmt("SP800-56A({})", m_mac->name());
140}
141
142std::unique_ptr<KDF> SP800_56C_One_Step_HMAC::new_object() const {
143 return std::make_unique<SP800_56C_One_Step_HMAC>(m_mac->new_object());
144}
145
146// Option 3 - KMAC
148 size_t key_len,
149 const uint8_t secret[],
150 size_t secret_len,
151 const uint8_t salt[],
152 size_t salt_len,
153 const uint8_t label[],
154 size_t label_len) const {
155 auto mac = create_kmac_instance(key_len);
156 kdm_internal<MessageAuthenticationCode>(
157 {key, key_len}, {secret, secret_len}, {label, label_len}, *mac, [&](MessageAuthenticationCode& kdf_mac) {
158 // 4.1 Option 2 and 3 - An implementation dependent byte string, salt,
159 // whose (non-null) value may be optionally provided in
160 // OtherInput, serves as the KMAC# key ...
161 if(salt_len == 0) {
162 // 4.1 Implementation-Dependent Parameters 3
163 // If H(x) = KMAC128[or 256](salt, x, H_outputBits, "KDF"),
164 // then ā€“ in the absence of an agreed-upon alternative ā€“
165 // the default_salt shall be an all - zero string of
166 // 164 bytes [or 132 bytes]
167 kdf_mac.set_key(std::vector<uint8_t>(default_salt_length(), 0));
168 } else {
169 kdf_mac.set_key(std::span{salt, salt_len});
170 }
171
172 // 4.1 Option 3 - The "customization string" S shall be the byte string
173 // 01001011 || 01000100 || 01000110, which represents the sequence
174 // of characters 'K', 'D', and 'F' in 8-bit ASCII.
175 kdf_mac.start(std::array<uint8_t, 3>{'K', 'D', 'F'});
176 });
177}
178
179std::unique_ptr<MessageAuthenticationCode> SP800_56C_One_Step_KMAC128::create_kmac_instance(
180 size_t output_byte_len) const {
181 return std::make_unique<KMAC128>(output_byte_len * 8);
182}
183
184std::unique_ptr<MessageAuthenticationCode> SP800_56C_One_Step_KMAC256::create_kmac_instance(
185 size_t output_byte_len) const {
186 return std::make_unique<KMAC256>(output_byte_len * 8);
187}
188
189} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:118
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
virtual std::unique_ptr< MessageAuthenticationCode > create_kmac_instance(size_t output_byte_len) const =0
void kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const override
virtual size_t default_salt_length() const =0
See SP800-56C Section 4.1 - Implementation-Dependent Parameters 3.
SP800_56C_One_Step_HMAC(std::unique_ptr< MessageAuthenticationCode > mac)
void kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const override
std::string name() const override
std::unique_ptr< KDF > new_object() const override
std::string name() const override
std::unique_ptr< KDF > new_object() const override
void kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, const uint8_t salt[], size_t salt_len, const uint8_t label[], size_t label_len) const override
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr T ceil_division(T a, T b)
Definition bit_ops.h:149
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146