diff options
-rw-r--r-- | src/lib/kdf/kdf.cpp | 6 | ||||
-rw-r--r-- | src/lib/kdf/sp800_56a/sp800_56a.cpp | 78 | ||||
-rw-r--r-- | src/lib/kdf/sp800_56a/sp800_56a.h | 19 |
3 files changed, 74 insertions, 29 deletions
diff --git a/src/lib/kdf/kdf.cpp b/src/lib/kdf/kdf.cpp index 122719f6d..695523d8e 100644 --- a/src/lib/kdf/kdf.cpp +++ b/src/lib/kdf/kdf.cpp @@ -193,9 +193,9 @@ std::unique_ptr<KDF> KDF::create(const std::string& algo_spec, if(req.algo_name() == "SP800-56A" && req.arg_count() == 1) { if(auto hash = HashFunction::create(req.arg(0))) - { - return std::unique_ptr<KDF>(new SP800_56A(hash.release())); - } + return std::unique_ptr<KDF>(new SP800_56A<HashFunction>(hash.release())); + if(auto mac = MessageAuthenticationCode::create(req.arg(0))) + return std::unique_ptr<KDF>(new SP800_56A<MessageAuthenticationCode>(mac.release())); } #endif diff --git a/src/lib/kdf/sp800_56a/sp800_56a.cpp b/src/lib/kdf/sp800_56a/sp800_56a.cpp index 9f5c1b1c5..c01f128b7 100644 --- a/src/lib/kdf/sp800_56a/sp800_56a.cpp +++ b/src/lib/kdf/sp800_56a/sp800_56a.cpp @@ -7,23 +7,64 @@ #include <botan/sp800_56a.h> #include <botan/hmac.h> -#include <botan/assert.h> -#include <botan/mem_ops.h> +#include <botan/scan_name.h> +#include <botan/exceptn.h> namespace Botan { +namespace { static const size_t MAX_REPS = (2ULL << 32); -size_t SP800_56A::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 +// Option1: auxiliary function is a hash function +template<typename T> +void Init( + T *t, + const uint8_t salt[], + const size_t salt_len) { - // Salt is not used by this algorithm - BOTAN_UNUSED(salt, salt_len); + BOTAN_UNUSED(t, salt, salt_len); +} + +// Option1: auxiliary function is a HMAC function +template<> +void Init<MessageAuthenticationCode>( + MessageAuthenticationCode *hmac_func, + const uint8_t salt[], + const size_t salt_len) +{ + const SCAN_Name req(hmac_func->name()); + if(req.algo_name() != "HMAC") { + throw Algorithm_Not_Found("Only HMAC can be used with KDF SP800-56A"); + } + + if (salt_len) { + hmac_func->set_key(salt, salt_len); + } else { + /* 5.8.1.1: Salt shall be an all-zero string whose bit length + equals that specified as the length of the input block for + the hash function */ + auto hash = HashFunction::create(req.arg(0)); + if (!hash) { + // Should never happen + throw Algorithm_Not_Found(req.arg(0)); + } + + secure_vector<uint8_t> s(hash->hash_block_size(), 0); + hmac_func->set_key(s.data(), s.size()); + } +} +} - secure_vector<uint8_t> h; - const size_t digest_len = m_hash->output_length(); +template<class AuxiliaryFunction_t> +size_t SP800_56A<AuxiliaryFunction_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 +{ + + Init<AuxiliaryFunction_t>(m_auxfunc.get(), salt, salt_len); + const size_t digest_len = m_auxfunc->output_length(); size_t reps = key_len / digest_len + !!(key_len % digest_len); if (reps >= MAX_REPS) { @@ -34,18 +75,23 @@ size_t SP800_56A::kdf( uint8_t key[], size_t key_len, } uint32_t counter = 1; + secure_vector<uint8_t> result; for(size_t i = 0; i < reps; i++) { - m_hash->update_be(counter++); - m_hash->update(secret, secret_len); - m_hash->update(label, label_len); - m_hash->final(h); + m_auxfunc->update_be(counter++); + m_auxfunc->update(secret, secret_len); + m_auxfunc->update(label, label_len); + m_auxfunc->final(result); const size_t offset = digest_len * i; - const size_t len = std::min(h.size(), key_len - offset); - copy_mem(&key[offset], h.data(), len); + const size_t len = std::min(result.size(), key_len - offset); + copy_mem(&key[offset], result.data(), len); } return key_len; } +/* Template initialization */ +template class SP800_56A<MessageAuthenticationCode>; +template class SP800_56A<HashFunction>; + } diff --git a/src/lib/kdf/sp800_56a/sp800_56a.h b/src/lib/kdf/sp800_56a/sp800_56a.h index 822f5ca1a..268574807 100644 --- a/src/lib/kdf/sp800_56a/sp800_56a.h +++ b/src/lib/kdf/sp800_56a/sp800_56a.h @@ -1,5 +1,5 @@ /* -* KDF defined in NIST SP 800-56a (Approved Alternative 1) +* KDF defined in NIST SP 800-56a revision 2 (Single-step key-derivation function) * (C) 2016 Krzysztof Kwiatkowski * * Botan is released under the Simplified BSD License (see license.txt) @@ -9,19 +9,19 @@ #define BOTAN_SP800_56A_H__ #include <botan/kdf.h> -#include <botan/hash.h> namespace Botan { /** * NIST SP 800-56A KDF */ +template<class AuxiliaryFunction_t> class BOTAN_DLL SP800_56A final : public KDF { public: - std::string name() const override { return "SP800-56A(" + m_hash->name() + ")"; } + std::string name() const override { return "SP800-56A(" + m_auxfunc->name() + ")"; } - KDF* clone() const override { return new SP800_56A(m_hash->clone()); } + KDF* clone() const override { return new SP800_56A(m_auxfunc->clone()); } /** * Derive a key using the SP800-56A KDF. @@ -33,12 +33,12 @@ class BOTAN_DLL SP800_56A final : public KDF * @param key_len the desired output length in bytes * @param secret shared secret Z * @param secret_len size of Z in bytes - * @param salt salt not used by an algorithm + * @param salt salt used only if HMAC is used as a hash function * @param salt_len not used by an algorithm * @param label label for the expansion step * @param label_len size of label in bytes * - * @throws Invalid_Argument key_len > 2^32 + * @throws Invalid_Argument key_len > 2^32 or MAC is not a HMAC */ size_t kdf(uint8_t key[], size_t key_len, const uint8_t secret[], size_t secret_len, @@ -46,13 +46,12 @@ class BOTAN_DLL SP800_56A final : public KDF const uint8_t label[], size_t label_len) const override; /** - * @param hash HASH algorithm used + * @param auxfunc HASH or HMAC algorithm to be used as auxiliary function */ - explicit SP800_56A(HashFunction* hash) : m_hash(hash) {} + explicit SP800_56A(AuxiliaryFunction_t* auxfunc) : m_auxfunc(auxfunc) {} private: - std::unique_ptr<HashFunction> m_hash; + std::unique_ptr<AuxiliaryFunction_t> m_auxfunc; }; } #endif - |