Wiselib
|
00001 /*************************************************************************** 00002 ** This file is part of the generic algorithm library Wiselib. ** 00003 ** Copyright (C) 2008,2009 by the Wisebed (www.wisebed.eu) project. ** 00004 ** ** 00005 ** The Wiselib is free software: you can redistribute it and/or modify ** 00006 ** it under the terms of the GNU Lesser General Public License as ** 00007 ** published by the Free Software Foundation, either version 3 of the ** 00008 ** License, or (at your option) any later version. ** 00009 ** ** 00010 ** The Wiselib is distributed in the hope that it will be useful, ** 00011 ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 00012 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 00013 ** GNU Lesser General Public License for more details. ** 00014 ** ** 00015 ** You should have received a copy of the GNU Lesser General Public ** 00016 ** License along with the Wiselib. ** 00017 ** If not, see <http://www.gnu.org/licenses/>. ** 00018 ***************************************************************************/ 00019 00020 #ifndef __ALGORITHMS_CRYPTO_SHA1_H_ 00021 #define __ALGORITHMS_CRYPTO_SHA1_H_ 00022 00023 #include "algorithms/crypto/pmp.h" 00024 #include <string.h> 00025 00026 #ifndef _SHA_enum_ 00027 #define _SHA_enum_ 00028 enum 00029 { 00030 shaSuccess = 0, 00031 shaNull, /* Null pointer parameter */ 00032 shaInputTooLong, /* input data too long */ 00033 shaStateError /* called Input after Result */ 00034 }; 00035 #endif 00036 #define SHA1HashSize 20 00037 #define METHOD2 00038 00039 /*Define the circular shift macro*/ 00040 #define SHA1CircularShift(bits,word) \ 00041 ((((word) << (bits)) & 0xFFFFFFFF) | \ 00042 ((word) >> (32-(bits)))) 00043 00044 00045 namespace wiselib 00046 { 00047 typedef struct SHA1Context 00048 { 00049 uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ 00050 00051 uint32_t Length_Low; /* Message length in bits */ 00052 uint32_t Length_High; /* Message length in bits */ 00053 00054 /* Index into message block array */ 00055 uint16_t Message_Block_Index; 00056 uint8_t Message_Block[64]; /* 512-bit message blocks */ 00057 00058 int8_t Computed; /* Is the digest computed? */ 00059 int8_t Corrupted; /* Is the message digest corrupted? */ 00060 } SHA1Context; 00061 00071 class SHA1 00072 { 00073 public: 00074 00075 //sha1reset 00076 static void SHA1Reset(SHA1Context *context) 00077 { 00078 context->Length_Low = 0; 00079 context->Length_High = 0; 00080 context->Message_Block_Index = 0; 00081 00082 context->Intermediate_Hash[0] = 0x67452301; 00083 context->Intermediate_Hash[1] = 0xEFCDAB89; 00084 context->Intermediate_Hash[2] = 0x98BADCFE; 00085 context->Intermediate_Hash[3] = 0x10325476; 00086 context->Intermediate_Hash[4] = 0xC3D2E1F0; 00087 00088 context->Computed = 0; 00089 context->Corrupted = 0; 00090 } 00091 00092 //sha1processmessageblock 00093 static void SHA1ProcessMessageBlock(SHA1Context *context) 00094 { 00095 const uint32_t K[] = { /* Constants defined in SHA-1 */ 00096 0x5A827999, 00097 0x6ED9EBA1, 00098 0x8F1BBCDC, 00099 0xCA62C1D6 00100 }; 00101 uint8_t t; /* Loop counter */ 00102 uint32_t temp; /* Temporary word value */ 00103 #ifdef METHOD2 00104 uint8_t s; 00105 uint32_t W[16]; 00106 #else 00107 uint32_t W[80]; /* Word sequence */ 00108 #endif 00109 uint32_t wA, wB, wC, wD, wE; /* Word buffers */ 00110 00111 /* 00112 * Initialize the first 16 words in the array W 00113 */ 00114 for(t = 0; t < 16; t++){ 00115 W[t] = ((uint32_t)context->Message_Block[t * 4]) << 24; 00116 W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16; 00117 W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8; 00118 W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]); 00119 } 00120 00121 #ifndef METHOD2 00122 for(t = 16; t < 80; t++){ 00123 W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 00124 } 00125 #endif 00126 00127 wA = context->Intermediate_Hash[0]; 00128 wB = context->Intermediate_Hash[1]; 00129 wC = context->Intermediate_Hash[2]; 00130 wD = context->Intermediate_Hash[3]; 00131 wE = context->Intermediate_Hash[4]; 00132 00133 for(t = 0; t < 20; t++){ 00134 #ifdef METHOD2 00135 s = t & 0x0f; 00136 if (t >= 16){ 00137 W[s] = SHA1CircularShift(1, 00138 W[(s + 13) & 0x0f] ^ \ 00139 W[(s + 8) & 0x0f] ^ \ 00140 W[(s + 2) & 0x0f] ^ \ 00141 W[s]); 00142 } 00143 temp = SHA1CircularShift(5,wA) + 00144 ((wB & wC) | ((~wB) & wD)) + wE + W[s] + K[0]; 00145 #else 00146 temp = SHA1CircularShift(5,A) + 00147 ((wB & wC) | ((~wB) & wD)) + wE + W[t] + K[0]; 00148 #endif 00149 wE = wD; 00150 wD = wC; 00151 wC = SHA1CircularShift(30,wB); 00152 00153 wB = wA; 00154 wA = temp; 00155 } 00156 00157 for(t = 20; t < 40; t++){ 00158 #ifdef METHOD2 00159 s = t & 0x0f; 00160 W[s] = SHA1CircularShift(1, 00161 W[(s + 13) & 0x0f] ^ \ 00162 W[(s + 8) & 0x0f] ^ \ 00163 W[(s + 2) & 0x0f] ^ \ 00164 W[s]); 00165 temp = SHA1CircularShift(5,wA) + (wB ^ wC ^ wD) + wE + W[s] + K[1]; 00166 #else 00167 temp = SHA1CircularShift(5,wA) + (wB ^ wC ^ wD) + wE + W[t] + K[1]; 00168 #endif 00169 wE = wD; 00170 wD = wC; 00171 wC = SHA1CircularShift(30,wB); 00172 wB = wA; 00173 wA = temp; 00174 } 00175 00176 for(t = 40; t < 60; t++){ 00177 #ifdef METHOD2 00178 s = t & 0x0f; 00179 W[s] = SHA1CircularShift(1, 00180 W[(s + 13) & 0x0f] ^ \ 00181 W[(s + 8) & 0x0f] ^ \ 00182 W[(s + 2) & 0x0f] ^ \ 00183 W[s]); 00184 temp = SHA1CircularShift(5,wA) + 00185 ((wB & wC) | (wB & wD) | (wC & wD)) + wE + W[s] + K[2]; 00186 #else 00187 temp = SHA1CircularShift(5,A) + 00188 ((wB & wC) | (wB & wD) | (wC & wD)) + wE + W[t] + K[2]; 00189 #endif 00190 wE = wD; 00191 wD = wC; 00192 wC = SHA1CircularShift(30,wB); 00193 wB = wA; 00194 wA = temp; 00195 } 00196 00197 for(t = 60; t < 80; t++){ 00198 #ifdef METHOD2 00199 s = t & 0x0f; 00200 W[s] = SHA1CircularShift(1, 00201 W[(s + 13) & 0x0f] ^ \ 00202 W[(s + 8) & 0x0f] ^ \ 00203 W[(s + 2) & 0x0f] ^ \ 00204 W[s]); 00205 temp = SHA1CircularShift(5,wA) + (wB ^ wC ^ wD) + wE + W[s] + K[3]; 00206 #else 00207 temp = SHA1CircularShift(5,wA) + (wB ^ wC ^ wD) + wE + W[t] + K[3]; 00208 #endif 00209 wE = wD; 00210 wD = wC; 00211 wC = SHA1CircularShift(30,wB); 00212 wB = wA; 00213 wA = temp; 00214 } 00215 00216 context->Intermediate_Hash[0] += wA; 00217 context->Intermediate_Hash[1] += wB; 00218 context->Intermediate_Hash[2] += wC; 00219 context->Intermediate_Hash[3] += wD; 00220 context->Intermediate_Hash[4] += wE; 00221 00222 context->Message_Block_Index = 0; 00223 } 00224 00225 //sha1pad 00226 static void SHA1PadMessage(SHA1Context *context) 00227 { 00228 /* 00229 * Check to see if the current message block is too small to hold 00230 * the initial padding bits and length. If so, we will pad the 00231 * block, process it, and then continue padding into a second 00232 * block. 00233 */ 00234 if (context->Message_Block_Index > 55){ 00235 context->Message_Block[context->Message_Block_Index++] = 0x80; 00236 while(context->Message_Block_Index < 64){ 00237 context->Message_Block[context->Message_Block_Index++] = 0; 00238 } 00239 00240 SHA1ProcessMessageBlock(context); 00241 00242 while(context->Message_Block_Index < 56){ 00243 context->Message_Block[context->Message_Block_Index++] = 0; 00244 } 00245 }else{ 00246 context->Message_Block[context->Message_Block_Index++] = 0x80; 00247 while(context->Message_Block_Index < 56){ 00248 context->Message_Block[context->Message_Block_Index++] = 0; 00249 } 00250 } 00251 00252 /* 00253 * Store the message length as the last 8 octets 00254 */ 00255 context->Message_Block[56] = context->Length_High >> 24; 00256 context->Message_Block[57] = context->Length_High >> 16; 00257 context->Message_Block[58] = context->Length_High >> 8; 00258 context->Message_Block[59] = context->Length_High; 00259 context->Message_Block[60] = context->Length_Low >> 24; 00260 context->Message_Block[61] = context->Length_Low >> 16; 00261 context->Message_Block[62] = context->Length_Low >> 8; 00262 context->Message_Block[63] = context->Length_Low; 00263 00264 SHA1ProcessMessageBlock(context); 00265 } 00266 00267 //sha1digest 00268 static int8_t SHA1Digest( SHA1Context *context, uint8_t Message_Digest[SHA1HashSize]) 00269 { 00270 uint8_t i; 00271 00272 if (!context || !Message_Digest){ 00273 return shaNull; 00274 } 00275 00276 if (context->Corrupted){ 00277 return context->Corrupted; 00278 } 00279 00280 if (!context->Computed){ 00281 SHA1PadMessage(context); 00282 for(i=0; i<64; ++i){ 00283 /* message may be sensitive, clear it out */ 00284 context->Message_Block[i] = 0; 00285 } 00286 context->Length_Low = 0; /* and clear length */ 00287 context->Length_High = 0; 00288 context->Computed = 1; 00289 00290 } 00291 00292 for(i = 0; i < SHA1HashSize; ++i){ 00293 Message_Digest[i] = context->Intermediate_Hash[i>>2] 00294 >> 8 * ( 3 - ( i & 0x03 ) ); 00295 } 00296 00297 return 1; 00298 } 00299 00300 //sha1update 00301 static int8_t SHA1Update(SHA1Context *context, const uint8_t *message_array, uint32_t length) 00302 { 00303 if (!length){ 00304 return shaSuccess; 00305 } 00306 00307 if (!context || !message_array){ 00308 return shaNull; 00309 } 00310 00311 if (context->Computed){ 00312 context->Corrupted = shaStateError; 00313 00314 return shaStateError; 00315 } 00316 00317 if (context->Corrupted){ 00318 return context->Corrupted; 00319 } 00320 while(length-- && !context->Corrupted){ 00321 context->Message_Block[context->Message_Block_Index++] = 00322 (*message_array & 0xFF); 00323 00324 context->Length_Low += 8; 00325 if (context->Length_Low == 0){ 00326 context->Length_High++; 00327 if (context->Length_High == 0){ 00328 /* Message is too long */ 00329 context->Corrupted = 1; 00330 } 00331 } 00332 00333 if (context->Message_Block_Index == 64){ 00334 SHA1ProcessMessageBlock(context); 00335 } 00336 00337 message_array++; 00338 } 00339 00340 return shaSuccess; 00341 } 00342 00343 //key derivation function 00344 static void KDF(uint8_t *Kp, int32_t K_len, uint8_t *Zp) 00345 { 00346 int32_t len, i; 00347 uint8_t z[KEYDIGITS*NN_DIGIT_LEN+4]; 00348 SHA1Context ctx; 00349 uint8_t sha1sum[20]; 00350 00351 memcpy(z, Zp, KEYDIGITS*NN_DIGIT_LEN); 00352 memset(z + KEYDIGITS*NN_DIGIT_LEN, 0, 3); 00353 //KDF 00354 len = K_len; 00355 i = 1; 00356 while(len > 0){ 00357 z[KEYDIGITS*NN_DIGIT_LEN + 3] = i; 00358 SHA1Reset(&ctx); 00359 SHA1Update(&ctx, z, KEYDIGITS*NN_DIGIT_LEN+4); 00360 SHA1Digest(&ctx, sha1sum); 00361 if(len >= 20){ 00362 memcpy(Kp+(i-1)*20, sha1sum, 20); 00363 }else{ 00364 memcpy(Kp+(i-1)*20, sha1sum, len); 00365 } 00366 i++; 00367 len = len - 20; 00368 } 00369 } 00370 00371 00372 //function for mac generation on the data and the key 00373 static void hmac_sha1(uint8_t *text, int32_t text_len, uint8_t *key, int32_t key_len, uint8_t *digest) 00374 { 00375 SHA1Context context; 00376 uint8_t k_ipad[65]; /* inner padding - 00377 * key XORd with ipad 00378 */ 00379 uint8_t k_opad[65]; /* outer padding - 00380 * key XORd with opad 00381 */ 00382 int8_t i; 00383 00384 /* 00385 * the HMAC_SHA1 transform looks like: 00386 * 00387 * SHA1(K XOR opad, SHA1(K XOR ipad, text)) 00388 * 00389 * where K is an n byte key 00390 * ipad is the byte 0x36 repeated 64 times 00391 00392 * opad is the byte 0x5c repeated 64 times 00393 * and text is the data being protected 00394 */ 00395 00396 /* start out by storing key in pads */ 00397 memcpy(k_ipad, key, key_len); 00398 memset(k_ipad + key_len, 0, 65 - key_len); 00399 memcpy(k_opad, key, key_len); 00400 memset(k_opad + key_len, 0, 65 - key_len); 00401 00402 /* XOR key with ipad and opad values */ 00403 for (i=0; i<64; i++) { 00404 k_ipad[i] ^= 0x36; 00405 k_opad[i] ^= 0x5c; 00406 } 00407 /* 00408 * perform inner SHA1 00409 */ 00410 SHA1Reset(&context); /* init context for 1st pass */ 00411 SHA1Update(&context, k_ipad, 64); /* start with inner pad */ 00412 SHA1Update(&context, text, text_len); /* then text of datagram */ 00413 SHA1Digest(&context, digest); /* finish up 1st pass */ 00414 /* 00415 * perform outer SHA1 00416 */ 00417 SHA1Reset(&context); /* init context for 2nd pass */ 00418 SHA1Update(&context, k_opad, 64); /* start with outer pad */ 00419 SHA1Update(&context, digest, 20); 00420 SHA1Digest(&context, digest); /* then results of 1st hash */ 00421 00422 } 00423 }; 00424 00425 } //end of namespace wiselib 00426 00427 #endif //SHA1_H 00428