Botan 2.19.2
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/sp800_56a.h>
10#include <botan/scan_name.h>
11#include <botan/exceptn.h>
12
13namespace Botan {
14
15namespace {
16
17template<class AuxiliaryFunction_t>
18size_t SP800_56A_kdf(
19 AuxiliaryFunction_t& auxfunc,
20 uint8_t key[], size_t key_len,
21 const uint8_t secret[], size_t secret_len,
22 const uint8_t label[], size_t label_len)
23 {
24 const uint64_t kRepsUpperBound = (1ULL << 32);
25
26 const size_t digest_len = auxfunc.output_length();
27
28 const size_t reps = key_len / digest_len + ((key_len % digest_len) ? 1 : 0);
29
30 if (reps >= kRepsUpperBound)
31 {
32 // See SP-800-56A, point 5.8.1
33 throw Invalid_Argument("SP800-56A KDF requested output too large");
34 }
35
36 uint32_t counter = 1;
37 secure_vector<uint8_t> result;
38 for(size_t i = 0; i < reps; i++)
39 {
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 return key_len;
51 }
52
53}
54
55size_t SP800_56A_Hash::kdf(uint8_t key[], size_t key_len,
56 const uint8_t secret[], size_t secret_len,
57 const uint8_t salt[], size_t salt_len,
58 const uint8_t label[], size_t label_len) const
59 {
60 /*
61 * TODO: should we reject a non-empty salt with an exception?
62 * Ignoring the salt seems quite dangerous to applications which
63 * don't expect it.
64 */
66
67 return SP800_56A_kdf(*m_hash, key, key_len, secret, secret_len, label, label_len);
68 }
69
71 {
72 // TODO: we need a MessageAuthenticationCode::is_hmac
73 const SCAN_Name req(m_mac->name());
74 if(req.algo_name() != "HMAC")
75 {
76 throw Algorithm_Not_Found("Only HMAC can be used with KDF SP800-56A");
77 }
78 }
79
80size_t SP800_56A_HMAC::kdf(uint8_t key[], size_t key_len,
81 const uint8_t secret[], size_t secret_len,
82 const uint8_t salt[], size_t salt_len,
83 const uint8_t label[], size_t label_len) const
84 {
85 /*
86 * SP 800-56A specifies if the salt is empty then a block of zeros
87 * equal to the hash's underlying block size are used. However this
88 * is equivalent to setting a zero-length key, so the same call
89 * works for either case.
90 */
91 m_mac->set_key(salt, salt_len);
92
93 return SP800_56A_kdf(*m_mac, key, key_len, secret, secret_len, label, label_len);
94 }
95
96
97
98}
#define BOTAN_UNUSED(...)
Definition: assert.h:142
const std::string & algo_name() const
Definition: scan_name.h:51
size_t 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:80
SP800_56A_HMAC(MessageAuthenticationCode *mac)
Definition: sp800_56a.cpp:70
size_t 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:55
Definition: alg_id.cpp:13
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
size_t salt_len
Definition: x509_obj.cpp:25