Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sha1.c Source File

sha1.c

Go to the documentation of this file.
00001 /**
00002  * @file sha1.c
00003  * @brief SHA-1 (Secure Hash Algorithm 1)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneCrypto Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @section Description
00026  *
00027  * SHA-1 is a secure hash algorithm for computing a condensed representation
00028  * of an electronic message. Refer to FIPS 180-4 for more details
00029  *
00030  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00031  * @version 1.7.6
00032  **/
00033 
00034 //Switch to the appropriate trace level
00035 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
00036 
00037 //Dependencies
00038 #include <string.h>
00039 #include "crypto.h"
00040 #include "sha1.h"
00041 
00042 //Check crypto library configuration
00043 #if (SHA1_SUPPORT == ENABLED)
00044 
00045 //Macro to access the workspace as a circular buffer
00046 #define W(t) w[(t) & 0x0F]
00047 
00048 //SHA-1 auxiliary functions
00049 #define CH(x, y, z) (((x) & (y)) | (~(x) & (z)))
00050 #define PARITY(x, y, z) ((x) ^ (y) ^ (z))
00051 #define MAJ(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
00052 
00053 //SHA-1 padding
00054 static const uint8_t padding[64] =
00055 {
00056    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00057    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00058    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00059    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00060 };
00061 
00062 //SHA-1 constants
00063 static const uint32_t k[4] =
00064 {
00065    0x5A827999,
00066    0x6ED9EBA1,
00067    0x8F1BBCDC,
00068    0xCA62C1D6
00069 };
00070 
00071 //SHA-1 object identifier (1.3.14.3.2.26)
00072 static const uint8_t sha1Oid[] = {0x2B, 0x0E, 0x03, 0x02, 0x1A};
00073 
00074 //Common interface for hash algorithms
00075 const HashAlgo sha1HashAlgo =
00076 {
00077    "SHA-1",
00078    sha1Oid,
00079    sizeof(sha1Oid),
00080    sizeof(Sha1Context),
00081    SHA1_BLOCK_SIZE,
00082    SHA1_DIGEST_SIZE,
00083    (HashAlgoCompute) sha1Compute,
00084    (HashAlgoInit) sha1Init,
00085    (HashAlgoUpdate) sha1Update,
00086    (HashAlgoFinal) sha1Final
00087 };
00088 
00089 
00090 /**
00091  * @brief Digest a message using SHA-1
00092  * @param[in] data Pointer to the message being hashed
00093  * @param[in] length Length of the message
00094  * @param[out] digest Pointer to the calculated digest
00095  * @return Error code
00096  **/
00097 
00098 error_t sha1Compute(const void *data, size_t length, uint8_t *digest)
00099 {
00100    //Allocate a memory buffer to hold the SHA-1 context
00101    Sha1Context *context = cryptoAllocMem(sizeof(Sha1Context));
00102    //Failed to allocate memory?
00103    if(context == NULL)
00104       return ERROR_OUT_OF_MEMORY;
00105 
00106    //Initialize the SHA-1 context
00107    sha1Init(context);
00108    //Digest the message
00109    sha1Update(context, data, length);
00110    //Finalize the SHA-1 message digest
00111    sha1Final(context, digest);
00112 
00113    //Free previously allocated memory
00114    cryptoFreeMem(context);
00115    //Successful processing
00116    return NO_ERROR;
00117 }
00118 
00119 
00120 /**
00121  * @brief Initialize SHA-1 message digest context
00122  * @param[in] context Pointer to the SHA-1 context to initialize
00123  **/
00124 
00125 void sha1Init(Sha1Context *context)
00126 {
00127    //Set initial hash value
00128    context->h[0] = 0x67452301;
00129    context->h[1] = 0xEFCDAB89;
00130    context->h[2] = 0x98BADCFE;
00131    context->h[3] = 0x10325476;
00132    context->h[4] = 0xC3D2E1F0;
00133 
00134    //Number of bytes in the buffer
00135    context->size = 0;
00136    //Total length of the message
00137    context->totalSize = 0;
00138 }
00139 
00140 
00141 /**
00142  * @brief Update the SHA-1 context with a portion of the message being hashed
00143  * @param[in] context Pointer to the SHA-1 context
00144  * @param[in] data Pointer to the buffer being hashed
00145  * @param[in] length Length of the buffer
00146  **/
00147 
00148 void sha1Update(Sha1Context *context, const void *data, size_t length)
00149 {
00150    size_t n;
00151 
00152    //Process the incoming data
00153    while(length > 0)
00154    {
00155       //The buffer can hold at most 64 bytes
00156       n = MIN(length, 64 - context->size);
00157 
00158       //Copy the data to the buffer
00159       memcpy(context->buffer + context->size, data, n);
00160 
00161       //Update the SHA-1 context
00162       context->size += n;
00163       context->totalSize += n;
00164       //Advance the data pointer
00165       data = (uint8_t *) data + n;
00166       //Remaining bytes to process
00167       length -= n;
00168 
00169       //Process message in 16-word blocks
00170       if(context->size == 64)
00171       {
00172          //Transform the 16-word block
00173          sha1ProcessBlock(context);
00174          //Empty the buffer
00175          context->size = 0;
00176       }
00177    }
00178 }
00179 
00180 
00181 /**
00182  * @brief Finish the SHA-1 message digest
00183  * @param[in] context Pointer to the SHA-1 context
00184  * @param[out] digest Calculated digest (optional parameter)
00185  **/
00186 
00187 void sha1Final(Sha1Context *context, uint8_t *digest)
00188 {
00189    uint_t i;
00190    size_t paddingSize;
00191    uint64_t totalSize;
00192 
00193    //Length of the original message (before padding)
00194    totalSize = context->totalSize * 8;
00195 
00196    //Pad the message so that its length is congruent to 56 modulo 64
00197    if(context->size < 56)
00198       paddingSize = 56 - context->size;
00199    else
00200       paddingSize = 64 + 56 - context->size;
00201 
00202    //Append padding
00203    sha1Update(context, padding, paddingSize);
00204 
00205    //Append the length of the original message
00206    context->w[14] = htobe32((uint32_t) (totalSize >> 32));
00207    context->w[15] = htobe32((uint32_t) totalSize);
00208 
00209    //Calculate the message digest
00210    sha1ProcessBlock(context);
00211 
00212    //Convert from host byte order to big-endian byte order
00213    for(i = 0; i < 5; i++)
00214       context->h[i] = htobe32(context->h[i]);
00215 
00216    //Copy the resulting digest
00217    if(digest != NULL)
00218       memcpy(digest, context->digest, SHA1_DIGEST_SIZE);
00219 }
00220 
00221 
00222 /**
00223  * @brief Process message in 16-word blocks
00224  * @param[in] context Pointer to the SHA-1 context
00225  **/
00226 
00227 void sha1ProcessBlock(Sha1Context *context)
00228 {
00229    uint_t t;
00230    uint32_t temp;
00231 
00232    //Initialize the 5 working registers
00233    uint32_t a = context->h[0];
00234    uint32_t b = context->h[1];
00235    uint32_t c = context->h[2];
00236    uint32_t d = context->h[3];
00237    uint32_t e = context->h[4];
00238 
00239    //Process message in 16-word blocks
00240    uint32_t *w = context->w;
00241 
00242    //Convert from big-endian byte order to host byte order
00243    for(t = 0; t < 16; t++)
00244       w[t] = betoh32(w[t]);
00245 
00246    //SHA-1 hash computation (alternate method)
00247    for(t = 0; t < 80; t++)
00248    {
00249       //Prepare the message schedule
00250       if(t >= 16)
00251          W(t) = ROL32(W(t + 13) ^ W(t + 8) ^ W(t + 2) ^ W(t), 1);
00252 
00253       //Calculate T
00254       if(t < 20)
00255          temp = ROL32(a, 5) + CH(b, c, d) + e + W(t) + k[0];
00256       else if(t < 40)
00257          temp = ROL32(a, 5) + PARITY(b, c, d) + e + W(t) + k[1];
00258       else if(t < 60)
00259          temp = ROL32(a, 5) + MAJ(b, c, d) + e + W(t) + k[2];
00260       else
00261          temp = ROL32(a, 5) + PARITY(b, c, d) + e + W(t) + k[3];
00262 
00263       //Update the working registers
00264       e = d;
00265       d = c;
00266       c = ROL32(b, 30);
00267       b = a;
00268       a = temp;
00269    }
00270 
00271    //Update the hash value
00272    context->h[0] += a;
00273    context->h[1] += b;
00274    context->h[2] += c;
00275    context->h[3] += d;
00276    context->h[4] += e;
00277 }
00278 
00279 #endif
00280