aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/kdf
diff options
context:
space:
mode:
authorKrzysztof Kwiatkowski <kris@amongbytes.com>2017-04-30 15:48:47 +0100
committerKrzysztof Kwiatkowski <kris@amongbytes.com>2017-05-03 00:44:28 +0100
commit576ada6d0b1ae20b781d487ba9bbeaadef17b202 (patch)
treeef0122d482dd6bbb36fe6a5fa82138bc6599dcaf /src/lib/kdf
parent29cc6bebe132a34f882d450b35a69bf71bb3e27b (diff)
Adds KDF based on SP 800-56A. Currently it is revision 1 (alternative 1). It should be extended to revision 2.
Diffstat (limited to 'src/lib/kdf')
-rw-r--r--src/lib/kdf/kdf.cpp14
-rw-r--r--src/lib/kdf/sp800_56a/info.txt7
-rw-r--r--src/lib/kdf/sp800_56a/sp800_56a.cpp51
-rw-r--r--src/lib/kdf/sp800_56a/sp800_56a.h58
4 files changed, 130 insertions, 0 deletions
diff --git a/src/lib/kdf/kdf.cpp b/src/lib/kdf/kdf.cpp
index 0e9d840c1..122719f6d 100644
--- a/src/lib/kdf/kdf.cpp
+++ b/src/lib/kdf/kdf.cpp
@@ -42,6 +42,10 @@
#include <botan/sp800_108.h>
#endif
+#if defined(BOTAN_HAS_SP800_56A)
+#include <botan/sp800_56a.h>
+#endif
+
#if defined(BOTAN_HAS_SP800_56C)
#include <botan/sp800_56c.h>
#endif
@@ -185,6 +189,16 @@ std::unique_ptr<KDF> KDF::create(const std::string& algo_spec,
}
#endif
+#if defined(BOTAN_HAS_SP800_56A)
+ 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()));
+ }
+ }
+#endif
+
#if defined(BOTAN_HAS_SP800_56C)
if(req.algo_name() == "SP800-56C" && req.arg_count() == 1)
{
diff --git a/src/lib/kdf/sp800_56a/info.txt b/src/lib/kdf/sp800_56a/info.txt
new file mode 100644
index 000000000..d8ef51673
--- /dev/null
+++ b/src/lib/kdf/sp800_56a/info.txt
@@ -0,0 +1,7 @@
+<defines>
+SP800_56A -> 20170501
+</defines>
+
+<requires>
+hmac
+</requires>
diff --git a/src/lib/kdf/sp800_56a/sp800_56a.cpp b/src/lib/kdf/sp800_56a/sp800_56a.cpp
new file mode 100644
index 000000000..9f5c1b1c5
--- /dev/null
+++ b/src/lib/kdf/sp800_56a/sp800_56a.cpp
@@ -0,0 +1,51 @@
+/*
+* KDF defined in NIST SP 800-56a (Approved Alternative 1)
+* (C) 2017 Krzysztof Kwiatkowski
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/sp800_56a.h>
+#include <botan/hmac.h>
+#include <botan/assert.h>
+#include <botan/mem_ops.h>
+
+namespace Botan {
+
+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
+{
+ // Salt is not used by this algorithm
+ BOTAN_UNUSED(salt, salt_len);
+
+ secure_vector<uint8_t> h;
+ const size_t digest_len = m_hash->output_length();
+
+ size_t reps = key_len / digest_len + !!(key_len % digest_len);
+ if (reps >= MAX_REPS) {
+ // See SP-800-56A, point 5.8.1
+ throw Invalid_Argument(
+ "key_len / digest output size "
+ "can't be bigger than 2^32 - 1");
+ }
+
+ uint32_t counter = 1;
+ 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);
+
+ 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);
+ }
+
+ return key_len;
+}
+
+}
diff --git a/src/lib/kdf/sp800_56a/sp800_56a.h b/src/lib/kdf/sp800_56a/sp800_56a.h
new file mode 100644
index 000000000..822f5ca1a
--- /dev/null
+++ b/src/lib/kdf/sp800_56a/sp800_56a.h
@@ -0,0 +1,58 @@
+/*
+* KDF defined in NIST SP 800-56a (Approved Alternative 1)
+* (C) 2016 Krzysztof Kwiatkowski
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_SP800_56A_H__
+#define BOTAN_SP800_56A_H__
+
+#include <botan/kdf.h>
+#include <botan/hash.h>
+
+namespace Botan {
+
+/**
+ * NIST SP 800-56A KDF
+ */
+class BOTAN_DLL SP800_56A final : public KDF
+ {
+ public:
+ std::string name() const override { return "SP800-56A(" + m_hash->name() + ")"; }
+
+ KDF* clone() const override { return new SP800_56A(m_hash->clone()); }
+
+ /**
+ * Derive a key using the SP800-56A KDF.
+ *
+ * The implementation hard codes the context value for the
+ * expansion step to the empty string.
+ *
+ * @param key derived keying material K_M
+ * @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_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
+ */
+ 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;
+
+ /**
+ * @param hash HASH algorithm used
+ */
+ explicit SP800_56A(HashFunction* hash) : m_hash(hash) {}
+ private:
+ std::unique_ptr<HashFunction> m_hash;
+ };
+}
+
+#endif
+