Botan  2.4.0
Crypto and TLS for C++11
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 
13 namespace Botan {
14 
15 namespace {
16 
17 template<class AuxiliaryFunction_t>
18 size_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 
55 size_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  */
65  BOTAN_UNUSED(salt, salt_len);
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 
80 size_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 }
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
size_t salt_len
Definition: x509_obj.cpp:25
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:97
Definition: alg_id.cpp:13
#define BOTAN_UNUSED(...)
Definition: assert.h:106
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:80