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.
/*
 * 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.