aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrzysztof Kwiatkowski <[email protected]>2017-05-02 23:17:32 +0100
committerKrzysztof Kwiatkowski <[email protected]>2017-05-03 00:44:35 +0100
commit827a62c7880d1f1b15010e088195f20a8b6304ec (patch)
treece53ae95a8a8eb39d8b1d403c81372cd15a6acc6
parent576ada6d0b1ae20b781d487ba9bbeaadef17b202 (diff)
SP800-56A revision 2 implementation
-rw-r--r--src/lib/kdf/kdf.cpp6
-rw-r--r--src/lib/kdf/sp800_56a/sp800_56a.cpp78
-rw-r--r--src/lib/kdf/sp800_56a/sp800_56a.h19
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
-