HMACEngine
HMACEngine is a template class that uses an implementation of DigestEngine for generating message hashes with a secret/key value.
HMACEngine.h
The definition of the template class for generating hash based message authentication code.
/* * HMACEngine.h * * Definition of the HMACEngine class. * * Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. * and Contributors. * * Permission is hereby granted, free of charge, to any person or organization * obtaining a copy of the software and accompanying documentation covered by * this license (the "Software") to use, reproduce, display, distribute, * execute, and transmit the Software, and to prepare derivative works of the * Software, and to permit third-parties to whom the Software is furnished to * do so, all subject to the following: * * The copyright notices in the Software and this entire statement, including * the above license grant, this restriction and the following disclaimer, * must be included in all copies of the Software, in whole or in part, and * all derivative works of the Software, unless such copies or derivative * works are solely in the form of machine-executable object code generated by * a source language processor. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef SPT_DIGEST_HMACENGINE #define SPT_DIGEST_HMACENGINE #if defined( ARDUINO ) #include "DigestEngine.h" #include "../StandardCplusplus/cstring" #else #include <digest/DigestEngine.h> #include <cstring> #endif namespace spt { namespace digest { /// This class implementes the HMAC message /// authentication code algorithm, as specified /// in RFC 2104. The underlying DigestEngine /// (MD5Engine, SHA1Engine, etc.) must be given as /// template argument. template <class Engine> class HMACEngine: public DigestEngine { public: enum { BLOCK_SIZE = Engine::BLOCK_SIZE, DIGEST_SIZE = Engine::DIGEST_SIZE }; HMACEngine( const std::string& passphrase ) { init( passphrase.data(), static_cast<uint32_t>( passphrase.length() ) ); } HMACEngine( const char* passphrase, uint32_t length ) { init( passphrase, length ); } ~HMACEngine() { std::memset( ipad, 0, BLOCK_SIZE ); std::memset( opad, 0, BLOCK_SIZE ); delete [] ipad; delete [] opad; } uint32_t digestLength() const { return DIGEST_SIZE; } void reset() { engine.reset(); engine.update( ipad, BLOCK_SIZE ); } const DigestEngine::Digest& digest() { const DigestEngine::Digest& d = engine.digest(); char db[DIGEST_SIZE]; char* pdb = db; for ( DigestEngine::Digest::const_iterator it = d.begin(); it != d.end(); ++it ) { *pdb++ = *it; } engine.reset(); engine.update( opad, BLOCK_SIZE ); engine.update( db, DIGEST_SIZE ); const DigestEngine::Digest& result = engine.digest(); reset(); return result; } protected: void init( const char* passphrase, uint32_t length ) { ipad = new char[BLOCK_SIZE]; opad = new char[BLOCK_SIZE]; std::memset( ipad, 0, BLOCK_SIZE ); std::memset( opad, 0, BLOCK_SIZE ); if ( length > BLOCK_SIZE ) { engine.reset(); engine.update( passphrase, length ); const DigestEngine::Digest& d = engine.digest(); char* cipad = ipad; char* copad = opad; int n = BLOCK_SIZE; for ( DigestEngine::Digest::const_iterator it = d.begin(); it != d.end() && n-- > 0; ++it ) { *cipad++ = *it; *copad++ = *it; } } else { std::memcpy( ipad, passphrase, length ); std::memcpy( opad, passphrase, length ); } for ( int i = 0; i < BLOCK_SIZE; ++i ) { ipad[i] ^= 0x36; opad[i] ^= 0x5c; } reset(); } void updateImpl( const void* data, uint32_t length ) { engine.update( data, length ); } private: HMACEngine(); HMACEngine( const HMACEngine& ); HMACEngine& operator = ( const HMACEngine& ); Engine engine; char* ipad; char* opad; }; } // namespace digest } // namespace spt #endif // SPT_DIGEST_HMACENGINE
HMACEngineTest.cpp
Unit test for the HMACEngine.
#if defined( ARDUINO ) #include "tut.hpp" #include "HMACEngine.h" #include "MD5Engine.h" #else #include <tut/tut.hpp> #include <SPT.h> #include <digest/HMACEngine.h> #include <digest/MD5Engine.h> #endif using spt::digest::DigestEngine; using spt::digest::HMACEngine; using spt::digest::MD5Engine; namespace tut { struct HMACEngineTestData {}; typedef test_group<HMACEngineTestData> HMACEngineTestGroup; typedef HMACEngineTestGroup::object HMACEngineTest; HMACEngineTestGroup hmacEngineTestGroup( "HMACEngine test suite" ); template<> template<> void HMACEngineTest::test<1>() { set_test_name( "first" ); // test vectors from RFC 2104 std::string key( 16, 0x0b ); std::string data( "Hi There" ); HMACEngine<MD5Engine> hmac( key ); hmac.update( data ); std::string digest( DigestEngine::digestToHex( hmac.digest() ) ); ensure( "First", digest == "9294727a3638bb1c13f48ef8158bfc9d" ); std::cout << "Free SRAM: " << spt::freeRam() << std::endl; } template<> template<> void HMACEngineTest::test<2>() { set_test_name( "second" ); std::string key( "Jefe" ); std::string data( "what do ya want for nothing?" ); HMACEngine<MD5Engine> hmac( key ); hmac.update( data ); std::string digest( DigestEngine::digestToHex( hmac.digest() ) ); ensure( "Second", digest == "750c783e6ab0b503eaa86e310a5db738" ); std::cout << "Free SRAM: " << spt::freeRam() << std::endl; } template<> template<> void HMACEngineTest::test<3>() { set_test_name( "third" ); std::string key( 16, 0xaa ); std::string data( 50, 0xdd ); HMACEngine<MD5Engine> hmac( key ); hmac.update( data ); std::string digest( DigestEngine::digestToHex( hmac.digest() ) ); ensure( "Third", digest == "56be34521d144c88dbb8c733f0e8b3f6" ); std::cout << "Free SRAM: " << spt::freeRam() << std::endl; } }
HMACEngine may be used with any implementation of DigestEngine.