embedded IPsec source code documentation


md5.c

Go to the documentation of this file.
00001 /*
00002  * embedded IPsec       
00003  * Copyright (c) 2003 Niklaus Schild and Christian Scheurer, HTI Biel/Bienne
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without modification,
00007  * are permitted provided that the following conditions are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright notice,
00010  *    this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright notice,
00012  *    this list of conditions and the following disclaimer in the documentation
00013  *    and/or other materials provided with the distribution.
00014  * 3. The name of the author may not be used to endorse or promote products
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00018  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00020  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00021  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00022  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00025  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00026  * OF SUCH DAMAGE.
00027  *
00028  */
00029 
00055 #include <string.h>
00056 
00057 #include "ipsec/md5.h"
00058 #include "ipsec/debug.h"
00059 
00060 unsigned char *MD5(const unsigned char *d, unsigned long n, unsigned char *md)
00061 {
00062         MD5_CTX c;
00063         static unsigned char m[MD5_DIGEST_LENGTH];
00064 
00065         if (md == NULL) md=m;
00066         MD5_Init(&c);
00067         MD5_Update(&c,d,n);
00068         MD5_Final(md,&c);
00069         memset(&c,0,sizeof(c)); /* security consideration */
00070         return(md);
00071 }
00072 
00073 
00074 #define INIT_DATA_A (unsigned long)0x67452301L
00075 #define INIT_DATA_B (unsigned long)0xefcdab89L
00076 #define INIT_DATA_C (unsigned long)0x98badcfeL
00077 #define INIT_DATA_D (unsigned long)0x10325476L
00078 
00079 void MD5_Init(MD5_CTX *c)
00080 {
00081         c->A=INIT_DATA_A;
00082         c->B=INIT_DATA_B;
00083         c->C=INIT_DATA_C;
00084         c->D=INIT_DATA_D;
00085         c->Nl=0;
00086         c->Nh=0;
00087         c->num=0;
00088 }
00089 
00090 
00091 void md5_block_host_order (MD5_CTX *c, const void *p,int num);
00092 void md5_block_data_order (MD5_CTX *c, const void *p,int num);
00093 
00094 /*
00095  * Engage compiler specific rotate intrinsic function if available.
00096  */
00097 
00098 #undef ROTATE
00099 
00100 // *** Keil C166 ***
00101 #ifdef __C166__
00102 #include <intrins.h>
00103 #define ROTATE(a,n)     _lrol_(a,n)
00104 #endif
00105 
00106 
00107 #ifdef ROTATE
00108 /* 5 instructions with rotate instruction, else 9 */
00109 #define REVERSE_FETCH32(a,l)    (                                       \
00110                 l=*(const MD5_LONG *)(a),                               \
00111                 ((ROTATE(l,8)&0x00FF00FF)|(ROTATE((l&0x00FF00FF),24)))  \
00112                                 )
00113 #endif
00114                                         
00115 
00116 #define HOST_c2l(c,l)   (l =(((unsigned long)(*((c)++)))    ),          \
00117                          l|=(((unsigned long)(*((c)++)))<< 8),          \
00118                          l|=(((unsigned long)(*((c)++)))<<16),          \
00119                          l|=(((unsigned long)(*((c)++)))<<24),          \
00120                          l)
00121 #define HOST_p_c2l(c,l,n)       {                                       \
00122                         switch (n) {                                    \
00123                         case 0: l =((unsigned long)(*((c)++)));         \
00124                         case 1: l|=((unsigned long)(*((c)++)))<< 8;     \
00125                         case 2: l|=((unsigned long)(*((c)++)))<<16;     \
00126                         case 3: l|=((unsigned long)(*((c)++)))<<24;     \
00127                                 } }
00128 #define HOST_p_c2l_p(c,l,sc,len) {                                      \
00129                         switch (sc) {                                   \
00130                         case 0: l =((unsigned long)(*((c)++)));         \
00131                                 if (--len == 0) break;                  \
00132                         case 1: l|=((unsigned long)(*((c)++)))<< 8;     \
00133                                 if (--len == 0) break;                  \
00134                         case 2: l|=((unsigned long)(*((c)++)))<<16;     \
00135                                 } }
00136 /* NOTE the pointer is not incremented at the end of this */
00137 #define HOST_c2l_p(c,l,n)       {                                       \
00138                         l=0; (c)+=n;                                    \
00139                         switch (n) {                                    \
00140                         case 3: l =((unsigned long)(*(--(c))))<<16;     \
00141                         case 2: l|=((unsigned long)(*(--(c))))<< 8;     \
00142                         case 1: l|=((unsigned long)(*(--(c))));         \
00143                                 } }
00144 #define HOST_l2c(l,c)   (*((c)++)=(unsigned char)(((l)    )&0xff),      \
00145                          *((c)++)=(unsigned char)(((l)>> 8)&0xff),      \
00146                          *((c)++)=(unsigned char)(((l)>>16)&0xff),      \
00147                          *((c)++)=(unsigned char)(((l)>>24)&0xff),      \
00148                          l)
00149 
00150 
00151 /*
00152  * Time for some action:-)
00153  */
00154 
00155 void MD5_Update (MD5_CTX *c, const void *data_, unsigned long len)
00156 {
00157         const unsigned char *data=data_;
00158         MD5_LONG * p;
00159         unsigned long l;
00160         int sw,sc,ew,ec;
00161 
00162         if (len==0) return;
00163 
00164         l=(c->Nl+(len<<3))&0xffffffffL;
00165         /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
00166          * Wei Dai <weidai@eskimo.com> for pointing it out. */
00167         if (l < c->Nl) /* overflow */
00168                 c->Nh++;
00169         c->Nh+=(len>>29);
00170         c->Nl=l;
00171 
00172         if (c->num != 0)
00173                 {
00174                 p=c->data;
00175                 sw=c->num>>2;
00176                 sc=c->num&0x03;
00177 
00178                 if ((c->num+len) >= MD5_CBLOCK)
00179                         {
00180                         l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
00181                         for (; sw<MD5_LBLOCK; sw++)
00182                                 {
00183                                 HOST_c2l(data,l); p[sw]=l;
00184                                 }
00185                         md5_block_host_order (c,p,1);
00186                         len-=(MD5_CBLOCK-c->num);
00187                         c->num=0;
00188                         /* drop through and do the rest */
00189                         }
00190                 else
00191                         {
00192                         c->num+=len;
00193                         if ((sc+len) < 4) /* ugly, add char's to a word */
00194                                 {
00195                                 l=p[sw]; HOST_p_c2l_p(data,l,sc,len); p[sw]=l;
00196                                 }
00197                         else
00198                                 {
00199                                 ew=(c->num>>2);
00200                                 ec=(c->num&0x03);
00201                                 l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
00202                                 for (; sw < ew; sw++)
00203                                         {
00204                                         HOST_c2l(data,l); p[sw]=l;
00205                                         }
00206                                 if (ec)
00207                                         {
00208                                         HOST_c2l_p(data,l,ec); p[sw]=l;
00209                                         }
00210                                 }
00211                         return;
00212                         }
00213                 }
00214 
00215         sw=(int) (len/MD5_CBLOCK);
00216         if (sw > 0)
00217                 {
00218                 if ((((unsigned long)data)%4) == 0)
00219                         {
00220                         /* data is properly aligned so that we can cast it: */
00221                         md5_block_host_order (c,(MD5_LONG *)data,sw);
00222                         sw*=MD5_CBLOCK;
00223                         data+=sw;
00224                         len-=sw;
00225                         }
00226                 else
00227                         {
00228                         md5_block_data_order(c,data,sw);
00229                         sw*=MD5_CBLOCK;
00230                         data+=sw;
00231                         len-=sw;
00232                         }
00233                 }
00234 
00235         if (len!=0)
00236                 {
00237                 p = c->data;
00238                 c->num = (int) len;
00239                 ew=(int) (len>>2);      /* words to copy */
00240                 ec=(int) (len&0x03);
00241                 for (; ew; ew--,p++)
00242                         {
00243                         HOST_c2l(data,l); *p=l;
00244                         }
00245                 HOST_c2l_p(data,l,ec);
00246                 *p=l;
00247                 }
00248 }
00249 
00250 
00251 void MD5_Transform (MD5_CTX *c, const unsigned char *data)
00252 {
00253         if ((((unsigned long)data)%4) == 0)
00254                 /* data is properly aligned so that we can cast it: */
00255                 md5_block_host_order (c,(MD5_LONG *)data,1);
00256         else
00257         md5_block_data_order (c,data,1);
00258 }
00259 
00260 
00261 void MD5_Final (unsigned char *md, MD5_CTX *c)
00262 {
00263         MD5_LONG *p;
00264         unsigned long l;
00265         int i,j;
00266         static const unsigned char end[4]={0x80,0x00,0x00,0x00};
00267         const unsigned char *cp=end;
00268 
00269         /* c->num should definitly have room for at least one more byte. */
00270         p=c->data;
00271         i=c->num>>2;
00272         j=c->num&0x03;
00273 
00274         l = (j==0) ? 0 : p[i];
00275 
00276         HOST_p_c2l(cp,l,j); p[i++]=l; /* i is the next 'undefined word' */
00277 
00278         if (i>(MD5_LBLOCK-2)) /* save room for Nl and Nh */
00279                 {
00280                 if (i<MD5_LBLOCK) p[i]=0;
00281                 md5_block_host_order (c,p,1);
00282                 i=0;
00283                 }
00284         for (; i<(MD5_LBLOCK-2); i++)
00285                 p[i]=0;
00286 
00287         p[MD5_LBLOCK-2]=c->Nl;
00288         p[MD5_LBLOCK-1]=c->Nh;
00289         md5_block_host_order (c,p,1);
00290 
00291 
00292         // HASH_MAKE_STRING(c,md);
00293         do {    
00294         unsigned long ll;               
00295         ll=(c)->A; HOST_l2c(ll,(md));   
00296         ll=(c)->B; HOST_l2c(ll,(md));   
00297         ll=(c)->C; HOST_l2c(ll,(md));   
00298         ll=(c)->D; HOST_l2c(ll,(md));   
00299         } while (0);
00300 
00301 
00302         c->num=0;
00303         /* clear stuff, HASH_BLOCK may be leaving some stuff on the stack
00304          * but I'm not worried :-)
00305         memset((void *)c,0,sizeof(MD5_CTX));
00306          */
00307 }
00308 
00309 
00310 #define F(b,c,d)        ((((c) ^ (d)) & (b)) ^ (d))
00311 #define G(b,c,d)        ((((b) ^ (c)) & (d)) ^ (c))
00312 #define H(b,c,d)        ((b) ^ (c) ^ (d))
00313 #define I(b,c,d)        (((~(d)) | (b)) ^ (c))
00314 
00315 #define R0(a,b,c,d,k,s,t) { \
00316         a+=((k)+(t)+F((b),(c),(d))); \
00317         a=ROTATE(a,s); \
00318         a+=b; };\
00319 
00320 #define R1(a,b,c,d,k,s,t) { \
00321         a+=((k)+(t)+G((b),(c),(d))); \
00322         a=ROTATE(a,s); \
00323         a+=b; };
00324 
00325 #define R2(a,b,c,d,k,s,t) { \
00326         a+=((k)+(t)+H((b),(c),(d))); \
00327         a=ROTATE(a,s); \
00328         a+=b; };
00329 
00330 #define R3(a,b,c,d,k,s,t) { \
00331         a+=((k)+(t)+I((b),(c),(d))); \
00332         a=ROTATE(a,s); \
00333         a+=b; };
00334 
00335 
00336 
00337 void md5_block_host_order (MD5_CTX *c, const void *data, int num)
00338 {
00339         const MD5_LONG *X=data;
00340         unsigned long A,B,C,D;
00341         /*
00342          * In case you wonder why A-D are declared as long and not
00343          * as MD5_LONG. Doing so results in slight performance
00344          * boost on LP64 architectures. The catch is we don't
00345          * really care if 32 MSBs of a 64-bit register get polluted
00346          * with eventual overflows as we *save* only 32 LSBs in
00347          * *either* case. Now declaring 'em long excuses the compiler
00348          * from keeping 32 MSBs zeroed resulting in 13% performance
00349          * improvement under SPARC Solaris7/64 and 5% under AlphaLinux.
00350          * Well, to be honest it should say that this *prevents* 
00351          * performance degradation.
00352          *
00353          *                              <appro@fy.chalmers.se>
00354          */
00355 
00356         A=c->A;
00357         B=c->B;
00358         C=c->C;
00359         D=c->D;
00360 
00361         for (;num--;X+=MD5_LBLOCK)
00362                 {
00363         /* Round 0 */
00364         R0(A,B,C,D,X[ 0], 7,0xd76aa478L);
00365         R0(D,A,B,C,X[ 1],12,0xe8c7b756L);
00366         R0(C,D,A,B,X[ 2],17,0x242070dbL);
00367         R0(B,C,D,A,X[ 3],22,0xc1bdceeeL);
00368         R0(A,B,C,D,X[ 4], 7,0xf57c0fafL);
00369         R0(D,A,B,C,X[ 5],12,0x4787c62aL);
00370         R0(C,D,A,B,X[ 6],17,0xa8304613L);
00371         R0(B,C,D,A,X[ 7],22,0xfd469501L);
00372         R0(A,B,C,D,X[ 8], 7,0x698098d8L);
00373         R0(D,A,B,C,X[ 9],12,0x8b44f7afL);
00374         R0(C,D,A,B,X[10],17,0xffff5bb1L);
00375         R0(B,C,D,A,X[11],22,0x895cd7beL);
00376         R0(A,B,C,D,X[12], 7,0x6b901122L);
00377         R0(D,A,B,C,X[13],12,0xfd987193L);
00378         R0(C,D,A,B,X[14],17,0xa679438eL);
00379         R0(B,C,D,A,X[15],22,0x49b40821L);
00380         /* Round 1 */
00381         R1(A,B,C,D,X[ 1], 5,0xf61e2562L);
00382         R1(D,A,B,C,X[ 6], 9,0xc040b340L);
00383         R1(C,D,A,B,X[11],14,0x265e5a51L);
00384         R1(B,C,D,A,X[ 0],20,0xe9b6c7aaL);
00385         R1(A,B,C,D,X[ 5], 5,0xd62f105dL);
00386         R1(D,A,B,C,X[10], 9,0x02441453L);
00387         R1(C,D,A,B,X[15],14,0xd8a1e681L);
00388         R1(B,C,D,A,X[ 4],20,0xe7d3fbc8L);
00389         R1(A,B,C,D,X[ 9], 5,0x21e1cde6L);
00390         R1(D,A,B,C,X[14], 9,0xc33707d6L);
00391         R1(C,D,A,B,X[ 3],14,0xf4d50d87L);
00392         R1(B,C,D,A,X[ 8],20,0x455a14edL);
00393         R1(A,B,C,D,X[13], 5,0xa9e3e905L);
00394         R1(D,A,B,C,X[ 2], 9,0xfcefa3f8L);
00395         R1(C,D,A,B,X[ 7],14,0x676f02d9L);
00396         R1(B,C,D,A,X[12],20,0x8d2a4c8aL);
00397         /* Round 2 */
00398         R2(A,B,C,D,X[ 5], 4,0xfffa3942L);
00399         R2(D,A,B,C,X[ 8],11,0x8771f681L);
00400         R2(C,D,A,B,X[11],16,0x6d9d6122L);
00401         R2(B,C,D,A,X[14],23,0xfde5380cL);
00402         R2(A,B,C,D,X[ 1], 4,0xa4beea44L);
00403         R2(D,A,B,C,X[ 4],11,0x4bdecfa9L);
00404         R2(C,D,A,B,X[ 7],16,0xf6bb4b60L);
00405         R2(B,C,D,A,X[10],23,0xbebfbc70L);
00406         R2(A,B,C,D,X[13], 4,0x289b7ec6L);
00407         R2(D,A,B,C,X[ 0],11,0xeaa127faL);
00408         R2(C,D,A,B,X[ 3],16,0xd4ef3085L);
00409         R2(B,C,D,A,X[ 6],23,0x04881d05L);
00410         R2(A,B,C,D,X[ 9], 4,0xd9d4d039L);
00411         R2(D,A,B,C,X[12],11,0xe6db99e5L);
00412         R2(C,D,A,B,X[15],16,0x1fa27cf8L);
00413         R2(B,C,D,A,X[ 2],23,0xc4ac5665L);
00414         /* Round 3 */
00415         R3(A,B,C,D,X[ 0], 6,0xf4292244L);
00416         R3(D,A,B,C,X[ 7],10,0x432aff97L);
00417         R3(C,D,A,B,X[14],15,0xab9423a7L);
00418         R3(B,C,D,A,X[ 5],21,0xfc93a039L);
00419         R3(A,B,C,D,X[12], 6,0x655b59c3L);
00420         R3(D,A,B,C,X[ 3],10,0x8f0ccc92L);
00421         R3(C,D,A,B,X[10],15,0xffeff47dL);
00422         R3(B,C,D,A,X[ 1],21,0x85845dd1L);
00423         R3(A,B,C,D,X[ 8], 6,0x6fa87e4fL);
00424         R3(D,A,B,C,X[15],10,0xfe2ce6e0L);
00425         R3(C,D,A,B,X[ 6],15,0xa3014314L);
00426         R3(B,C,D,A,X[13],21,0x4e0811a1L);
00427         R3(A,B,C,D,X[ 4], 6,0xf7537e82L);
00428         R3(D,A,B,C,X[11],10,0xbd3af235L);
00429         R3(C,D,A,B,X[ 2],15,0x2ad7d2bbL);
00430         R3(B,C,D,A,X[ 9],21,0xeb86d391L);
00431 
00432         A = c->A += A;
00433         B = c->B += B;
00434         C = c->C += C;
00435         D = c->D += D;
00436                 }
00437 }
00438 
00439 
00440 void md5_block_data_order (MD5_CTX *c, const void *data_, int num)
00441 {
00442         const unsigned char *data=data_;
00443         unsigned long A,B,C,D,l;
00444         /*
00445          * In case you wonder why A-D are declared as long and not
00446          * as MD5_LONG. Doing so results in slight performance
00447          * boost on LP64 architectures. The catch is we don't
00448          * really care if 32 MSBs of a 64-bit register get polluted
00449          * with eventual overflows as we *save* only 32 LSBs in
00450          * *either* case. Now declaring 'em long excuses the compiler
00451          * from keeping 32 MSBs zeroed resulting in 13% performance
00452          * improvement under SPARC Solaris7/64 and 5% under AlphaLinux.
00453          * Well, to be honest it should say that this *prevents* 
00454          * performance degradation.
00455          *
00456          *                              <appro@fy.chalmers.se>
00457          */
00458         unsigned long   XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7,
00459                         XX8, XX9,XX10,XX11,XX12,XX13,XX14,XX15;
00460 #define X(i)    XX##i
00461 
00462         A=c->A;
00463         B=c->B;
00464         C=c->C;
00465         D=c->D;
00466 
00467         for (;num--;)
00468                 {
00469         HOST_c2l(data,l); X( 0)=l;              HOST_c2l(data,l); X( 1)=l;
00470         /* Round 0 */
00471         R0(A,B,C,D,X( 0), 7,0xd76aa478L);       HOST_c2l(data,l); X( 2)=l;
00472         R0(D,A,B,C,X( 1),12,0xe8c7b756L);       HOST_c2l(data,l); X( 3)=l;
00473         R0(C,D,A,B,X( 2),17,0x242070dbL);       HOST_c2l(data,l); X( 4)=l;
00474         R0(B,C,D,A,X( 3),22,0xc1bdceeeL);       HOST_c2l(data,l); X( 5)=l;
00475         R0(A,B,C,D,X( 4), 7,0xf57c0fafL);       HOST_c2l(data,l); X( 6)=l;
00476         R0(D,A,B,C,X( 5),12,0x4787c62aL);       HOST_c2l(data,l); X( 7)=l;
00477         R0(C,D,A,B,X( 6),17,0xa8304613L);       HOST_c2l(data,l); X( 8)=l;
00478         R0(B,C,D,A,X( 7),22,0xfd469501L);       HOST_c2l(data,l); X( 9)=l;
00479         R0(A,B,C,D,X( 8), 7,0x698098d8L);       HOST_c2l(data,l); X(10)=l;
00480         R0(D,A,B,C,X( 9),12,0x8b44f7afL);       HOST_c2l(data,l); X(11)=l;
00481         R0(C,D,A,B,X(10),17,0xffff5bb1L);       HOST_c2l(data,l); X(12)=l;
00482         R0(B,C,D,A,X(11),22,0x895cd7beL);       HOST_c2l(data,l); X(13)=l;
00483         R0(A,B,C,D,X(12), 7,0x6b901122L);       HOST_c2l(data,l); X(14)=l;
00484         R0(D,A,B,C,X(13),12,0xfd987193L);       HOST_c2l(data,l); X(15)=l;
00485         R0(C,D,A,B,X(14),17,0xa679438eL);
00486         R0(B,C,D,A,X(15),22,0x49b40821L);
00487         /* Round 1 */
00488         R1(A,B,C,D,X( 1), 5,0xf61e2562L);
00489         R1(D,A,B,C,X( 6), 9,0xc040b340L);
00490         R1(C,D,A,B,X(11),14,0x265e5a51L);
00491         R1(B,C,D,A,X( 0),20,0xe9b6c7aaL);
00492         R1(A,B,C,D,X( 5), 5,0xd62f105dL);
00493         R1(D,A,B,C,X(10), 9,0x02441453L);
00494         R1(C,D,A,B,X(15),14,0xd8a1e681L);
00495         R1(B,C,D,A,X( 4),20,0xe7d3fbc8L);
00496         R1(A,B,C,D,X( 9), 5,0x21e1cde6L);
00497         R1(D,A,B,C,X(14), 9,0xc33707d6L);
00498         R1(C,D,A,B,X( 3),14,0xf4d50d87L);
00499         R1(B,C,D,A,X( 8),20,0x455a14edL);
00500         R1(A,B,C,D,X(13), 5,0xa9e3e905L);
00501         R1(D,A,B,C,X( 2), 9,0xfcefa3f8L);
00502         R1(C,D,A,B,X( 7),14,0x676f02d9L);
00503         R1(B,C,D,A,X(12),20,0x8d2a4c8aL);
00504         /* Round 2 */
00505         R2(A,B,C,D,X( 5), 4,0xfffa3942L);
00506         R2(D,A,B,C,X( 8),11,0x8771f681L);
00507         R2(C,D,A,B,X(11),16,0x6d9d6122L);
00508         R2(B,C,D,A,X(14),23,0xfde5380cL);
00509         R2(A,B,C,D,X( 1), 4,0xa4beea44L);
00510         R2(D,A,B,C,X( 4),11,0x4bdecfa9L);
00511         R2(C,D,A,B,X( 7),16,0xf6bb4b60L);
00512         R2(B,C,D,A,X(10),23,0xbebfbc70L);
00513         R2(A,B,C,D,X(13), 4,0x289b7ec6L);
00514         R2(D,A,B,C,X( 0),11,0xeaa127faL);
00515         R2(C,D,A,B,X( 3),16,0xd4ef3085L);
00516         R2(B,C,D,A,X( 6),23,0x04881d05L);
00517         R2(A,B,C,D,X( 9), 4,0xd9d4d039L);
00518         R2(D,A,B,C,X(12),11,0xe6db99e5L);
00519         R2(C,D,A,B,X(15),16,0x1fa27cf8L);
00520         R2(B,C,D,A,X( 2),23,0xc4ac5665L);
00521         /* Round 3 */
00522         R3(A,B,C,D,X( 0), 6,0xf4292244L);
00523         R3(D,A,B,C,X( 7),10,0x432aff97L);
00524         R3(C,D,A,B,X(14),15,0xab9423a7L);
00525         R3(B,C,D,A,X( 5),21,0xfc93a039L);
00526         R3(A,B,C,D,X(12), 6,0x655b59c3L);
00527         R3(D,A,B,C,X( 3),10,0x8f0ccc92L);
00528         R3(C,D,A,B,X(10),15,0xffeff47dL);
00529         R3(B,C,D,A,X( 1),21,0x85845dd1L);
00530         R3(A,B,C,D,X( 8), 6,0x6fa87e4fL);
00531         R3(D,A,B,C,X(15),10,0xfe2ce6e0L);
00532         R3(C,D,A,B,X( 6),15,0xa3014314L);
00533         R3(B,C,D,A,X(13),21,0x4e0811a1L);
00534         R3(A,B,C,D,X( 4), 6,0xf7537e82L);
00535         R3(D,A,B,C,X(11),10,0xbd3af235L);
00536         R3(C,D,A,B,X( 2),15,0x2ad7d2bbL);
00537         R3(B,C,D,A,X( 9),21,0xeb86d391L);
00538 
00539         A = c->A += A;
00540         B = c->B += B;
00541         C = c->C += C;
00542         D = c->D += D;
00543                 }
00544 }
00545 
00546 
00547 
00559 void hmac_md5(unsigned char* text, int text_len, unsigned char*  key, int key_len, unsigned char*  digest)
00560 {
00561     MD5_CTX context;
00562     unsigned char k_ipad[65];    /* inner padding - key XORd with ipad */
00563     unsigned char k_opad[65];    /* outer padding - key XORd with opad */
00564     unsigned char tk[16];                /* L=16 for MD5 (RFC 2141, 2. Definition of HMAC) */
00565     int i;
00566 
00567         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00568                       "hmac_md5", 
00569                                   ("text=%p, text_len=%d, key=%p, key_len=%d, digest=%p",
00570                               (void *)text, text_len, (void *)key, key_len, (void *)digest)
00571                                  );
00572 
00573 
00574     /* if key is longer than 64 bytes reset it to key=MD5(key) */
00575     if (key_len > 64) {
00576 
00577             MD5_CTX      tctx;
00578 
00579             MD5_Init(&tctx);
00580             MD5_Update(&tctx, key, key_len);
00581             MD5_Final(tk, &tctx);
00582 
00583             key = tk;
00584             key_len = 16;
00585     }
00586 
00587     /*
00588      * the HMAC_MD5 transform looks like:
00589      *
00590      * MD5(K XOR opad, MD5(K XOR ipad, text))
00591      *
00592      * where K is an n byte key
00593      * ipad is the byte 0x36 repeated 64 times
00594      * opad is the byte 0x5c repeated 64 times
00595      * and text is the data being protected
00596      */
00597 
00598     /* start out by storing key in pads */
00599     memset(k_ipad, '\0', sizeof(k_ipad));
00600     memset(k_opad, '\0', sizeof(k_opad));
00601     memcpy(k_ipad, key, key_len);
00602     memcpy(k_opad, key, key_len);
00603 
00604 
00605     /* XOR key with ipad and opad values */
00606     for (i=0; i<64; i++) {
00607             k_ipad[i] ^= 0x36;
00608             k_opad[i] ^= 0x5c;
00609     }
00610     /*
00611      * perform inner MD5
00612      */
00613     MD5_Init(&context);                  /* init context for 1st
00614                                           * pass */
00615     MD5_Update(&context, k_ipad, 64);    /* start with inner pad */
00616     MD5_Update(&context, text, text_len);/* then text of datagram */
00617     MD5_Final(digest, &context);         /* finish up 1st pass */
00618     /*
00619      * perform outer MD5
00620      */
00621     MD5_Init(&context);                  /* init context for 2nd
00622                                           * pass */
00623     MD5_Update(&context, k_opad, 64);    /* start with outer pad */
00624     MD5_Update(&context, digest, 16);    /* then results of 1st
00625                                           * hash */
00626     MD5_Final(digest, &context);         /* finish up 2nd pass */
00627 
00628         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "hmac_md5", ("void") );
00629 }
00630 

Copyright 2003 by Christian Scheurer and Niklaus Schild