hash/hmac: add HMAC-SHA1 support
This commit is contained in:
parent
e52b8368f2
commit
cedcf90c3f
@ -32,14 +32,15 @@ static const uint8_t OFILL = 0x5C;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
HMAC::HMAC (const uint8_t *restrict key, size_t len)
|
||||
template <class T>
|
||||
HMAC<T>::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 <class T>
|
||||
void
|
||||
HMAC::update (const void *restrict data, size_t len)
|
||||
HMAC<T>::update (const void *restrict data, size_t len)
|
||||
{
|
||||
m_hash.update ((const uint8_t*)data, len);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void
|
||||
HMAC::finish (void)
|
||||
HMAC<T>::finish (void)
|
||||
{
|
||||
m_hash.finish ();
|
||||
auto d = m_hash.digest ();
|
||||
@ -96,8 +99,9 @@ HMAC::finish (void)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void
|
||||
HMAC::reset (void)
|
||||
HMAC<T>::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 <class T>
|
||||
typename HMAC<T>::digest_t
|
||||
HMAC<T>::digest (void)
|
||||
{
|
||||
return m_hash.digest ();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "md5.hpp"
|
||||
#include "sha1.hpp"
|
||||
|
||||
template class HMAC<util::hash::MD5>;
|
||||
template class HMAC<util::hash::SHA1>;
|
||||
|
@ -20,13 +20,16 @@
|
||||
#ifndef __UTIL_HASH_HMAC_HPP
|
||||
#define __UTIL_HASH_HMAC_HPP
|
||||
|
||||
#include "md5.hpp"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace util { namespace hash {
|
||||
template <class T>
|
||||
/// 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<uint8_t,64> m_ikey;
|
||||
std::array<uint8_t,64> m_okey;
|
||||
std::array<uint8_t,T::BLOCK_SIZE> m_ikey;
|
||||
std::array<uint8_t,T::BLOCK_SIZE> m_okey;
|
||||
|
||||
MD5 m_hash;
|
||||
T m_hash;
|
||||
};
|
||||
} }
|
||||
|
||||
|
@ -29,6 +29,8 @@ namespace util {
|
||||
class MD5 {
|
||||
public:
|
||||
typedef std::array<uint8_t,16> digest_t;
|
||||
static const size_t BLOCK_SIZE = 64;
|
||||
static const size_t DIGEST_SIZE = 16;
|
||||
|
||||
public:
|
||||
MD5();
|
||||
|
@ -31,6 +31,8 @@ namespace util { namespace hash {
|
||||
class SHA1 {
|
||||
public:
|
||||
typedef std::array<uint8_t,20> digest_t;
|
||||
static const size_t BLOCK_SIZE = 64;
|
||||
static const size_t DIGEST_SIZE = 20;
|
||||
|
||||
public:
|
||||
SHA1();
|
||||
|
192
test/hmac.cpp
192
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 <cstring>
|
||||
#include <iostream>
|
||||
@ -17,26 +20,50 @@ to_vector (const char *str)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
bool
|
||||
test_hmac (const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &dat,
|
||||
const std::vector<uint8_t> &res)
|
||||
{
|
||||
util::hash::HMAC<T> 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<uint8_t>&,
|
||||
const std::vector<uint8_t>&,
|
||||
const std::vector<uint8_t>&);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static const struct {
|
||||
std::vector<uint8_t> key;
|
||||
std::vector<uint8_t> dat;
|
||||
HMAC::digest_t res;
|
||||
std::vector<uint8_t> 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<util::hash::MD5>
|
||||
},
|
||||
|
||||
{
|
||||
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<util::hash::MD5>
|
||||
},
|
||||
|
||||
{
|
||||
@ -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<util::hash::MD5>
|
||||
},
|
||||
|
||||
// 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<util::hash::MD5>
|
||||
},
|
||||
|
||||
{
|
||||
{ 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<util::hash::MD5>
|
||||
// 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<util::hash::MD5>
|
||||
},
|
||||
|
||||
{
|
||||
@ -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<util::hash::MD5>
|
||||
},
|
||||
|
||||
// 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<util::hash::SHA1>
|
||||
},
|
||||
|
||||
{
|
||||
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<util::hash::SHA1>
|
||||
},
|
||||
|
||||
{
|
||||
{ 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<util::hash::SHA1>
|
||||
},
|
||||
|
||||
{
|
||||
{ 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<util::hash::SHA1>
|
||||
},
|
||||
|
||||
{
|
||||
{ 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<util::hash::SHA1>
|
||||
},
|
||||
|
||||
{
|
||||
{ 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<util::hash::SHA1>
|
||||
},
|
||||
|
||||
{
|
||||
{ 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<util::hash::SHA1>
|
||||
},
|
||||
|
||||
{
|
||||
{ 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<util::hash::SHA1>
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user