Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

/ray/src/lib/crypto/sha1hash.cc

Go to the documentation of this file.
00001 /*
00002  * lib/crypto/sha1hash.cc
00003  * 
00004  * Implementation of class SHA1Hash, a class for computing the 
00005  * SHA1 message digest / hash algorithm as specified by NIST/NSA 
00006  * (not the original weaker SHA0 algorithm, but the one extended 
00007  * with a rotation in the expanding function as added lateron by 
00008  * the NSA).
00009  * 
00010  * Copyright (c) 2000--2004 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 
00011  * 
00012  * This file may be distributed and/or modified under the terms of the 
00013  * GNU General Public License version 2 as published by the Free Software 
00014  * Foundation. (See COPYING.GPL for details.)
00015  * 
00016  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00017  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00018  * 
00019  */
00020 
00021 #include "sha1hash.h"
00022 
00023 const SecureHashBase::Parameters SHA1Hash::par=
00024 {
00025     INIT_FIELD(hash_size) 20,
00026     INIT_FIELD(block_size) 64,
00027     INIT_FIELD(hash_ID) 0x1001,
00028     INIT_FIELD(name) "SHA1"
00029 };
00030 
00031 
00032 static inline uint32 sha_func0(uint32 x,uint32 y,uint32 z)
00033     //{  return((x & y) | ((~x) & z));  }  // slower 
00034     {  return(z ^ (x & (y ^ z)));  }  // faster
00035 
00036 static inline uint32 sha_func1(uint32 x,uint32 y,uint32 z)
00037     {  return(x ^ y ^ z);  }
00038 
00039 static inline uint32 sha_func2(uint32 x,uint32 y,uint32 z)
00040     //{  return((x & y) | (x & z) | (y & z));  }  // slower
00041     {  return((x & y) | (z & (x | y)));  }  // faster
00042 
00043 static inline uint32 sha_func3(uint32 x,uint32 y,uint32 z)
00044     {  return(x ^ y ^ z);  }
00045 
00046 static inline uint32 rotate(uint32 x,int n)
00047     {  return((x<<n) | (x>>(32-n)));  }
00048 
00049 
00050 // All this magic stuff...
00051 static const uint32 sha_const0 = 0x5a827999U;
00052 static const uint32 sha_const1 = 0x6ed9eba1U;
00053 static const uint32 sha_const2 = 0x8f1bbcdcU;
00054 static const uint32 sha_const3 = 0xca62c1d6U;
00055 
00056 static const uint32 sha_init_state[5]=
00057     { 0x67452301U, 0xefcdab89U, 0x98badcfeU, 0x10325476U, 0xc3d2e1f0U };
00058 
00059 
00060 // NOTE: the rotation was added later by the NSA... 
00061 #define EXPAND(pa,pb,pc,pd) \
00062     rotate(*(pa++) ^ *(pb++) ^ *(pc++) ^ *(pd++),1)
00063 
00064 
00065 // msg: size 64 bytes
00066 // w: temporary buffer where AtomicHash stores (expanded) input data (msg). 
00067 void SHA1Hash::AtomicHash(const unsigned char *msg,uint32 *w)
00068 {
00069     register uint32 *p;
00070     uint32 *we=&w[16];
00071     
00072     // Fill message into w-buffer. 
00073     for(p=w; p<we; p++)
00074     {
00075         // We want MSB first 
00076         // (htonl() converts LSBfirst -> MSBfirst in i386; but not used 
00077         // here as it would need word alignment of msg data.) 
00078         *p= uint32(*(msg++));   *p<<=8;
00079         *p|=uint32(*(msg++));   *p<<=8;
00080         *p|=uint32(*(msg++));   *p<<=8;
00081         *p|=uint32(*(msg++));
00082     }
00083     
00084     uint32 *p_03=p-3;
00085     uint32 *p_08=p-8;
00086     uint32 *p_14=p-14;
00087     uint32 *p_16=p-16;
00088     we=&w[20];
00089     while(p<we)   // 20-16=4 times
00090     {  *(p++) = EXPAND(p_03,p_08,p_14,p_16);  }
00091     
00092     // Now compute the loops: 
00093     uint32 a=state[0], b=state[1], c=state[2], d=state[3], e=state[4];
00094     uint32 tmp,sha_const=sha_const0;
00095     for(p=w; p<we; p++)
00096     {
00097         tmp = rotate(a,5) + sha_func0(b,c,d) + e + (*p) + sha_const;
00098         e=d;  d=c;
00099         c=rotate(b,30);
00100         b=a;  a=tmp;
00101     }
00102     sha_const=sha_const1;
00103     for(we+=20; p<we; p++)
00104     {
00105         *p = EXPAND(p_03,p_08,p_14,p_16);
00106         tmp = rotate(a,5) + sha_func1(b,c,d) + e + (*p) + sha_const;
00107         e=d;  d=c;
00108         c=rotate(b,30);
00109         b=a;  a=tmp;
00110     }
00111     sha_const=sha_const2;
00112     for(we+=20; p<we; p++)
00113     {
00114         *p = EXPAND(p_03,p_08,p_14,p_16);
00115         tmp = rotate(a,5) + sha_func2(b,c,d) + e + (*p) + sha_const;
00116         e=d;  d=c;
00117         c=rotate(b,30);
00118         b=a;  a=tmp;
00119     }
00120     sha_const=sha_const3;
00121     for(we+=20; p<we; p++)
00122     {
00123         *p = EXPAND(p_03,p_08,p_14,p_16);
00124         tmp = rotate(a,5) + sha_func3(b,c,d) + e + (*p) + sha_const;
00125         e=d;  d=c;
00126         c=rotate(b,30);
00127         b=a;  a=tmp;
00128     }
00129     
00130     // Add the result: 
00131     state[0]+=a;
00132     state[1]+=b;
00133     state[2]+=c;
00134     state[3]+=d;
00135     state[4]+=e;
00136 }
00137 
00138 
00139 void SHA1Hash::GetHash(char *buf) const
00140 {
00141     register unsigned char *hsh=(unsigned char*)buf+3;
00142     for(register const uint32 *i=state,*ie=&state[5]; i<ie; i++)
00143     {
00144         register uint32 j=*i;
00145         *(hsh--)=(unsigned char)(j & 0xffU);  j>>=8;
00146         *(hsh--)=(unsigned char)(j & 0xffU);  j>>=8;
00147         *(hsh--)=(unsigned char)(j & 0xffU);  j>>=8;
00148         *(hsh  )=(unsigned char)(j & 0xffU);
00149         hsh+=7;  // 4+3; would be 4+4 if the last *(hsh  )=... was *(hsh--)=...
00150     }
00151 }
00152 
00153 
00154 void SHA1Hash::reset()
00155 {
00156     length=0LLU;
00157     state[0]=sha_init_state[0];
00158     state[1]=sha_init_state[1];
00159     state[2]=sha_init_state[2];
00160     state[3]=sha_init_state[3];
00161     state[4]=sha_init_state[4];
00162     tmp_size=0;
00163     for(unsigned char *d=tmpbuf,*de=d+64; d<de; d++)
00164     {  *d=(unsigned char)0;  }
00165 }
00166 
00167 
00168 void SHA1Hash::feed(const char *_buf,size_t len)
00169 {
00170     if(!len)
00171     {  return;  }
00172     
00173     const unsigned char *buf=(const unsigned char*)_buf;
00174     uint32 w[80];   // Yes, this is 4*80 bytes, NOT 4*20 bytes. 
00175     
00176     if(tmp_size)  // There is some data left from last time. 
00177     {
00178         size_t needed=64-tmp_size;
00179         if(len>=needed)
00180         {
00181             for(unsigned char *d=&tmpbuf[tmp_size],*de=&tmpbuf[64]; d<de; d++)
00182             {  *d=*(buf++);  }
00183             AtomicHash(tmpbuf,w);
00184             len-=needed;
00185             tmp_size=0;
00186             length+=64LLU;
00187             if(!len)
00188             {  return;  }
00189         }
00190         else
00191         {
00192             unsigned char *d=&tmpbuf[tmp_size];
00193             tmp_size+=int(len);
00194             for(unsigned char *de=&tmpbuf[tmp_size]; d<de; d++)
00195             {  *d=*(buf++);  }
00196             return;
00197         }
00198     }
00199     
00200     size_t l=len;
00201     for(;;)
00202     {
00203         if(l<64)
00204         {  break;  }
00205         AtomicHash((const unsigned char*)buf,w);
00206         buf+=64;
00207         l-=64;
00208     }
00209     length+=uint64(len-l);
00210     if(l)  // Some bytes left; store them for later. 
00211     {
00212         for(unsigned char *d=tmpbuf,*de=d+l; d<de; d++)
00213         {  *d=*(buf++);  }
00214         tmp_size=int(l);
00215     }
00216 }
00217 
00218 
00219 void SHA1Hash::final()
00220 {
00221     uint32 w[80];   // Yes, this is 4*80 bytes, NOT 4*20 bytes. 
00222     int pad80=0;
00223     
00224     // Now, let's see if we need padding. 
00225     // We must check for >=56 as we always have to add one 0x80 padding. 
00226     // Padding does not count for the length, of course.
00227     length+=uint64(tmp_size);
00228     if(tmp_size>=56)  // We need to pad the tmpbuf with zeros and hash it. 
00229     {
00230         unsigned char *d=&tmpbuf[tmp_size];
00231         *(d++)=(unsigned char)0x80;   // append binary 10000000. 
00232         for(unsigned char *de=&tmpbuf[64]; d<de; d++)
00233         {  *d=(unsigned char)0;  }
00234         AtomicHash(tmpbuf,w);
00235         tmp_size=0;
00236         ++pad80;
00237     }
00238     
00239     // The length was counted in bytes, but we need the number of bits here: 
00240     uint64 len=length*8LLU;
00241     
00242     // Now, we have to fill up tmpbuf with zeros and add the length in bits 
00243     // as the last 8 bytes. 
00244     unsigned char *d=&tmpbuf[tmp_size];
00245     if(!pad80)
00246     {  *(d++)=(unsigned char)0x80;  }  // append binary 10000000. 
00247     for(unsigned char *de=&tmpbuf[56]; d<de; d++)
00248     {  *d=(unsigned char)0;  }
00249     
00250     // Add more significant word: 
00251     uint32 word = uint32(len >> 32);
00252     d+=3;
00253     *(d--)=(unsigned char)(word & 0xffU);  word>>=8;
00254     *(d--)=(unsigned char)(word & 0xffU);  word>>=8;
00255     *(d--)=(unsigned char)(word & 0xffU);  word>>=8;
00256     *(d  )=(unsigned char)(word & 0xffU);
00257     
00258     // Add less significant word: 
00259     word = uint32(len & 0xffffffffLLU);
00260     d+=7;
00261     *(d--)=(unsigned char)(word & 0xffU);  word>>=8;
00262     *(d--)=(unsigned char)(word & 0xffU);  word>>=8;
00263     *(d--)=(unsigned char)(word & 0xffU);  word>>=8;
00264     *(d  )=(unsigned char)(word & 0xffU);
00265     
00266     AtomicHash(tmpbuf,w);
00267     tmp_size=0;
00268 }

Generated on Sat Feb 19 22:33:45 2005 for Ray by doxygen 1.3.5