Sans Pareil Technologies, Inc.

Key To Your Business

SHA1Engine



A DigestEngine implementation for generating SHA1 message digest values.

SHA1Engine.h

The definition of the SHA1 digest engine.

    1: /*
    2: * SHA1Engine.h
    3: *
    4: * Definition of class SHA1Engine.
    5: *
    6: * Secure Hash Standard SHA-1 algorithm
    7: * (FIPS 180-1, see http: *www.itl.nist.gov/fipspubs/fip180-1.htm)
    8: *
    9: * Based on the public domain implementation by Peter C. Gutmann
   10: * on 2 Sep 1992, modified by Carl Ellison to be SHA-1.
   11: *
   12: * Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
   13: * and Contributors.
   14: *
   15: * Permission is hereby granted, free of charge, to any person or organization
   16: * obtaining a copy of the software and accompanying documentation covered by
   17: * this license (the "Software") to use, reproduce, display, distribute,
   18: * execute, and transmit the Software, and to prepare derivative works of the
   19: * Software, and to permit third-parties to whom the Software is furnished to
   20: * do so, all subject to the following:
   21: *
   22: * The copyright notices in the Software and this entire statement, including
   23: * the above license grant, this restriction and the following disclaimer,
   24: * must be included in all copies of the Software, in whole or in part, and
   25: * all derivative works of the Software, unless such copies or derivative
   26: * works are solely in the form of machine-executable object code generated by
   27: * a source language processor.
   28: *
   29: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   30: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   31: * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
   32: * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
   33: * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
   34: * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   35: * DEALINGS IN THE SOFTWARE.
   36: */
   37:
   38:
   39: #ifndef SPT_DIGEST_SHA1ENGINE
   40: #define SPT_DIGEST_SHA1ENGINE
   41:
   42:
   43: #include "DigestEngine.h"
   44:
   45:
   46: namespace spt
   47: {
   48:   namespace digest
   49:   {
   50:   /// This class implementes the SHA-1 message digest algorithm.
   51:   /// (FIPS 180-1, see http://www.itl.nist.gov/fipspubs/fip180-1.htm)
   52:   class SHA1Engine: public DigestEngine
   53:   {
   54:   public:
   55:     enum
   56:     {
   57:       BLOCK_SIZE  = 64,
   58:       DIGEST_SIZE = 20
   59:     };
   60:
   61:     SHA1Engine();
   62:     ~SHA1Engine();
   63:
   64:     uint32_t digestLength() const;
   65:     void reset();
   66:     const DigestEngine::Digest& digest();
   67:
   68:   protected:
   69:     void updateImpl( const void* data, uint32_t length );
   70:
   71:   private:
   72:     void transform();
   73:     static void byteReverse( uint32_t* buffer, uint32_t byteCount );
   74:     void byteReverse( uint32_t* buffer, int byteCount );
   75:
   76:     struct Context
   77:     {
   78:       uint32_t digest[5]; // Message digest
   79:       uint32_t countLo;   // 64-bit bit count
   80:       uint32_t countHi;
   81:       uint32_t data[16];  // SHA data buffer
   82:       uint32_t slop;      // # of bytes saved in data[]
   83:     };
   84:
   85:     Context context;
   86:     DigestEngine::Digest digestValue;
   87:
   88:     SHA1Engine( const SHA1Engine& );
   89:     SHA1Engine& operator = ( const SHA1Engine& );
   90:   };
   91:
   92:   } // namespace digest
   93:
   94: } // namespace spt
   95:
   96:
   97: #endif // SPT_DIGEST_SHA1ENGINE


SHA1Engine.cpp

