From cedcf90c3f351599b48c32fff0f3e4a7190c93c6 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 2 Mar 2015 01:21:52 +1100 Subject: [PATCH] hash/hmac: add HMAC-SHA1 support --- hash/hmac.cpp | 27 +++++-- hash/hmac.hpp | 13 ++-- hash/md5.hpp | 2 + hash/sha1.hpp | 2 + test/hmac.cpp | 192 ++++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 203 insertions(+), 33 deletions(-) diff --git a/hash/hmac.cpp b/hash/hmac.cpp index 5ec56544..94845c9a 100644 --- a/hash/hmac.cpp +++ b/hash/hmac.cpp @@ -32,14 +32,15 @@ static const uint8_t OFILL = 0x5C; //----------------------------------------------------------------------------- -HMAC::HMAC (const uint8_t *restrict key, size_t len) +template +HMAC::HMAC (const uint8_t *restrict key, size_t len) { CHECK (key); static_assert (sizeof (m_ikey) == sizeof (m_okey), "key padding must match"); // If the key is larger than the blocklength, use the hash of the key - if (len > 64) { + if (len > T::BLOCK_SIZE) { m_hash.update (key, len); m_hash.finish (); @@ -74,16 +75,18 @@ HMAC::HMAC (const uint8_t *restrict key, size_t len) //----------------------------------------------------------------------------- +template void -HMAC::update (const void *restrict data, size_t len) +HMAC::update (const void *restrict data, size_t len) { m_hash.update ((const uint8_t*)data, len); } //----------------------------------------------------------------------------- +template void -HMAC::finish (void) +HMAC::finish (void) { m_hash.finish (); auto d = m_hash.digest (); @@ -96,8 +99,9 @@ HMAC::finish (void) //----------------------------------------------------------------------------- +template void -HMAC::reset (void) +HMAC::reset (void) { m_hash.reset (); m_hash.update (m_ikey.data (), m_ikey.size ()); @@ -105,8 +109,17 @@ HMAC::reset (void) //----------------------------------------------------------------------------- -HMAC::digest_t -HMAC::digest (void) +template +typename HMAC::digest_t +HMAC::digest (void) { return m_hash.digest (); } + + +//----------------------------------------------------------------------------- +#include "md5.hpp" +#include "sha1.hpp" + +template class HMAC; +template class HMAC; diff --git a/hash/hmac.hpp b/hash/hmac.hpp index e187acb4..ede1e758 100644 --- a/hash/hmac.hpp +++ b/hash/hmac.hpp @@ -20,13 +20,16 @@ #ifndef __UTIL_HASH_HMAC_HPP #define __UTIL_HASH_HMAC_HPP -#include "md5.hpp" +#include +#include +#include namespace util { namespace hash { + template /// RFC 2104 key-hashing for message authentication class HMAC { public: - using digest_t = MD5::digest_t; + using digest_t = typename T::digest_t; HMAC (const uint8_t *key, size_t); @@ -37,10 +40,10 @@ namespace util { namespace hash { digest_t digest (void); private: - std::array m_ikey; - std::array m_okey; + std::array m_ikey; + std::array m_okey; - MD5 m_hash; + T m_hash; }; } } diff --git a/hash/md5.hpp b/hash/md5.hpp index 0d1ee238..885c49dc 100644 --- a/hash/md5.hpp +++ b/hash/md5.hpp @@ -29,6 +29,8 @@ namespace util { class MD5 { public: typedef std::array digest_t; + static const size_t BLOCK_SIZE = 64; + static const size_t DIGEST_SIZE = 16; public: MD5(); diff --git a/hash/sha1.hpp b/hash/sha1.hpp index 424c5461..c9b229be 100644 --- a/hash/sha1.hpp +++ b/hash/sha1.hpp @@ -31,6 +31,8 @@ namespace util { namespace hash { class SHA1 { public: typedef std::array digest_t; + static const size_t BLOCK_SIZE = 64; + static const size_t DIGEST_SIZE = 20; public: SHA1(); diff --git a/test/hmac.cpp b/test/hmac.cpp index fb478ed7..1468e12e 100644 --- a/test/hmac.cpp +++ b/test/hmac.cpp @@ -1,6 +1,9 @@ #include "hash/hmac.hpp" -#include "types.hpp" + #include "debug.hpp" +#include "hash/md5.hpp" +#include "hash/sha1.hpp" +#include "types.hpp" #include #include @@ -17,26 +20,50 @@ to_vector (const char *str) } +//----------------------------------------------------------------------------- +template +bool +test_hmac (const std::vector &key, + const std::vector &dat, + const std::vector &res) +{ + util::hash::HMAC h (key.data (), key.size ()); + h.update (dat.data (), dat.size ()); + h.finish (); + + auto ours = h.digest (); + + return std::equal (ours.begin (), ours.end (), res.begin ()); +} + + +typedef bool (*test_func) (const std::vector&, + const std::vector&, + const std::vector&); + //----------------------------------------------------------------------------- static const struct { std::vector key; std::vector dat; - HMAC::digest_t res; + std::vector res; + test_func fun; } 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 } } + { 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, + 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d }, + &test_hmac }, { to_vector ("Jefe"), to_vector ("what do ya want for nothing?"), - { { 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, - 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 } } + { 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, + 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 }, + &test_hmac }, { @@ -49,8 +76,9 @@ static const struct { 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 } } + { 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88, + 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 }, + &test_hmac }, // RFC 2202 test data, MD5 @@ -66,16 +94,18 @@ static const struct { 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD }, - { { 0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea, - 0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79 } } + { 0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea, + 0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79 }, + &test_hmac }, { { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, to_vector ("Test With Truncation"), - { { 0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e, 0xdc, 0x00, - 0xf9, 0xba, 0xb9, 0x95, 0x69, 0x0e, 0xfd, 0x4c } } + { 0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e, 0xdc, 0x00, + 0xf9, 0xba, 0xb9, 0x95, 0x69, 0x0e, 0xfd, 0x4c }, + &test_hmac // digest-96: 0x56461ef2342edc00f9bab995 }, @@ -91,8 +121,9 @@ static const struct { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, to_vector ("Test Using Larger Than Block-Size Key - Hash Key First"), - { { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f, - 0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd } } + { 0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f, + 0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd }, + &test_hmac }, { @@ -107,9 +138,131 @@ static const struct { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, to_vector ("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), - { { 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, - 0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e } } - } + { 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, + 0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e }, + &test_hmac + }, + + // RFC 2202 test data, SHA1 + { + { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b }, + to_vector ("Hi There"), + { 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, + 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, + 0xf1, 0x46, 0xbe, 0x00 }, + &test_hmac + }, + + { + to_vector ("Jefe"), + to_vector ("what do ya want for nothing?"), + { 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, + 0xd2, 0x74, 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c, + 0x25, 0x9a, 0x7c, 0x79 }, + &test_hmac + }, + + { + { 0xaa, 0xaa, 0xaa, 0xaa, 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 }, + { 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd, + 0x91, 0xa3, 0x9a, 0xf4, 0x8a, 0xa1, 0x7b, 0x4f, + 0x63, 0xf1, 0x75, 0xd3 }, + &test_hmac + }, + + { + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19 }, + { 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd }, + { 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6, + 0xbc, 0x84, 0x14, 0xf9, 0xbf, 0x50, 0xc8, 0x6c, + 0x2d, 0x72, 0x35, 0xda }, + &test_hmac + }, + + { + { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c }, + to_vector ("Test With Truncation"), + { 0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, + 0xe7, 0xf2, 0x7b, 0xe1, 0xd5, 0x8b, 0xb9, 0x32, + 0x4a, 0x9a, 0x5a, 0x04 }, + &test_hmac + }, + + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, + to_vector ("Test Using Larger Than Block-Size Key - Hash Key First"), + { 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, + 0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55, + 0xed, 0x40, 0x21, 0x12 }, + &test_hmac + }, + + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, + to_vector ("Test Using Larger Than Block-Size Key - Hash Key First"), + { 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, + 0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55, + 0xed, 0x40, 0x21, 0x12 }, + &test_hmac + }, + + { + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, + to_vector ("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), + { 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, + 0x6d, 0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, + 0xbb, 0xff, 0x1a, 0x91 }, + &test_hmac + }, }; @@ -121,11 +274,8 @@ main (int, char**) for (const auto &t: TESTS) { std::cerr << i++ << ": " << t.key.size () << ", " << t.dat.size () << '\n'; - 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) + if (!t.fun (t.key, t.dat, t.res)) return EXIT_FAILURE; }