Coverage Report

Created: 2025-04-11 06:34

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