Sans Pareil Technologies, Inc.

Key To Your Business

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.

    1: /*
    2: * HMACEngine.h
    3: *
    4: * Definition of the HMACEngine class.
    5: *
    6: * Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
    7: * and Contributors.
    8: *
    9: * Permission is hereby granted, free of charge, to any person or organization
   10: * obtaining a copy of the software and accompanying documentation covered by
   11: * this license (the "Software") to use, reproduce, display, distribute,
   12: * execute, and transmit the Software, and to prepare derivative works of the
   13: * Software, and to permit third-parties to whom the Software is furnished to
   14: * do so, all subject to the following:
   15: *
   16: * The copyright notices in the Software and this entire statement, including
   17: * the above license grant, this restriction and the following disclaimer,
   18: * must be included in all copies of the Software, in whole or in part, and
   19: * all derivative works of the Software, unless such copies or derivative
   20: * works are solely in the form of machine-executable object code generated by
   21: * a source language processor.
   22: *
   23: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   24: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   25: * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
   26: * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
   27: * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
   28: * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   29: * DEALINGS IN THE SOFTWARE.
   30: */
   31:
   32: #ifndef SPT_DIGEST_HMACENGINE
   33: #define SPT_DIGEST_HMACENGINE
   34:
   35:
   36: #if defined( ARDUINO )
   37: #include "DigestEngine.h"
   38: #include "../StandardCplusplus/cstring"
   39: #else
   40: #include <digest/DigestEngine.h>
   41: #include <cstring>
   42: #endif
   43:
   44:
   45: namespace spt
   46: {
   47:   namespace digest
   48:   {
   49:     /// This class implementes the HMAC message
   50:     /// authentication code algorithm, as specified
   51:     /// in RFC 2104. The underlying DigestEngine
   52:     /// (MD5Engine, SHA1Engine, etc.) must be given as
   53:     /// template argument.
   54:     template <class Engine>
   55:     class HMACEngine: public DigestEngine
   56:     {
   57:     public:
   58:       enum
   59:       {
   60:         BLOCK_SIZE  = Engine::BLOCK_SIZE,
   61:         DIGEST_SIZE = Engine::DIGEST_SIZE
   62:       };
   63:
   64:       HMACEngine( const std::string& passphrase )
   65:       {
   66:         init( passphrase.data(), static_cast<uint32_t>( passphrase.length() ) );
   67:       }
   68:
   69:       HMACEngine( const char* passphrase, uint32_t length )
   70:       {
   71:         init( passphrase, length );
   72:       }
   73:
   74:       ~HMACEngine()
   75:       {
   76:         std::memset( ipad, 0, BLOCK_SIZE );
   77:         std::memset( opad, 0, BLOCK_SIZE );
   78:         delete [] ipad;
   79:         delete [] opad;
   80:       }
   81:
   82:       uint32_t digestLength() const { return DIGEST_SIZE; }
   83:
   84:       void reset()
   85:       {
   86:         engine.reset();
   87:         engine.update( ipad, BLOCK_SIZE );
   88:       }
   89:
   90:       const DigestEngine::Digest& digest()
   91:       {
   92:         const DigestEngine::Digest& d = engine.digest();
   93:
   94:         char db[DIGEST_SIZE];
   95:         char* pdb = db;
   96:
   97:         for ( DigestEngine::Digest::const_iterator it = d.begin(); it != d.end(); ++it )
   98:         {
   99:           *pdb++ = *it;
  100:         }
  101:
  102:         engine.reset();
  103:         engine.update( opad, BLOCK_SIZE );
  104:         engine.update( db, DIGEST_SIZE );
  105:
  106:         const DigestEngine::Digest& result = engine.digest();
  107:         reset();
  108:         return result;
  109:       }
  110:
  111:     protected:
  112:       void init( const char* passphrase, uint32_t length )
  113:       {
  114:         ipad = new char[BLOCK_SIZE];
  115:         opad = new char[BLOCK_SIZE];
  116:         std::memset( ipad, 0, BLOCK_SIZE );
  117:         std::memset( opad, 0, BLOCK_SIZE );
  118:
  119:         if ( length > BLOCK_SIZE )
  120:         {
  121:           engine.reset();
  122:           engine.update( passphrase, length );
  123:           const DigestEngine::Digest& d = engine.digest();
  124:           char* cipad = ipad;
  125:           char* copad = opad;
  126:           int n = BLOCK_SIZE;
  127:
  128:           for ( DigestEngine::Digest::const_iterator it = d.begin(); it != d.end() && n-- > 0; ++it )
  129:           {
  130:             *cipad++ = *it;
  131:             *copad++ = *it;
  132:           }
  133:         }
  134:         else
  135:         {
  136:           std::memcpy( ipad, passphrase, length );
  137:           std::memcpy( opad, passphrase, length );
  138:         }
  139:
  140:         for ( int i = 0; i < BLOCK_SIZE; ++i )
  141:         {
  142:           ipad[i] ^= 0x36;
  143:           opad[i] ^= 0x5c;
  144:         }
  145:
  146:         reset();
  147:       }
  148:
  149:       void updateImpl( const void* data, uint32_t length )
  150:       {
  151:         engine.update( data, length );
  152:       }
  153:
  154:     private:
  155:       HMACEngine();
  156:       HMACEngine( const HMACEngine& );
  157:       HMACEngine& operator = ( const HMACEngine& );
  158:
  159:       Engine engine;
  160:       char*  ipad;
  161:       char*  opad;
  162:     };
  163:
  164:   } // namespace digest
  165:
  166: } // namespace spt
  167:
  168:
  169: #endif // SPT_DIGEST_HMACENGINE


