/** * \file * \brief Software implementation of the SHA1 algorithm. * * \copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. * * \page License * * Subject to your compliance with these terms, you may use Microchip software * and any derivatives exclusively with Microchip products. It is your * responsibility to comply with third party license terms applicable to your * use of third party software (including open source software) that may * accompany Microchip software. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR * THIS SOFTWARE. */ #include "sha1_routines.h" #include /** * \brief Initialize context for performing SHA1 hash in software. * * \param[in] ctx Hash context */ void CL_hashInit(CL_HashContext *ctx) { static const U32 hashContext_h_init[] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; // Initialize context memset(ctx, 0, sizeof(*ctx)); memcpy_P(ctx->h, hashContext_h_init, sizeof(ctx->h)); } /** * \brief Add arbitrary data to a SHA1 hash. * * \param[in] ctx Hash context * \param[in] src Data to be added to the hash * \param[in] nbytes Data size in bytes */ void CL_hashUpdate(CL_HashContext *ctx, const U8 *src, int nbytes) { /* Digest src bytes, updating context. */ U8 i, freeBytes; U32 temp32; typedef struct { U8 buf[64]; } Buf64; // We are counting on the fact that Buf64 is 64 bytes long. In // principle the compiler may make Buf64 bigger 64 bytes, but this // seems unlikely. Add an assertion check to be sure. Beware that // assert may not be active in release versions. // //assert(sizeof(Buf64) == 64); // Get number of free bytes in the buf freeBytes = (U8)(ctx->byteCount); freeBytes &= 63; freeBytes = (U8)(64 - freeBytes); while (nbytes > 0) { // Get i, number of bytes to transfer from src i = freeBytes; if (nbytes < i) { i = (U8)nbytes; } // Copy src bytes to buf if (i == 64) { // This seems to be much faster on IAR than memcpy(). *(Buf64*)(ctx->buf) = *(Buf64*)src; } else { // Have to use memcpy, size is other than 64 bytes. memcpy(((U8*)ctx->buf) + 64 - freeBytes, src, i); } // Adjust for transferred bytes src += i; nbytes -= i; freeBytes -= i; // Do SHA crunch if buf is full if (freeBytes == 0) { shaEngine(ctx->buf, ctx->h); } // Update 64-bit byte count temp32 = (ctx->byteCount += i); if (temp32 == 0) { ++ctx->byteCountHi; } // Set up for next iteration freeBytes = 64; } } /** \brief Complete the SHA1 hash in software and return the digest. * \param[in] ctx Hash context * \param[out] dest Digest is returned here (20 bytes) */ void CL_hashFinal(CL_HashContext *ctx, U8 *dest) { /* Finish a hash calculation and put result in dest. */ U8 i; U8 nbytes; U32 temp; U8 *ptr; /* Append pad byte, clear trailing bytes */ nbytes = (U8)(ctx->byteCount) & 63; ((U8*)ctx->buf)[nbytes] = 0x80; for (i = (nbytes + 1); i < 64; i++) { ((U8*)ctx->buf)[i] = 0; } /* If no room for an 8-byte count at end of buf, digest the buf, then clear it */ if (nbytes > (64 - 9)) { shaEngine(ctx->buf, ctx->h); memset(ctx->buf, 0, 64); } /* Put the 8-byte bit count at end of buf. We have been tracking bytes, not bits, so we left-shift our byte count by 3 as we do this. */ temp = ctx->byteCount << 3; // low 4 bytes of bit count ptr = &((U8*)ctx->buf)[63]; // point to low byte of bit count for (i = 0; i < 4; i++) { *ptr-- = (U8)temp; temp >>= 8; } // temp = ctx->byteCountHi << 3; temp |= ctx->byteCount >> (32 - 3); // high 4 bytes of bit count for (i = 0; i < 4; i++) { *ptr-- = (U8)temp; temp >>= 8; } //show("final SHA crunch", ctx->buf, 64); /* Final digestion */ shaEngine(ctx->buf, ctx->h); /* Unpack chaining variables to dest bytes. */ memcpy(dest, ctx->h, 20); for (i = 0; i < 5; i++) { dest[i * 4 + 0] = (ctx->h[i] >> 24) & 0xFF; dest[i * 4 + 1] = (ctx->h[i] >> 16) & 0xFF; dest[i * 4 + 2] = (ctx->h[i] >> 8) & 0xFF; dest[i * 4 + 3] = (ctx->h[i] >> 0) & 0xFF; } } /** \brief Perform SHA1 hash of data in software. * \param[in] msg Data to be hashed * \param[in] msgBytes Data size in bytes * \param[out] dest Digest is returned here (20 bytes) */ void CL_hash(U8 *msg, int msgBytes, U8 *dest) { CL_HashContext ctx; CL_hashInit(&ctx); CL_hashUpdate(&ctx, msg, msgBytes); CL_hashFinal(&ctx, dest); } void shaEngine(U32 *buf, U32 *h) { /* SHA-1 Engine. From FIPS 180. On entry, buf[64] contains the 64 bytes to digest. These bytes are destroyed. _H[20] contains the 5 chaining variables. They must have the proper value on entry and are updated on exit. The order of bytes in buf[] and _h[] matches that used by the hardware SHA engine. */ U8 t; U32 a, b, c, d, e; U32 temp = 0; U8 *p; U32 *w = (U32*)buf; /* Pack first 64 bytes of buf into w[0,...,15]. Within a word, bytes are big-endian. Do this in place -- buf[0,...,63] overlays w[0,...,15]. */ p = (U8*)w; for (t = 0; t < 16; t++) { temp = (temp << 8) | *p++; temp = (temp << 8) | *p++; temp = (temp << 8) | *p++; temp = (temp << 8) | *p++; w[t] = temp; } /* Pack the 20 bytes of _h[] into h[0,...,4]. Do in place using same convention as for buidling w[]. */ //p = (U8*)h; //for (t = 0; t < 5; t++) { //temp = (temp << 8) | *p++; //temp = (temp << 8) | *p++; //temp = (temp << 8) | *p++; //temp = (temp << 8) | *p++; //h[t] = temp; //} /* Copy the chaining variables to a, b, c, d, e */ a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4]; /* Now do the 80 rounds */ for (t = 0; t < 80; t++) { temp = a; leftRotate(temp, 5); temp += e; temp += w[t & 0xf]; if (t < 20) { temp += (b & c) | (~b & d); temp += 0x5a827999L; } else if (t < 40) { temp += b ^ c ^ d; temp += 0x6ed9eba1L; } else if (t < 60) { temp += (b & c) | (b & d) | (c & d); temp += 0x8f1bbcdcL; } else { temp += b ^ c ^ d; temp += 0xca62c1d6L; } e = d; d = c; c = b; leftRotate(c, 30); b = a; a = temp; temp = w[t & 0xf] ^ w[(t - 3) & 0xf] ^ w[(t - 8) & 0xf] ^ w[(t - 14) & 0xf]; leftRotate(temp, 1); w[t & 0xf] = temp; } /* Update the chaining variables */ h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e; /* Unpack the chaining variables into _h[] buffer. */ //p = (U8*)h; //for (t = 0; t < 5; t++) { //temp = h[t]; //p[3] = (U8)temp; temp >>= 8; //p[2] = (U8)temp; temp >>= 8; //p[1] = (U8)temp; temp >>= 8; //p[0] = (U8)temp; //p += 4; //} }