The implementation of the SHA1 message digest algorithm.

    1: /*
    2: * SHA1Engine.cpp
    3: *
    4: * $Id: SHA1Engine.cpp 5792 2015-06-13 19:12:19Z rakesh $
    5: *
    6: * Library: Foundation
    7: * Package: Crypt
    8: * Module:  SHA1Engine
    9: *
   10: * Based on the public domain implementation by Peter C. Gutmann
   11: * on 2 Sep 1992, modified by Carl Ellison to be SHA-1.
   12: *
   13: * Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
   14: * and Contributors.
   15: *
   16: * Permission is hereby granted, free of charge, to any person or organization
   17: * obtaining a copy of the software and accompanying documentation covered by
   18: * this license (the "Software") to use, reproduce, display, distribute,
   19: * execute, and transmit the Software, and to prepare derivative works of the
   20: * Software, and to permit third-parties to whom the Software is furnished to
   21: * do so, all subject to the following:
   22: *
   23: * The copyright notices in the Software and this entire statement, including
   24: * the above license grant, this restriction and the following disclaimer,
   25: * must be included in all copies of the Software, in whole or in part, and
   26: * all derivative works of the Software, unless such copies or derivative
   27: * works are solely in the form of machine-executable object code generated by
   28: * a source language processor.
   29: *
   30: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   31: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   32: * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
   33: * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
   34: * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
   35: * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   36: * DEALINGS IN THE SOFTWARE.
   37: */
   38:
   39:
   40: #include "SHA1Engine.h"
   41:
   42: #if defined( ARDUINO )
   43: #include "../StandardCplusplus/cstring"
   44: #else
   45: #include <cstring>
   46: #endif
   47:
   48:
   49: namespace spt
   50: {
   51:   namespace digest
   52:   {
   53: //#ifdef POCO_ARCH_LITTLE_ENDIAN || ARDUINO
   54:   #define SHA1_Byte_REVERSE(x, y) byteReverse(x, y)
   55: //#else
   56:   //#define SHA1_Byte_REVERSE(x, y)
   57: //#endif
   58:   }
   59: }
   60:
   61:
   62: using spt::Byte;
   63: using spt::digest::DigestEngine;
   64: using spt::digest::SHA1Engine;
   65:
   66:
   67: SHA1Engine::SHA1Engine()
   68: {
   69:   digestValue.reserve(16);
   70:   reset();
   71: }
   72:
   73:
   74: SHA1Engine::~SHA1Engine()
   75: {
   76:   reset();
   77: }
   78:
   79:
   80: inline void SHA1Engine::byteReverse( uint32_t* buffer, int byteCount )
   81: {
   82:   byteCount /= sizeof( uint32_t );
   83:   for ( int count = 0; count < byteCount; ++count )
   84:   {
   85:     uint32_t value = (buffer[ count ] << 16) | (buffer[ count ] >> 16);
   86:     buffer[count] = ((value & 0xFF00FF00L) >> 8) | ((value & 0x00FF00FFL) << 8);
   87:   }
   88: }
   89:
   90:  
   91: void SHA1Engine::updateImpl( const void* buffer_, uint32_t count )
   92: {
   93:   const Byte* buffer = static_cast<const Byte*>( buffer_ );
   94:   Byte* db = reinterpret_cast<Byte*>( &context.data[0] );
   95:
   96:   /* Update bitcount */
   97:   if ( ( context.countLo + static_cast<uint32_t>( count << 3 ) ) < context.countLo )
   98:   {
   99:     context.countHi++; /* Carry from low to high bitCount */
  100:   }
  101:
  102:   context.countLo += static_cast<uint32_t>( count << 3 );
  103:   context.countHi += static_cast<uint32_t>( count >> 29 );
  104:
  105:   /* Process data in BLOCK_SIZE chunks */
  106:   while ( count-- > 0 )
  107:   {
  108:     db[context.slop++] = *(buffer++);
  109:     if ( context.slop == BLOCK_SIZE )
  110:     {
  111:       /* transform this one block */
  112:       SHA1_Byte_REVERSE( context.data, BLOCK_SIZE );
  113:       transform();
  114:       context.slop = 0 ;  /* no slop left */
  115:     }
  116:   }
  117: }
  118:
  119:
  120: uint32_t SHA1Engine::digestLength() const { return DIGEST_SIZE; }
  121:
  122:
  123: void SHA1Engine::reset()
  124: {
  125:   context.digest[0] = 0x67452301L;
  126:   context.digest[1] = 0xEFCDAB89L;
  127:   context.digest[2] = 0x98BADCFEL;
  128:   context.digest[3] = 0x10325476L;
  129:   context.digest[4] = 0xC3D2E1F0L;
  130:   context.countLo   = 0;
  131:   context.countHi   = 0;
  132:   context.slop      = 0;
  133:   std::memset( context.data, 0, sizeof( context.data ) );
  134: }
  135:
  136:
  137: const DigestEngine::Digest& SHA1Engine::digest()
  138: {
  139:   int32_t count;
  140:   uint32_t lowBitcount  = context.countLo;
  141:   uint32_t highBitcount = context.countHi;
  142:
  143:   /* Compute number of bytes mod 64 */
  144:   count = static_cast<int32_t>( ( context.countLo >> 3 ) & 0x3F );
  145:
  146:   /* Set the first char of padding to 0x80.  This is safe since there is
  147:     always at least one byte free */
  148:   ((Byte*) context.data)[count++] = 0x80;
  149:
  150:   /* Pad out to 56 mod 64 */
  151:   if ( count > 56 )
  152:   {
  153:     /* Two lots of padding:  Pad the first block to 64 bytes */
  154:     std::memset( (Byte*) &context.data + count, 0, 64 - count );
  155:     SHA1_Byte_REVERSE( context.data, BLOCK_SIZE );
  156:     transform();
  157:
  158:     /* Now fill the next block with 56 bytes */
  159:     std::memset( &context.data, 0, 56 );
  160:   }
  161:   else
  162:   {
  163:     /* Pad block to 56 bytes */
  164:     std::memset( (Byte*) &context.data + count, 0, 56 - count );
  165:   }
  166:   SHA1_Byte_REVERSE( context.data, BLOCK_SIZE );
  167:
  168:   /* Append length in bits and transform */
  169:   context.data[14] = highBitcount;
  170:   context.data[15] = lowBitcount;
  171:
  172:   transform();
  173:   SHA1_Byte_REVERSE( context.data, DIGEST_SIZE );
  174:
  175:   Byte hash[DIGEST_SIZE];
  176:   for ( count = 0; count < DIGEST_SIZE; ++count )
  177:   {
  178:     hash[count] = (Byte) ((context.digest[count>>2]) >> (8*(3-(count & 0x3)))) & 0xff;
  179:   }
  180:
  181:   digestValue.clear();
  182:   digestValue.insert( digestValue.begin(), hash, hash + DIGEST_SIZE );
  183:   reset();
  184:   return digestValue;
  185: }
  186:
  187:
  188: /* The SHA f()-functions */
  189: #define f1(x,y,z)   ( ( x & y ) | ( ~x & z ) )              /* Rounds  0-19 */
  190: #define f2(x,y,z)   ( x ^ y ^ z )                           /* Rounds 20-39 */
  191: #define f3(x,y,z)   ( ( x & y ) | ( x & z ) | ( y & z ) )   /* Rounds 40-59 */
  192: #define f4(x,y,z)   ( x ^ y ^ z )                           /* Rounds 60-79 */
  193:
  194:
  195: /* The SHA Mysterious Constants */
  196: #define K1  0x5A827999L     /* Rounds  0-19 */
  197: #define K2  0x6ED9EBA1L     /* Rounds 20-39 */
  198: #define K3  0x8F1BBCDCL     /* Rounds 40-59 */
  199: #define K4  0xCA62C1D6L     /* Rounds 60-79 */
  200:
  201:
  202: /* 32-bit rotate - kludged with shifts */
  203: typedef uint32_t UL;  /* to save space */
  204:
  205:
  206: #define S(n,X)  ( ( ((UL)X) << n ) | ( ((UL)X) >> ( 32 - n ) ) )
  207:
  208:
  209: /* The initial expanding function */
  210: #define expand(count)   W[ count ] = S(1,(W[ count - 3 ] ^ W[ count - 8 ] ^ W[ count - 14 ] ^ W[ count - 16 ]))  /* to make this SHA-1 */
  211:
  212:
  213: /* The four SHA sub-rounds */
  214: #define subRound1(count)    \
  215: { \
  216:     temp = S( 5, A ) + f1( B, C, D ) + E + W[ count ] + K1; \
  217:     E = D; \
  218:     D = C; \
  219:     C = S( 30, B ); \
  220:     B = A; \
  221:     A = temp; \
  222: }
  223:
  224: #define subRound2(count)    \
  225: { \
  226:     temp = S( 5, A ) + f2( B, C, D ) + E + W[ count ] + K2; \
  227:     E = D; \
  228:     D = C; \
  229:     C = S( 30, B ); \
  230:     B = A; \
  231:     A = temp; \
  232: }
  233:
  234: #define subRound3(count)    \
  235: { \
  236:     temp = S( 5, A ) + f3( B, C, D ) + E + W[ count ] + K3; \
  237:     E = D; \
  238:     D = C; \
  239:     C = S( 30, B ); \
  240:     B = A; \
  241:     A = temp; \
  242: }
  243:
  244: #define subRound4(count)    \
  245: { \
  246:     temp = S( 5, A ) + f4( B, C, D ) + E + W[ count ] + K4; \
  247:     E = D; \
  248:     D = C; \
  249:     C = S( 30, B ); \
  250:     B = A; \
  251:     A = temp; \
  252: }
  253:
  254:
  255: void SHA1Engine::transform()
  256: {
  257:   uint32_t W[80];
  258:   uint32_t temp;
  259:   uint32_t A, B, C, D, E;
  260:   int i;
  261:
  262:   /* Step A.  Copy the data buffer into the local work buffer */
  263:   for( i = 0; i < 16; i++ ) W[ i ] = context.data[ i ];
  264:
  265:   /* Step B.  Expand the 16 words into 64 temporary data words */
  266:   expand( 16 ); expand( 17 ); expand( 18 ); expand( 19 ); expand( 20 );
  267:   expand( 21 ); expand( 22 ); expand( 23 ); expand( 24 ); expand( 25 );
  268:   expand( 26 ); expand( 27 ); expand( 28 ); expand( 29 ); expand( 30 );
  269:   expand( 31 ); expand( 32 ); expand( 33 ); expand( 34 ); expand( 35 );
  270:   expand( 36 ); expand( 37 ); expand( 38 ); expand( 39 ); expand( 40 );
  271:   expand( 41 ); expand( 42 ); expand( 43 ); expand( 44 ); expand( 45 );
  272:   expand( 46 ); expand( 47 ); expand( 48 ); expand( 49 ); expand( 50 );
  273:   expand( 51 ); expand( 52 ); expand( 53 ); expand( 54 ); expand( 55 );
  274:   expand( 56 ); expand( 57 ); expand( 58 ); expand( 59 ); expand( 60 );
  275:   expand( 61 ); expand( 62 ); expand( 63 ); expand( 64 ); expand( 65 );
  276:   expand( 66 ); expand( 67 ); expand( 68 ); expand( 69 ); expand( 70 );
  277:   expand( 71 ); expand( 72 ); expand( 73 ); expand( 74 ); expand( 75 );
  278:   expand( 76 ); expand( 77 ); expand( 78 ); expand( 79 );
  279:
  280:   /* Step C.  Set up first buffer */
  281:   A = context.digest[ 0 ];
  282:   B = context.digest[ 1 ];
  283:   C = context.digest[ 2 ];
  284:   D = context.digest[ 3 ];
  285:   E = context.digest[ 4 ];
  286:
  287:   /* Step D.  Serious mangling, divided into four sub-rounds */
  288:   subRound1( 0 ); subRound1( 1 ); subRound1( 2 ); subRound1( 3 );
  289:   subRound1( 4 ); subRound1( 5 ); subRound1( 6 ); subRound1( 7 );
  290:   subRound1( 8 ); subRound1( 9 ); subRound1( 10 ); subRound1( 11 );
  291:   subRound1( 12 ); subRound1( 13 ); subRound1( 14 ); subRound1( 15 );
  292:   subRound1( 16 ); subRound1( 17 ); subRound1( 18 ); subRound1( 19 );
  293:   subRound2( 20 ); subRound2( 21 ); subRound2( 22 ); subRound2( 23 );
  294:   subRound2( 24 ); subRound2( 25 ); subRound2( 26 ); subRound2( 27 );
  295:   subRound2( 28 ); subRound2( 29 ); subRound2( 30 ); subRound2( 31 );
  296:   subRound2( 32 ); subRound2( 33 ); subRound2( 34 ); subRound2( 35 );
  297:   subRound2( 36 ); subRound2( 37 ); subRound2( 38 ); subRound2( 39 );
  298:   subRound3( 40 ); subRound3( 41 ); subRound3( 42 ); subRound3( 43 );
  299:   subRound3( 44 ); subRound3( 45 ); subRound3( 46 ); subRound3( 47 );
  300:   subRound3( 48 ); subRound3( 49 ); subRound3( 50 ); subRound3( 51 );
  301:   subRound3( 52 ); subRound3( 53 ); subRound3( 54 ); subRound3( 55 );
  302:   subRound3( 56 ); subRound3( 57 ); subRound3( 58 ); subRound3( 59 );
  303:   subRound4( 60 ); subRound4( 61 ); subRound4( 62 ); subRound4( 63 );
  304:   subRound4( 64 ); subRound4( 65 ); subRound4( 66 ); subRound4( 67 );
  305:   subRound4( 68 ); subRound4( 69 ); subRound4( 70 ); subRound4( 71 );
  306:   subRound4( 72 ); subRound4( 73 ); subRound4( 74 ); subRound4( 75 );
  307:   subRound4( 76 ); subRound4( 77 ); subRound4( 78 ); subRound4( 79 );
  308:
  309:   /* Step E.  Build message digest */
  310:   context.digest[ 0 ] += A;
  311:   context.digest[ 1 ] += B;
  312:   context.digest[ 2 ] += C;
  313:   context.digest[ 3 ] += D;
  314:   context.digest[ 4 ] += E;
  315: }