HMACEngineTest.cpp

Unit test for the HMACEngine.

    1: #if defined( ARDUINO )
    2: #include "tut.hpp"
    3: #include "HMACEngine.h"
    4: #include "MD5Engine.h"
    5: #else
    6: #include <tut/tut.hpp>
    7: #include <SPT.h>
    8: #include <digest/HMACEngine.h>
    9: #include <digest/MD5Engine.h>
   10: #endif
   11:
   12: using spt::digest::DigestEngine;
   13: using spt::digest::HMACEngine;
   14: using spt::digest::MD5Engine;
   15:
   16: namespace tut
   17: {
   18:   struct HMACEngineTestData {};
   19:
   20:   typedef test_group<HMACEngineTestData> HMACEngineTestGroup;
   21:   typedef HMACEngineTestGroup::object HMACEngineTest;
   22:   HMACEngineTestGroup hmacEngineTestGroup( "HMACEngine test suite" );
   23:
   24:
   25:   template<>
   26:   template<>
   27:   void HMACEngineTest::test<1>()
   28:   {
   29:     set_test_name( "first" );
   30:
   31:     // test vectors from RFC 2104
   32:
   33:     std::string key( 16, 0x0b );
   34:     std::string data( "Hi There" );
   35:     HMACEngine<MD5Engine> hmac( key );
   36:     hmac.update( data );
   37:     std::string digest( DigestEngine::digestToHex( hmac.digest() ) );
   38:     ensure( "First", digest == "9294727a3638bb1c13f48ef8158bfc9d" );
   39:     std::cout << "Free SRAM: " << spt::freeRam() << std::endl;
   40:   }
   41:
   42:
   43:   template<>
   44:   template<>
   45:   void HMACEngineTest::test<2>()
   46:   {
   47:     set_test_name( "second" );
   48:
   49:     std::string key( "Jefe" );
   50:     std::string data( "what do ya want for nothing?" );
   51:     HMACEngine<MD5Engine> hmac( key );
   52:     hmac.update( data );
   53:     std::string digest( DigestEngine::digestToHex( hmac.digest() ) );
   54:     ensure( "Second", digest == "750c783e6ab0b503eaa86e310a5db738" );
   55:     std::cout << "Free SRAM: " << spt::freeRam() << std::endl;
   56:   }
   57:
   58:
   59:   template<>
   60:   template<>
   61:   void HMACEngineTest::test<3>()
   62:   {
   63:     set_test_name( "third" );
   64:
   65:     std::string key( 16, 0xaa );
   66:     std::string data( 50, 0xdd );
   67:     HMACEngine<MD5Engine> hmac( key );
   68:     hmac.update( data );
   69:     std::string digest( DigestEngine::digestToHex( hmac.digest() ) );
   70:     ensure( "Third", digest == "56be34521d144c88dbb8c733f0e8b3f6" );
   71:     std::cout << "Free SRAM: " << spt::freeRam() << std::endl;
   72:   }
   73: }