Botan 3.4.0
Crypto and TLS for C&
sp800_56a.cpp
Go to the documentation of this file.
1/*
2* KDF defined in NIST SP 800-56a (Approved Alternative 1)
3*
4* (C) 2017 Ribose Inc. Written by Krzysztof Kwiatkowski.
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/sp800_56a.h>
10
11#include <botan/exceptn.h>
12#include <botan/internal/fmt.h>
13
14namespace Botan {
15
16namespace {
17
18template <class AuxiliaryFunction_t>
19void SP800_56A_kdf(AuxiliaryFunction_t& auxfunc,
20 uint8_t key[],
21 size_t key_len,
22 const uint8_t secret[],
23 size_t secret_len,
24 const uint8_t label[],
25 size_t label_len) {
26 const uint64_t kRepsUpperBound = (1ULL << 32);
27
28 const size_t digest_len = auxfunc.output_length();
29
30 const size_t reps = key_len / digest_len + ((key_len % digest_len) ? 1 : 0);
31
32 if(reps >= kRepsUpperBound) {
33 // See SP-800-56A, point 5.8.1
34 throw Invalid_Argument("SP800-56A KDF requested output too large");
35 }
36
37 uint32_t counter = 1;
38 secure_vector<uint8_t> result;
39 for(size_t i = 0; i < reps; i++) {
40 auxfunc.update_be(counter++);
41 auxfunc.update(secret, secret_len);
42 auxfunc.update(label, label_len);
43 auxfunc.final(result);
44
45 const size_t offset = digest_len * i;
46 const size_t len = std::min(result.size(), key_len - offset);
47 copy_mem(&key[offset], result.data(), len);
48 }
49}
50
51} // namespace
52
53void SP800_56A_Hash::kdf(uint8_t key[],
54 size_t key_len,
55 const uint8_t secret[],
56 size_t secret_len,
57 const uint8_t salt[],
58 size_t salt_len,
59 const uint8_t label[],
60 size_t label_len) const {
61 BOTAN_UNUSED(salt);
62
63 if(salt_len > 0) {
64 throw Invalid_Argument("SP800_56A_Hash does not support a non-empty salt");
65 }
66
67 SP800_56A_kdf(*m_hash, key, key_len, secret, secret_len, label, label_len);
68}
69
70std::string SP800_56A_Hash::name() const {
71 return fmt("SP800-56A({})", m_hash->name());
72}
73
74std::unique_ptr<KDF> SP800_56A_Hash::new_object() const {
75 return std::make_unique<SP800_56A_Hash>(m_hash->new_object());
76}
77
78SP800_56A_HMAC::SP800_56A_HMAC(std::unique_ptr<MessageAuthenticationCode> mac) : m_mac(std::move(mac)) {
79 // TODO: we need a MessageAuthenticationCode::is_hmac
80 if(!m_mac->name().starts_with("HMAC(")) {
81 throw Algorithm_Not_Found("Only HMAC can be used with KDF SP800-56A");
82 }
83}
84
85void SP800_56A_HMAC::kdf(uint8_t key[],
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 /*
94 * SP 800-56A specifies if the salt is empty then a block of zeros
95 * equal to the hash's underlying block size are used. However this
96 * is equivalent to setting a zero-length key, so the same call
97 * works for either case.
98 */
99 m_mac->set_key(salt, salt_len);
100
101 SP800_56A_kdf(*m_mac, key, key_len, secret, secret_len, label, label_len);
102}
103
104std::string SP800_56A_HMAC::name() const {
105 return fmt("SP800-56A({})", m_mac->name());
106}
107
108std::unique_ptr<KDF> SP800_56A_HMAC::new_object() const {
109 return std::make_unique<SP800_56A_HMAC>(m_mac->new_object());
110}
111
112} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:118
SP800_56A_HMAC(std::unique_ptr< MessageAuthenticationCode > mac)
Definition sp800_56a.cpp:78
std::string name() 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
Definition sp800_56a.cpp:85
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
Definition sp800_56a.cpp:53
std::string name() const override
Definition sp800_56a.cpp:70
std::unique_ptr< KDF > new_object() const override
Definition sp800_56a.cpp:74
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