DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sha256_software.c Source File

sha256_software.c

00001 /*******************************************************************************
00002 * Copyright (C) 2013 Maxim Integrated Products, Inc., All Rights Reserved.
00003 *
00004 * Permission is hereby granted, free of charge, to any person obtaining a
00005 * copy of this software and associated documentation files (the "Software"),
00006 * to deal in the Software without restriction, including without limitation
00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008 * and/or sell copies of the Software, and to permit persons to whom the
00009 * Software is furnished to do so, subject to the following conditions:
00010 *
00011 * The above copyright notice and this permission notice shall be included
00012 * in all copies or substantial portions of the Software.
00013 *
00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020 * OTHER DEALINGS IN THE SOFTWARE.
00021 *
00022 * Except as contained in this notice, the name of Maxim Integrated 
00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 
00024 * Products, Inc. Branding Policy.
00025 *
00026 * The mere transfer of this software does not imply any licenses
00027 * of trade secrets, proprietary technology, copyrights, patents,
00028 * trademarks, maskwork rights, or any other form of intellectual
00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 
00030 * ownership rights.
00031 *******************************************************************************
00032 */
00033 
00034 #include <string.h>
00035 
00036 typedef unsigned char uchar;
00037 typedef unsigned short ushort;
00038 typedef unsigned long ulong;
00039 
00040 #define SHA_256_INITIAL_LENGTH    8
00041 
00042 #define TRUE 1
00043 #define FALSE 0
00044 
00045 // General Purpose SHA-256 Function
00046 void ComputeSHA256(uchar* message, short length, ushort skipconst, ushort reverse, uchar* digest);
00047 
00048 // Utility Functions
00049 static ulong sha_ch(ulong x, ulong y, ulong z);
00050 static ulong sha_maj(ulong x, ulong y, ulong z);
00051 static ulong sha_rotr_32(ulong val, ushort r);
00052 static ulong sha_shr_32(ulong val, ushort r);
00053 static ulong sha_bigsigma256_0(ulong x);
00054 static ulong sha_littlesigma256_0(ulong x);
00055 static ulong sha_littlesigma256_1(ulong x);
00056 static void sha_copy32(const ulong* p1, ulong* p2, ushort length);
00057 static void sha_copyWordsToBytes32(const ulong* input, uchar* output, ushort numwords);
00058 static void sha_writeResult(ushort reverse, uchar* outpointer, const ulong* H32);
00059 static ulong sha_getW(int index, ulong* W32);
00060 static void sha_prepareSchedule(const uchar* message, ulong* W32);
00061 static void sha256_hashblock(const uchar* message, ushort lastblock, ulong* H32);
00062 
00063 // External Debug print  
00064 #ifdef DEBUG_SHA
00065 extern int dprintf(char *format, ...);
00066 #endif
00067 
00068 // SHA-256 globals values
00069 static const ulong SHA_256_Initial[] = 
00070 {
00071    0x6a09e667,
00072    0xbb67ae85,
00073    0x3c6ef372,
00074    0xa54ff53a,
00075    0x510e527f,
00076    0x9b05688c,
00077    0x1f83d9ab,
00078    0x5be0cd19
00079 };
00080 
00081 static const ulong SHA_CONSTANTS[] =  
00082 {
00083   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
00084   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
00085   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
00086   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
00087   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
00088   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
00089   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
00090   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
00091   0xca273ece, 0xd186b8c7, 0xeada7dd6, 0xf57d4f7f, 0x06f067aa, 0x0a637dc5, 0x113f9804, 0x1b710b35,
00092   0x28db77f5, 0x32caab7b, 0x3c9ebe0a, 0x431d67c4, 0x4cc5d4be, 0x597f299c, 0x5fcb6fab, 0x6c44198c
00093 };
00094 
00095 //-----------------------------------------------------------------------------
00096 // ------ General Purpose SHA-256 Function
00097 //-----------------------------------------------------------------------------
00098 
00099 //-----------------------------------------------------------------------------
00100 /// Computes SHA-256 given the data block 'message' with no padding. 
00101 /// The result is returned in 'digest'.   
00102 ///
00103 /// @param[in] message
00104 /// Buffer containing the message to hash 
00105 /// @param[in] skipconst
00106 /// Flag to skip adding constant on last block (skipconst=1) (Required for Maxim devices)
00107 /// @param[in] reverse
00108 /// Flag to reverse order of digest (reverse=1, MSWord first, LSByte first) (Required for Maxim devices)
00109 /// @param[out] digest
00110 /// Pointer to result hash digest in byte order used by Maxim devices
00111 //
00112 void ComputeSHA256(uchar* message, short length, ushort skipconst, ushort reverse, uchar* digest)
00113 {
00114    const ushort wordsize = 32;
00115     
00116    ushort bytes_per_block;
00117    ushort nonpaddedlength;
00118    ushort numblocks;
00119    ushort i,j;
00120    ulong bitlength;
00121    ushort markerwritten;
00122    ushort lastblock;
00123    
00124    uchar workbuffer[128];
00125    ulong H32[8];                                 // last SHA result variables
00126 
00127   #ifdef DEBUG_SHA
00128   dprintf("\nSHA-256 INPUT:\n");
00129   for (i = 0; i < length; i+=4)
00130   {
00131      for (j = 0; j < 4; j++)
00132         dprintf("%02X ",message[i+j]);
00133      dprintf("\n");
00134   }
00135   dprintf("\n");
00136   #endif
00137 
00138    // if wordsize is 32 bits, we need 512 bit blocks.  else 1024 bit blocks.
00139    // that means 16 words are in one message.
00140    bytes_per_block = 16 * (wordsize / 8);
00141    // 1 byte for the '80' that follows the message, 8 or 16 bytes of length
00142    nonpaddedlength = length + 1 + (wordsize/4);
00143    numblocks = nonpaddedlength / bytes_per_block;
00144    if ((nonpaddedlength % bytes_per_block) != 0) 
00145    {
00146       // then there is some remainder we need to pad
00147       numblocks++;
00148    }
00149 
00150    sha_copy32(SHA_256_Initial, H32, SHA_256_INITIAL_LENGTH); 
00151 
00152    bitlength = 8 * length;
00153    markerwritten = 0;
00154    // 'length' is our number of bytes remaining.
00155    for (i = 0; i < numblocks; i++)
00156    {
00157       if (length > bytes_per_block)
00158       {
00159          memcpy(workbuffer, message, bytes_per_block);
00160          length -= bytes_per_block;
00161       }
00162       else if (length==bytes_per_block)
00163       {
00164          memcpy(workbuffer, message, length);
00165          length = 0;
00166       }
00167       else // length is less than number of bytes in a block
00168       {
00169          memcpy(workbuffer, message, length);
00170          // message is now used for temporary space
00171          message = workbuffer + length;     
00172          if (markerwritten == 0)
00173          {
00174             *message++ = 0x80;
00175             length++;
00176          }
00177 
00178          while (length < bytes_per_block)
00179          {
00180             // this loop is inserting padding, in this case all zeroes
00181             *message++ = 0;
00182             length++;
00183          }
00184          length = 0;
00185          // signify that we have already written the 80h
00186          markerwritten = 1;
00187       }
00188 
00189       // on the last block, put the bit length at the very end
00190       lastblock = (i == (numblocks - 1));
00191       if (lastblock)
00192       {
00193          // point at the last byte in the block
00194          message = workbuffer + bytes_per_block - 1;
00195          for (j = 0; j < wordsize/4; j++)
00196          {
00197             *message-- = (uchar)bitlength;
00198             bitlength = bitlength >> 8;
00199          }
00200       }
00201 
00202       // SHA in software 
00203       sha256_hashblock(workbuffer, (ushort)(lastblock && skipconst), H32);
00204       message += bytes_per_block;
00205    }
00206 
00207    sha_writeResult(reverse, digest, H32);
00208 
00209   #ifdef DEBUG_SHA
00210   dprintf("\nSHA-256 Result:\n");
00211   for (i = 0; i < 32; i++)
00212      dprintf("%02X ",digest[i]);
00213   dprintf("\n");
00214   #endif
00215 }
00216 
00217 //-----------------------------------------------------------------------------
00218 // ------ Internal utility functions to support SHA-256 calculation
00219 //-----------------------------------------------------------------------------
00220 
00221 //-----------------------------------------------------------------------------
00222 /// @internal
00223 /// SHA-256 support function 
00224 /// @endinternal
00225 //
00226 static ulong sha_ch(ulong x, ulong y, ulong z)
00227 {
00228    return (x & y) ^ ((~x) & z);
00229 }
00230 
00231 //-----------------------------------------------------------------------------
00232 /// @internal
00233 /// SHA-256 support function 
00234 /// @endinternal
00235 //
00236 static ulong sha_maj(ulong x, ulong y, ulong z)
00237 {
00238    ulong temp = x & y;
00239    temp ^= (x & z);
00240    temp ^= (y & z);
00241    return temp;  //(x & y) ^ (x & z) ^ (y & z);
00242 }
00243 
00244 //-----------------------------------------------------------------------------
00245 /// @internal
00246 /// SHA-256 support function 
00247 /// @endinternal
00248 //
00249 static ulong sha_rotr_32(ulong val, ushort r)
00250 {
00251    val = val & 0xFFFFFFFFL;
00252    return ((val >> r) | (val << (32 - r))) & 0xFFFFFFFFL;
00253 }
00254 
00255 //-----------------------------------------------------------------------------
00256 /// @internal
00257 /// SHA-256 support function 
00258 /// @endinternal
00259 //
00260 static ulong sha_shr_32(ulong val, ushort r)
00261 {
00262    val = val & 0xFFFFFFFFL;
00263    return val >> r;
00264 }
00265 
00266 //-----------------------------------------------------------------------------
00267 /// @internal
00268 /// SHA-256 support function 
00269 /// @endinternal
00270 //
00271 static ulong sha_bigsigma256_0(ulong x)
00272 {
00273    return sha_rotr_32(x,2) ^ sha_rotr_32(x,13) ^ sha_rotr_32(x,22);
00274 }
00275 
00276 //-----------------------------------------------------------------------------
00277 /// @internal
00278 /// SHA-256 support function 
00279 /// @endinternal
00280 //
00281 static ulong sha_bigsigma256_1(ulong x)
00282 {
00283    return sha_rotr_32(x,6) ^ sha_rotr_32(x,11) ^ sha_rotr_32(x,25);
00284 }
00285 
00286 //-----------------------------------------------------------------------------
00287 /// @internal
00288 /// SHA-256 support function 
00289 /// @endinternal
00290 //
00291 static ulong sha_littlesigma256_0(ulong x)
00292 {
00293    return sha_rotr_32(x,7) ^ sha_rotr_32(x,18) ^ sha_shr_32(x,3);
00294 }
00295 
00296 //-----------------------------------------------------------------------------
00297 /// @internal
00298 /// SHA-256 support function 
00299 /// @endinternal
00300 //
00301 static ulong sha_littlesigma256_1(ulong x)
00302 {
00303    return sha_rotr_32(x,17) ^ sha_rotr_32(x,19) ^ sha_shr_32(x,10);
00304 }
00305 
00306 //-----------------------------------------------------------------------------
00307 /// @internal
00308 /// SHA-256 support function 
00309 /// @endinternal
00310 //
00311 static void sha_copy32(const ulong* p1, ulong* p2, ushort length)
00312 {
00313    while (length > 0)
00314    {
00315       *p2++ = *p1++;
00316       length--;
00317    }
00318 }
00319 
00320 //-----------------------------------------------------------------------------
00321 /// @internal
00322 /// SHA-256 support function 
00323 /// @endinternal
00324 //
00325 static void sha_copyWordsToBytes32(const ulong* input, uchar* output, ushort numwords)
00326 {
00327     ulong temp;
00328     ushort i;
00329 
00330     for (i=0;i<numwords;i++)
00331     {
00332         temp = *input++;
00333         *output++ = (uchar)(temp >> 24);
00334         *output++ = (uchar)(temp >> 16);
00335         *output++ = (uchar)(temp >> 8);
00336         *output++ = (uchar)(temp);
00337     }
00338 }
00339 
00340 //-----------------------------------------------------------------------------
00341 /// @internal
00342 /// SHA-256 support function 
00343 /// @endinternal
00344 //
00345 static void sha_writeResult(ushort reverse, uchar* outpointer, const ulong* H32)
00346 {
00347    int i;
00348    uchar tmp;
00349 
00350    sha_copyWordsToBytes32(H32, outpointer, 8); 
00351 
00352    if (reverse)
00353    {
00354       for (i = 0; i < 16; i++)
00355       {  
00356          tmp = outpointer[i];
00357          outpointer[i] = outpointer[31-i];
00358          outpointer[31-i] = tmp;
00359       }
00360    }
00361 
00362 }
00363 
00364 //-----------------------------------------------------------------------------
00365 /// @internal
00366 /// SHA-256 support function 
00367 /// @endinternal
00368 //
00369 static ulong sha_getW(int index, ulong* W32)
00370 {
00371    ulong newW;
00372    if (index < 16)
00373    {
00374       return W32[index];
00375    }
00376 
00377    newW = sha_littlesigma256_1(W32[(index-2)&0x0f]) + 
00378             W32[(index-7)&0x0f] + 
00379           sha_littlesigma256_0(W32[(index-15)&0x0f]) + 
00380             W32[(index-16)&0x0f];
00381    W32[index & 0x0f] = newW & 0xFFFFFFFFL;  // just in case...
00382 
00383    return newW;
00384 }
00385 
00386 //-----------------------------------------------------------------------------
00387 /// @internal
00388 /// SHA-256 support function
00389 /// Prepair the block for hashing
00390 /// @endinternal
00391 //
00392 static void sha_prepareSchedule(const uchar* message, ulong* W32)
00393 {
00394    // we need to copy the initial message into the 16 W registers
00395    ushort i,j;
00396    ulong temp;
00397    for (i = 0; i < 16; i++)
00398    {
00399       temp = 0;
00400       for (j = 0; j < 4;j++)
00401       {
00402          temp = temp << 8;
00403          temp = temp | (*message & 0xff);
00404          message++;
00405       }
00406 
00407       W32[i] = temp;
00408    }
00409 }
00410 
00411 //-----------------------------------------------------------------------------
00412 /// @internal
00413 /// SHA-256 support function 
00414 /// Hash a single block of data.
00415 /// @endinternal
00416 //
00417 static void sha256_hashblock(const uchar* message, ushort lastblock, ulong* H32)
00418 {
00419    ushort sha1counter = 0;
00420    ushort sha1functionselect = 0;
00421    ushort i;
00422    ulong nodeT1, nodeT2;
00423 
00424    ulong Wt, Kt;
00425    
00426    ulong a32, b32, c32, d32, e32, f32, g32, h32; // SHA working variables
00427    ulong W32[16];                                // SHA message schedule
00428 
00429    // chunk the original message into the working schedule
00430    sha_prepareSchedule(message, W32);
00431 
00432    a32 = H32[0];
00433    b32 = H32[1];
00434    c32 = H32[2];
00435    d32 = H32[3];
00436    e32 = H32[4];
00437    f32 = H32[5];
00438    g32 = H32[6];
00439    h32 = H32[7];
00440 
00441    // rounds
00442    for (i = 0; i < 64; i++)
00443    {
00444       Wt = sha_getW(i, W32);
00445       Kt = SHA_CONSTANTS[i]; 
00446 
00447       nodeT1 = (h32 + sha_bigsigma256_1(e32) + sha_ch(e32,f32,g32) + Kt + Wt); // & 0xFFFFFFFFL;
00448       nodeT2 = (sha_bigsigma256_0(a32) + sha_maj(a32,b32,c32)); // & 0xFFFFFFFFL;
00449       h32 = g32;
00450       g32 = f32;
00451       f32 = e32;
00452       e32 = d32 + nodeT1;
00453       d32 = c32;
00454       c32 = b32;
00455       b32 = a32;
00456       a32 = nodeT1 + nodeT2;
00457 
00458       sha1counter++;
00459       if (sha1counter==20)
00460       {
00461          sha1functionselect++;
00462          sha1counter = 0;
00463       }         
00464 
00465    }
00466 
00467    if (!lastblock)
00468    {
00469       // now fix up our H array
00470       H32[0] += a32;
00471       H32[1] += b32;
00472       H32[2] += c32;
00473       H32[3] += d32;
00474       H32[4] += e32;
00475       H32[5] += f32;
00476       H32[6] += g32;
00477       H32[7] += h32;
00478    }
00479    else
00480    {
00481       // now fix up our H array
00482       H32[0] = a32;
00483       H32[1] = b32;
00484       H32[2] = c32;
00485       H32[3] = d32;
00486       H32[4] = e32;
00487       H32[5] = f32;
00488       H32[6] = g32;
00489       H32[7] = h32;
00490    }
00491 }