Sat Aug 6 00:39:32 2011

Asterisk developer's documentation


sha1.c

Go to the documentation of this file.
00001 /*
00002  *
00003  * Based on the RFC 3174
00004  * 
00005  * Full Copyright Statement
00006  *
00007  *  Copyright (C) The Internet Society (2001).  All Rights Reserved.
00008  *
00009  *  This document and translations of it may be copied and furnished to
00010  *  others, and derivative works that comment on or otherwise explain it
00011  *  or assist in its implementation may be prepared, copied, published
00012  *  and distributed, in whole or in part, without restriction of any
00013  *  kind, provided that the above copyright notice and this paragraph are
00014  *  included on all such copies and derivative works.  However, this
00015  *  document itself may not be modified in any way, such as by removing
00016  *  the copyright notice or references to the Internet Society or other
00017  *  Internet organizations, except as needed for the purpose of
00018  *  developing Internet standards in which case the procedures for
00019  *  copyrights defined in the Internet Standards process must be
00020  *  followed, or as required to translate it into languages other than
00021  *  English.
00022  *
00023  *  The limited permissions granted above are perpetual and will not be
00024  *  revoked by the Internet Society or its successors or assigns.
00025 
00026  *  This document and the information contained herein is provided on an
00027  *  "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
00028  *  TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
00029  *  BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
00030  *  HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
00031  *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
00032  *
00033  *
00034  * 
00035  *  Description:
00036  *   This file implements the Secure Hashing Algorithm 1 as
00037  *   defined in FIPS PUB 180-1 published April 17, 1995.
00038  *
00039  *   The SHA-1, produces a 160-bit message digest for a given
00040  *   data stream.  It should take about 2**n steps to find a
00041  *   message with the same digest as a given message and
00042  *   2**(n/2) to find any two messages with the same digest,
00043  *   when n is the digest size in bits.  Therefore, this
00044  *   algorithm can serve as a means of providing a
00045  *   "fingerprint" for a message.
00046  *
00047  *  Portability Issues:
00048  *   SHA-1 is defined in terms of 32-bit "words".  This code
00049  *   uses <stdint.h> (included via "sha1.h" to define 32 and 8
00050  *   bit unsigned integer types.  If your C compiler does not
00051  *   support 32 bit unsigned integers, this code is not
00052  *   appropriate.
00053  *
00054  *  Caveats:
00055  *   SHA-1 is designed to work with messages less than 2^64 bits
00056  *   long.  Although SHA-1 allows a message digest to be generated
00057  *   for messages of any number of bits less than 2^64, this
00058  *   implementation only works with messages with a length that is
00059  *   a multiple of the size of an 8-bit character.
00060  *
00061  */
00062 
00063 
00064 #include "asterisk/sha1.h"
00065 
00066 /*
00067  *  Define the SHA1 circular left shift macro
00068  */
00069 #define SHA1CircularShift(bits,word) \
00070                (((word) << (bits)) | ((word) >> (32-(bits))))
00071 
00072 /* Local Function Prototyptes */
00073 void SHA1PadMessage(SHA1Context *);
00074 void SHA1ProcessMessageBlock(SHA1Context *);
00075 
00076 /*
00077  *  SHA1Reset
00078  *
00079  *  Description:
00080  *   This function will initialize the SHA1Context in preparation
00081  *   for computing a new SHA1 message digest.
00082  *
00083  *  Parameters:
00084  *   context: [in/out]
00085  *       The context to reset.
00086  *
00087  *  Returns:
00088  *   sha Error Code.
00089  *
00090  */
00091 int SHA1Reset(SHA1Context *context)
00092 {
00093    if (!context) {
00094       return shaNull;
00095    }
00096 
00097    context->Length_Low             = 0;
00098    context->Length_High            = 0;
00099    context->Message_Block_Index    = 0;
00100 
00101    context->Intermediate_Hash[0]   = 0x67452301;
00102    context->Intermediate_Hash[1]   = 0xEFCDAB89;
00103    context->Intermediate_Hash[2]   = 0x98BADCFE;
00104    context->Intermediate_Hash[3]   = 0x10325476;
00105    context->Intermediate_Hash[4]   = 0xC3D2E1F0;
00106 
00107    context->Computed               = 0;
00108    context->Corrupted              = 0;
00109 
00110    return shaSuccess;
00111 }
00112 
00113 /*
00114  *  SHA1Result
00115  *
00116  *  Description:
00117  *   This function will return the 160-bit message digest into the
00118  *   Message_Digest array  provided by the caller.
00119  *   NOTE: The first octet of hash is stored in the 0th element,
00120  *         the last octet of hash in the 19th element.
00121  *
00122  *  Parameters:
00123  *   context: [in/out]
00124  *       The context to use to calculate the SHA-1 hash.
00125  *   Message_Digest: [out]
00126  *       Where the digest is returned.
00127  *
00128  *  Returns:
00129  *   sha Error Code.
00130  *
00131  */
00132 int SHA1Result( SHA1Context *context,
00133                uint8_t Message_Digest[SHA1HashSize])
00134 {
00135    int i;
00136 
00137    if (!context || !Message_Digest) {
00138       return shaNull;
00139    }
00140 
00141    if (context->Corrupted) {
00142       return context->Corrupted;
00143    }
00144 
00145    if (!context->Computed) {
00146       SHA1PadMessage(context);
00147       for (i = 0; i < 64; ++i) {
00148          /* message may be sensitive, clear it out */
00149          context->Message_Block[i] = 0;
00150       }
00151       context->Length_Low = 0;    /* and clear length */
00152       context->Length_High = 0;
00153       context->Computed = 1;
00154    }
00155 
00156    for (i = 0; i < SHA1HashSize; ++i) {
00157       Message_Digest[i] = context->Intermediate_Hash[i >> 2] >> 8 * ( 3 - ( i & 0x03 ) );
00158    }
00159 
00160    return shaSuccess;
00161 }
00162 
00163 /*
00164  *  SHA1Input
00165  *
00166  *  Description:
00167  *   This function accepts an array of octets as the next portion
00168  *   of the message.
00169  *
00170  *  Parameters:
00171  *   context: [in/out]
00172  *       The SHA context to update
00173  *   message_array: [in]
00174  *       An array of characters representing the next portion of
00175  *       the message.
00176  *   length: [in]
00177  *       The length of the message in message_array
00178  *
00179  *  Returns:
00180  *   sha Error Code.
00181  *
00182  */
00183 int SHA1Input(SHA1Context *context, const uint8_t *message_array, unsigned length)
00184 {
00185    if (!length) {
00186       return shaSuccess;
00187    }
00188 
00189    if (!context || !message_array) {
00190       return shaNull;
00191    }
00192 
00193    if (context->Computed) {
00194       context->Corrupted = shaStateError;
00195       return shaStateError;
00196    }
00197 
00198    if (context->Corrupted) {
00199       return context->Corrupted;
00200    }
00201 
00202    while (length-- && !context->Corrupted) {
00203       context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF);
00204 
00205       context->Length_Low += 8;
00206       if (context->Length_Low == 0) {
00207          context->Length_High++;
00208          if (context->Length_High == 0) {
00209             /* Message is too long */
00210             context->Corrupted = 1;
00211          }
00212       }
00213 
00214       if (context->Message_Block_Index == 64) {
00215          SHA1ProcessMessageBlock(context);
00216       }
00217 
00218       message_array++;
00219    }
00220 
00221    return shaSuccess;
00222 }
00223 
00224 /*
00225  *  SHA1ProcessMessageBlock
00226  *
00227  *  Description:
00228  *   This function will process the next 512 bits of the message
00229  *   stored in the Message_Block array.
00230  *
00231  *  Parameters:
00232  *   None.
00233  *
00234  *  Returns:
00235  *   Nothing.
00236  *
00237  *  Comments:
00238  *   Many of the variable names in this code, especially the
00239  *   single character names, were used because those were the
00240  *   names used in the publication.
00241  *
00242  *
00243  */
00244 void SHA1ProcessMessageBlock(SHA1Context *context)
00245 {
00246    const uint32_t K[] =     {     /* Constants defined in SHA-1  */
00247                             0x5A827999,
00248                             0x6ED9EBA1,
00249                             0x8F1BBCDC,
00250                             0xCA62C1D6
00251                             };
00252    int           t;                 /* Loop counter                */
00253    uint32_t    temp;              /* Temporary word value        */
00254    uint32_t    W[80];             /* Word sequence               */
00255    uint32_t    A, B, C, D, E;     /* Word buffers                */
00256 
00257    /*
00258     *  Initialize the first 16 words in the array W
00259     */
00260    for (t = 0; t < 16; t++) {
00261       W[t] = context->Message_Block[t * 4] << 24;
00262       W[t] |= context->Message_Block[t * 4 + 1] << 16;
00263       W[t] |= context->Message_Block[t * 4 + 2] << 8;
00264       W[t] |= context->Message_Block[t * 4 + 3];
00265    }
00266 
00267    for (t = 16; t < 80; t++) {
00268       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
00269    }
00270 
00271    A = context->Intermediate_Hash[0];
00272    B = context->Intermediate_Hash[1];
00273    C = context->Intermediate_Hash[2];
00274    D = context->Intermediate_Hash[3];
00275    E = context->Intermediate_Hash[4];
00276 
00277    for (t = 0; t < 20; t++) {
00278       temp = SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
00279       E = D;
00280       D = C;
00281       C = SHA1CircularShift(30,B);
00282       B = A;
00283       A = temp;
00284    }
00285 
00286    for (t = 20; t < 40; t++) {
00287       temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
00288       E = D;
00289       D = C;
00290       C = SHA1CircularShift(30,B);
00291       B = A;
00292       A = temp;
00293    }
00294 
00295    for (t = 40; t < 60; t++) {
00296       temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
00297       E = D;
00298       D = C;
00299       C = SHA1CircularShift(30,B);
00300       B = A;
00301       A = temp;
00302    }
00303 
00304    for (t = 60; t < 80; t++) {
00305       temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
00306       E = D;
00307       D = C;
00308       C = SHA1CircularShift(30,B);
00309       B = A;
00310       A = temp;
00311    }
00312 
00313    context->Intermediate_Hash[0] += A;
00314    context->Intermediate_Hash[1] += B;
00315    context->Intermediate_Hash[2] += C;
00316    context->Intermediate_Hash[3] += D;
00317    context->Intermediate_Hash[4] += E;
00318 
00319    context->Message_Block_Index = 0;
00320 }
00321 
00322 
00323 /*
00324  *  SHA1PadMessage
00325  *
00326  *  Description:
00327  *   According to the standard, the message must be padded to an even
00328  *   512 bits.  The first padding bit must be a '1'.  The last 64
00329  *   bits represent the length of the original message.  All bits in
00330  *   between should be 0.  This function will pad the message
00331  *   according to those rules by filling the Message_Block array
00332  *   accordingly.  It will also call the ProcessMessageBlock function
00333  *   provided appropriately.  When it returns, it can be assumed that
00334  *   the message digest has been computed.
00335  *
00336  *  Parameters:
00337  *   context: [in/out]
00338  *       The context to pad
00339  *   ProcessMessageBlock: [in]
00340  *       The appropriate SHA*ProcessMessageBlock function
00341  *  Returns:
00342  *   Nothing.
00343  *
00344  */
00345 
00346 void SHA1PadMessage(SHA1Context *context)
00347 {
00348    /*
00349     *  Check to see if the current message block is too small to hold
00350     *  the initial padding bits and length.  If so, we will pad the
00351     *  block, process it, and then continue padding into a second
00352     *  block.
00353     */
00354    if (context->Message_Block_Index > 55) {
00355       context->Message_Block[context->Message_Block_Index++] = 0x80;
00356       while (context->Message_Block_Index < 64) {
00357          context->Message_Block[context->Message_Block_Index++] = 0;
00358       }
00359 
00360       SHA1ProcessMessageBlock(context);
00361 
00362       while (context->Message_Block_Index < 56) {
00363          context->Message_Block[context->Message_Block_Index++] = 0;
00364       }
00365    } else {
00366       context->Message_Block[context->Message_Block_Index++] = 0x80;
00367       while (context->Message_Block_Index < 56) {
00368          context->Message_Block[context->Message_Block_Index++] = 0;
00369       }
00370    }
00371 
00372    /*
00373     *  Store the message length as the last 8 octets
00374     */
00375    context->Message_Block[56] = context->Length_High >> 24;
00376    context->Message_Block[57] = context->Length_High >> 16;
00377    context->Message_Block[58] = context->Length_High >> 8;
00378    context->Message_Block[59] = context->Length_High;
00379    context->Message_Block[60] = context->Length_Low >> 24;
00380    context->Message_Block[61] = context->Length_Low >> 16;
00381    context->Message_Block[62] = context->Length_Low >> 8;
00382    context->Message_Block[63] = context->Length_Low;
00383 
00384    SHA1ProcessMessageBlock(context);
00385 }

Generated on Sat Aug 6 00:39:32 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7