SHA1EngineTest.cpp

Unit tests for the SHA1 implementation.

    1: #if defined( ARDUINO )
    2: #include "tut.hpp"
    3: #include "SHA1Engine.h"
    4: #else
    5: #include <tut/tut.hpp>
    6: #include <SPT.h>
    7: #include <digest/SHA1Engine.h>
    8: #endif
    9:
   10: using spt::digest::DigestEngine;
   11: using spt::digest::SHA1Engine;
   12:
   13: namespace tut
   14: {
   15:   struct SHA1EngineTestData {};
   16:
   17:   typedef test_group<SHA1EngineTestData> SHA1EngineTestGroup;
   18:   typedef SHA1EngineTestGroup::object SHA1EngineTest;
   19:   SHA1EngineTestGroup sha1EngineTestGroup( "SHA1Engine test suite" );
   20:
   21:
   22:   template<>
   23:   template<>
   24:   void SHA1EngineTest::test<1>()
   25:   {
   26:     set_test_name( "basic" );
   27:
   28:     SHA1Engine engine;
   29:
   30:     // test vectors from FIPS 180-1
   31:
   32:     engine.update("abc");
   33:     ensure( "abc",
   34:       DigestEngine::digestToHex(engine.digest()) == "a9993e364706816aba3e25717850c26c9cd0d89d" );
   35:
   36:     engine.update( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" );
   37:     ensure( "Random chars",
   38:       DigestEngine::digestToHex(engine.digest()) == "84983e441c3bd26ebaae4aa1f95129e5e54670f1");
   39:
   40:     std::cout << "Free SRAM before million iterations: " << spt::freeRam() << std::endl;
   41:     uint32_t max = uint32_t( 1000000 );
   42:     for ( uint32_t i = 0; i < max; ++i ) engine.update( 'a' );
   43:
   44:     ensure( "Million a's",
   45:       DigestEngine::digestToHex(engine.digest()) == "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
   46:     std::cout << "Free SRAM: " << spt::freeRam() << std::endl;
   47:   }
   48: }