From f4fe636cb0f7ce02592e2f8593eace97590b9d3f Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 2 Mar 2015 00:06:47 +1100 Subject: [PATCH] hash/hmac: add simple HMAC-MD5 --- Makefile.am | 3 ++ hash/hmac.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++ hash/hmac.hpp | 47 +++++++++++++++++++++++ test/hmac.cpp | 67 +++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 hash/hmac.cpp create mode 100644 hash/hmac.hpp create mode 100644 test/hmac.cpp diff --git a/Makefile.am b/Makefile.am index fd2e19d3..4393bb8a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,8 @@ UTIL_FILES = \ hash/crc.cpp \ hash/crc.hpp \ hash/fletcher.hpp \ + hash/hmac.cpp \ + hash/hmac.hpp \ hash/md2.cpp \ hash/md2.hpp \ hash/md4.cpp \ @@ -238,6 +240,7 @@ TEST_BIN = \ test/extent \ test/fixed \ test/float \ + test/hmac \ test/hton \ test/ip \ test/json_types \ diff --git a/hash/hmac.cpp b/hash/hmac.cpp new file mode 100644 index 00000000..7088fdf4 --- /dev/null +++ b/hash/hmac.cpp @@ -0,0 +1,102 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2015 Danny Robson + */ + +#include "hmac.hpp" + +#include "debug.hpp" + +#include + +using util::hash::HMAC; + + +//----------------------------------------------------------------------------- +static const uint8_t IFILL = 0x36; +static const uint8_t OFILL = 0x5C; + + +//----------------------------------------------------------------------------- +HMAC::HMAC (const uint8_t *restrict key, size_t len) +{ + CHECK (key); + CHECK_LE (len, m_ikey.size ()); + CHECK_LE (len, m_okey.size ()); + + static_assert (sizeof (m_ikey) == sizeof (m_okey), "key padding must match"); + + + std::copy (key, key + len, m_ikey.begin ()); + std::fill (m_ikey.begin () + len, + m_ikey.end (), + 0); + + m_okey = m_ikey; + + std::transform (m_ikey.begin (), + m_ikey.end (), + m_ikey.begin (), + [] (auto v) { return v ^ IFILL; }); + + std::transform (m_okey.begin (), + m_okey.end (), + m_okey.begin (), + [] (auto v) { return v ^ OFILL; }); + + m_hash.update (m_ikey.data (), m_ikey.size ()); +} + + + +//----------------------------------------------------------------------------- +void +HMAC::update (const void *restrict data, size_t len) +{ + m_hash.update ((const uint8_t*)data, len); +} + + +//----------------------------------------------------------------------------- +void +HMAC::finish (void) +{ + m_hash.finish (); + auto d = m_hash.digest (); + + m_hash.reset (); + m_hash.update (m_okey.data (), m_okey.size ()); + m_hash.update (d.data (), d.size ()); + m_hash.finish (); +} + + +//----------------------------------------------------------------------------- +void +HMAC::reset (void) +{ + m_hash.reset (); + m_hash.update (m_ikey.data (), m_ikey.size ()); +} + + +//----------------------------------------------------------------------------- +HMAC::digest_t +HMAC::digest (void) +{ + return m_hash.digest (); +} diff --git a/hash/hmac.hpp b/hash/hmac.hpp new file mode 100644 index 00000000..e187acb4 --- /dev/null +++ b/hash/hmac.hpp @@ -0,0 +1,47 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2015 Danny Robson + */ + +#ifndef __UTIL_HASH_HMAC_HPP +#define __UTIL_HASH_HMAC_HPP + +#include "md5.hpp" + +namespace util { namespace hash { + /// RFC 2104 key-hashing for message authentication + class HMAC { + public: + using digest_t = MD5::digest_t; + + HMAC (const uint8_t *key, size_t); + + void update (const void *restrict, size_t); + void finish (void); + void reset (void); + + digest_t digest (void); + + private: + std::array m_ikey; + std::array m_okey; + + MD5 m_hash; + }; +} } + +#endif diff --git a/test/hmac.cpp b/test/hmac.cpp new file mode 100644 index 00000000..4a13c953 --- /dev/null +++ b/test/hmac.cpp @@ -0,0 +1,67 @@ +#include "hash/hmac.hpp" +#include "types.hpp" +#include "debug.hpp" + +#include +#include + +using util::hash::HMAC; + + +static const struct { + std::vector key; + std::vector dat; + HMAC::digest_t res; +} TESTS[] = { + // RFC 2104 test data, MD5 + { + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }, + { 'H', 'i', ' ', 'T', 'h', 'e', 'r', 'e' }, + { { 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, + 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d } } + }, + + { + { 'J', 'e', 'f', 'e' }, + { 'w', 'h', 'a', 't', ' ', 'd', 'o', ' ', + 'y', 'a', ' ', 'w', 'a', 'n', 't', ' ', + 'f', 'o', 'r', ' ', 'n', 'o', 't', 'h', + 'i', 'n', 'g', '?' }, + { { 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, + 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 } } + }, + + { + { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA }, + { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD }, + { { 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88, + 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 } } + } +}; + + + + + +int +main (int, char**) +{ + for (const auto &t: TESTS) { + util::hash::HMAC h (t.key.data (), t.key.size ()); + h.update (t.dat.data (), t.dat.size ()); + h.finish (); + + if (h.digest () != t.res) + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +}