/src/botan/src/lib/kdf/sp800_56a/sp800_56a.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include <botan/internal/scan_name.h> |
11 | | #include <botan/exceptn.h> |
12 | | |
13 | | namespace Botan { |
14 | | |
15 | | namespace { |
16 | | |
17 | | template<class AuxiliaryFunction_t> |
18 | | void 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 | 0 | { |
24 | 0 | const uint64_t kRepsUpperBound = (1ULL << 32); |
25 | |
|
26 | 0 | const size_t digest_len = auxfunc.output_length(); |
27 | |
|
28 | 0 | const size_t reps = key_len / digest_len + ((key_len % digest_len) ? 1 : 0); |
29 | |
|
30 | 0 | if (reps >= kRepsUpperBound) |
31 | 0 | { |
32 | | // See SP-800-56A, point 5.8.1 |
33 | 0 | throw Invalid_Argument("SP800-56A KDF requested output too large"); |
34 | 0 | } |
35 | | |
36 | 0 | uint32_t counter = 1; |
37 | 0 | secure_vector<uint8_t> result; |
38 | 0 | for(size_t i = 0; i < reps; i++) |
39 | 0 | { |
40 | 0 | auxfunc.update_be(counter++); |
41 | 0 | auxfunc.update(secret, secret_len); |
42 | 0 | auxfunc.update(label, label_len); |
43 | 0 | auxfunc.final(result); |
44 | |
|
45 | 0 | const size_t offset = digest_len * i; |
46 | 0 | const size_t len = std::min(result.size(), key_len - offset); |
47 | 0 | copy_mem(&key[offset], result.data(), len); |
48 | 0 | } |
49 | 0 | } Unexecuted instantiation: sp800_56a.cpp:void Botan::(anonymous namespace)::SP800_56A_kdf<Botan::HashFunction>(Botan::HashFunction&, unsigned char*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long) Unexecuted instantiation: sp800_56a.cpp:void Botan::(anonymous namespace)::SP800_56A_kdf<Botan::MessageAuthenticationCode>(Botan::MessageAuthenticationCode&, unsigned char*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long) |
50 | | |
51 | | } |
52 | | |
53 | | void SP800_56A_Hash::kdf(uint8_t key[], size_t key_len, |
54 | | const uint8_t secret[], size_t secret_len, |
55 | | const uint8_t salt[], size_t salt_len, |
56 | | const uint8_t label[], size_t label_len) const |
57 | 0 | { |
58 | | /* |
59 | | * TODO: should we reject a non-empty salt with an exception? |
60 | | * Ignoring the salt seems quite dangerous to applications which |
61 | | * don't expect it. |
62 | | */ |
63 | 0 | BOTAN_UNUSED(salt, salt_len); |
64 | |
|
65 | 0 | SP800_56A_kdf(*m_hash, key, key_len, secret, secret_len, label, label_len); |
66 | 0 | } |
67 | | |
68 | | SP800_56A_HMAC::SP800_56A_HMAC(std::unique_ptr<MessageAuthenticationCode> mac) : m_mac(std::move(mac)) |
69 | 0 | { |
70 | | // TODO: we need a MessageAuthenticationCode::is_hmac |
71 | 0 | const SCAN_Name req(m_mac->name()); |
72 | 0 | if(req.algo_name() != "HMAC") |
73 | 0 | { |
74 | 0 | throw Algorithm_Not_Found("Only HMAC can be used with KDF SP800-56A"); |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | void SP800_56A_HMAC::kdf(uint8_t key[], size_t key_len, |
79 | | const uint8_t secret[], size_t secret_len, |
80 | | const uint8_t salt[], size_t salt_len, |
81 | | const uint8_t label[], size_t label_len) const |
82 | 0 | { |
83 | | /* |
84 | | * SP 800-56A specifies if the salt is empty then a block of zeros |
85 | | * equal to the hash's underlying block size are used. However this |
86 | | * is equivalent to setting a zero-length key, so the same call |
87 | | * works for either case. |
88 | | */ |
89 | 0 | m_mac->set_key(salt, salt_len); |
90 | |
|
91 | 0 | SP800_56A_kdf(*m_mac, key, key_len, secret, secret_len, label, label_len); |
92 | 0 | } |
93 | | |
94 | | |
95 | | |
96 | | } |