hash/hmac: add simple HMAC-MD5

This commit is contained in:
Danny Robson 2015-03-02 00:06:47 +11:00
parent 277354807e
commit f4fe636cb0
4 changed files with 219 additions and 0 deletions

View File

@ -45,6 +45,8 @@ UTIL_FILES = \
hash/crc.cpp \ hash/crc.cpp \
hash/crc.hpp \ hash/crc.hpp \
hash/fletcher.hpp \ hash/fletcher.hpp \
hash/hmac.cpp \
hash/hmac.hpp \
hash/md2.cpp \ hash/md2.cpp \
hash/md2.hpp \ hash/md2.hpp \
hash/md4.cpp \ hash/md4.cpp \
@ -238,6 +240,7 @@ TEST_BIN = \
test/extent \ test/extent \
test/fixed \ test/fixed \
test/float \ test/float \
test/hmac \
test/hton \ test/hton \
test/ip \ test/ip \
test/json_types \ test/json_types \

102
hash/hmac.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "hmac.hpp"
#include "debug.hpp"
#include <algorithm>
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 ();
}

47
hash/hmac.hpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#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<uint8_t,64> m_ikey;
std::array<uint8_t,64> m_okey;
MD5 m_hash;
};
} }
#endif

67
test/hmac.cpp Normal file
View File

@ -0,0 +1,67 @@
#include "hash/hmac.hpp"
#include "types.hpp"
#include "debug.hpp"
#include <iostream>
#include <vector>
using util::hash::HMAC;
static const struct {
std::vector<uint8_t> key;
std::vector<uint8_t> 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;
}