From 950f989cf0d766551171d19a8a829f229b787d38 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Sat, 19 Jan 2019 12:46:44 -0800 Subject: [PATCH] ircd::crh: Add HMAC support. --- include/ircd/crh.h | 25 +++++++++ ircd/openssl.cc | 126 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/include/ircd/crh.h b/include/ircd/crh.h index 97b4f1fc3..d40ce7391 100644 --- a/include/ircd/crh.h +++ b/include/ircd/crh.h @@ -20,6 +20,7 @@ namespace ircd::crh IRCD_EXCEPTION(ircd::error, error) struct hash; + struct hmac; struct sha1; struct sha256; struct ripemd160; @@ -28,6 +29,7 @@ namespace ircd::crh // Export aliases down to ircd:: namespace ircd { + using crh::hmac; using crh::sha1; using crh::sha256; using crh::ripemd160; @@ -61,6 +63,29 @@ struct ircd::crh::hash virtual ~hash() noexcept; }; +struct ircd::crh::hmac +{ + struct ctx; + + protected: + std::unique_ptr ctx; + + public: + /// Returns the byte length of the mutable_buffer for digests + size_t length() const; + + /// Samples the digest and modifies the state (depending on impl) + const_buffer finalize(const mutable_buffer &b); + + /// Appends to the message + void update(const const_buffer &); + + hmac(const string_view &algorithm, const const_buffer &key); + hmac(hmac &&) = default; + hmac(const hmac &) = delete; + ~hmac() noexcept; +}; + /// SHA-1 hashing device. struct ircd::crh::sha1 final diff --git a/ircd/openssl.cc b/ircd/openssl.cc index 0c157369c..1cd7e2820 100644 --- a/ircd/openssl.cc +++ b/ircd/openssl.cc @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -1430,6 +1431,131 @@ ircd::openssl::init::~init() // crh.h // +// +// hmac +// + +struct ircd::crh::hmac::ctx +:HMAC_CTX +{ + static constexpr const size_t &MAX_CTXS {64}; + static thread_local allocator::fixed ctxs; + + static void *operator new(const size_t count); + static void operator delete(void *const ptr, const size_t count); + + ctx(const string_view &algorithm, const const_buffer &key); + ~ctx() noexcept; +}; + +decltype(ircd::crh::hmac::ctx::ctxs) +thread_local ircd::crh::hmac::ctx::ctxs +{}; + +void * +ircd::crh::hmac::ctx::operator new(const size_t bytes) +{ + assert(bytes > 0); + assert(bytes % sizeof(ctx) == 0); + return ctxs().allocate(bytes / sizeof(ctx)); +} + +void +ircd::crh::hmac::ctx::operator delete(void *const ptr, + const size_t bytes) +{ + if(!ptr) + return; + + assert(bytes % sizeof(ctx) == 0); + ctxs().deallocate(reinterpret_cast(ptr), bytes / sizeof(ctx)); +} + +// +// hmac::ctx::ctx +// + +ircd::crh::hmac::ctx::ctx(const string_view &algorithm, + const const_buffer &key) +:HMAC_CTX{0} +{ + const EVP_MD *const md + { + iequals(algorithm, "sha1")? + EVP_sha1(): + iequals(algorithm, "sha256")? + EVP_sha256(): + nullptr + }; + + if(unlikely(!md)) + throw error + { + "Algorithm '%s' not supported for HMAC", algorithm + }; + + HMAC_CTX_init(this); + openssl::call(::HMAC_Init_ex, this, data(key), size(key), md, nullptr); +} + +ircd::crh::hmac::ctx::~ctx() +noexcept +{ + HMAC_CTX_cleanup(this); +} + +// +// hmac::hmac +// + +ircd::crh::hmac::hmac(const string_view &algorithm, + const const_buffer &key) +:ctx +{ + std::make_unique(algorithm, key) +} +{ +} + +ircd::crh::hmac::~hmac() +noexcept +{ +} + +void +ircd::crh::hmac::update(const const_buffer &buf) +{ + assert(bool(ctx)); + const auto ptr + { + reinterpret_cast(data(buf)) + }; + + openssl::call(::HMAC_Update, ctx.get(), ptr, size(buf)); +} + +ircd::const_buffer +ircd::crh::hmac::finalize(const mutable_buffer &buf) +{ + assert(bool(ctx)); + const auto ptr + { + reinterpret_cast(data(buf)) + }; + + uint len; + openssl::call(::HMAC_Final, ctx.get(), ptr, &len); + return {data(buf), len}; +} + +size_t +ircd::crh::hmac::length() +const +{ + assert(bool(ctx)); + return HMAC_size(ctx.get()); +} + // // sha1 //