modules_k/xmpp/sha.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  * 
00018  *  Gabber
00019  *  Copyright (C) 1999-2000 Dave Smith & Julian Missig
00020  *
00021  */
00022 
00028 /* 
00029    Implements the Secure Hash Algorithm (SHA1)
00030 
00031    Copyright (C) 1999 Scott G. Miller
00032 
00033    Released under the terms of the GNU General Public License v2
00034    see file COPYING for details
00035 
00036    Credits: 
00037       Robert Klep <robert@ilse.nl>  -- Expansion function fix 
00038           Thomas "temas" Muldowney <temas@box5.net>:
00039                         -- shahash() for string fun
00040                         -- Will add the int32 stuff in a few
00041                         
00042    ---
00043    FIXME: This source takes int to be a 32 bit integer.  This
00044    may vary from system to system.  I'd use autoconf if I was familiar
00045    with it.  Anyone want to help me out?
00046 */
00047 
00048 //#include <config.h>
00049 
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <fcntl.h>
00053 #include <string.h>
00054 
00055 #ifndef MACOS
00056 #  include <sys/stat.h>
00057 #  include <sys/types.h>
00058 #endif
00059 #ifndef WIN32
00060 #  include <unistd.h>
00061 #  define INT64 long long
00062 #else
00063 #  define snprintf _snprintf
00064 #  define INT64 __int64
00065 #endif
00066 
00067 #define switch_endianness(x) (x<<24 & 0xff000000) | \
00068                              (x<<8  & 0x00ff0000) | \
00069                              (x>>8  & 0x0000ff00) | \
00070                              (x>>24 & 0x000000ff)
00071 
00072 /* Initial hash values */
00073 #define Ai 0x67452301 
00074 #define Bi 0xefcdab89
00075 #define Ci 0x98badcfe
00076 #define Di 0x10325476
00077 #define Ei 0xc3d2e1f0
00078 
00079 /* SHA1 round constants */
00080 #define K1 0x5a827999
00081 #define K2 0x6ed9eba1
00082 #define K3 0x8f1bbcdc 
00083 #define K4 0xca62c1d6
00084 
00085 /* Round functions.  Note that f2() is used in both rounds 2 and 4 */
00086 #define f1(B,C,D) ((B & C) | ((~B) & D))
00087 #define f2(B,C,D) (B ^ C ^ D)
00088 #define f3(B,C,D) ((B & C) | (B & D) | (C & D))
00089 
00090 /* left circular shift functions (rotate left) */
00091 #define rol1(x) ((x<<1) | ((x>>31) & 1))
00092 #define rol5(A) ((A<<5) | ((A>>27) & 0x1f))
00093 #define rol30(B) ((B<<30) | ((B>>2) & 0x3fffffff))
00094 
00095 /*
00096   Hashes 'data', which should be a pointer to 512 bits of data (sixteen
00097   32 bit ints), into the ongoing 160 bit hash value (five 32 bit ints)
00098   'hash'
00099 */
00100 int 
00101 sha_hash(int *data, int *hash)  
00102 {
00103   int W[80];
00104   unsigned int A=hash[0], B=hash[1], C=hash[2], D=hash[3], E=hash[4];
00105   unsigned int t, x, TEMP;
00106 
00107   for (t=0; t<16; t++) 
00108     {
00109 #ifndef WORDS_BIGENDIAN
00110       W[t]=switch_endianness(data[t]);
00111 #else 
00112       W[t]=data[t];
00113 #endif
00114     }
00115 
00116 
00117   /* SHA1 Data expansion */
00118   for (t=16; t<80; t++) 
00119     {
00120       x=W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
00121       W[t]=rol1(x);
00122     }
00123 
00124   /* SHA1 main loop (t=0 to 79) 
00125    This is broken down into four subloops in order to use
00126    the correct round function and constant */
00127   for (t=0; t<20; t++) 
00128     {
00129       TEMP=rol5(A) + f1(B,C,D) + E + W[t] + K1;
00130       E=D;
00131       D=C;
00132       C=rol30(B);
00133       B=A;
00134       A=TEMP;
00135     }
00136   for (; t<40; t++) 
00137     {
00138       TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K2;
00139       E=D;
00140       D=C;
00141       C=rol30(B);
00142       B=A;
00143       A=TEMP;
00144     }
00145   for (; t<60; t++) 
00146     {
00147       TEMP=rol5(A) + f3(B,C,D) + E + W[t] + K3;
00148       E=D;
00149       D=C;
00150       C=rol30(B);
00151       B=A;
00152       A=TEMP;
00153     }
00154   for (; t<80; t++) 
00155     {
00156       TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K4;
00157       E=D;
00158       D=C;
00159       C=rol30(B);
00160       B=A;
00161       A=TEMP;
00162     }
00163   hash[0]+=A; 
00164   hash[1]+=B;
00165   hash[2]+=C;
00166   hash[3]+=D;
00167   hash[4]+=E;
00168   return 0;
00169 }
00170 
00171 /*
00172   Takes a pointer to a 160 bit block of data (five 32 bit ints) and
00173   initializes it to the start constants of the SHA1 algorithm.  This
00174   must be called before using hash in the call to sha_hash
00175 */
00176 int 
00177 sha_init(int *hash) 
00178 {
00179   hash[0]=Ai;
00180   hash[1]=Bi;
00181   hash[2]=Ci;
00182   hash[3]=Di;
00183   hash[4]=Ei;
00184   return 0;
00185 }
00186 
00187 int strprintsha(char *dest, int *hashval) 
00188 {
00189         int x;
00190         char *hashstr = dest;
00191         for (x=0; x<5; x++) 
00192         {
00193                 snprintf(hashstr, 9, "%08x", hashval[x]);
00194                 hashstr+=8;
00195         }
00196         /*old way */
00197         //snprintf(hashstr++, 1, "\0");
00198         /*new way - by bogdan*/
00199         *hashstr = 0;
00200 
00201         return 0;
00202 }
00203 
00204 char *shahash(const char *str) 
00205 {
00206         char read_buffer[65];
00207         //int read_buffer[64];
00208         int c=1, i;
00209        
00210         INT64 length=0;
00211 
00212         int strsz;
00213         static char final[40];
00214         int *hashval;
00215 
00216         hashval = (int *)malloc(20);
00217 
00218         sha_init(hashval);
00219 
00220         strsz = strlen(str);
00221 
00222         if(strsz == 0) 
00223         {
00224              memset(read_buffer, 0, 65);
00225              read_buffer[0] = 0x80;
00226              sha_hash((int *)read_buffer, hashval);
00227         }
00228 
00229         while (strsz>0) 
00230         {
00231                 memset(read_buffer, 0, 65);
00232                 strncpy((char*)read_buffer, str, 64);
00233                 c = strlen((char *)read_buffer);
00234                 length+=c;
00235                 strsz-=c;
00236                 if (strsz<=0) 
00237                 {
00238                         length<<=3;     
00239                         read_buffer[c]=(char)0x80;
00240                         for (i=c+1; i<64; i++) 
00241                                 read_buffer[i]=0;
00242                         if (c>55) 
00243                         {
00244                                 /* we need to do an entire new block */
00245                                 sha_hash((int *)read_buffer, hashval);
00246                                 for (i=0; i<14; i++) 
00247                                         ((int*)read_buffer)[i]=0;
00248                         }      
00249 #ifndef WORDS_BIGENDIAN
00250                         for (i=0; i<8; i++) 
00251                         {
00252                                 read_buffer[56+i]=(char)(length>>(56-(i*8))) & 0xff;
00253                         }
00254 #else   
00255                         memcpy(read_buffer+56, &length, 8);
00256 #endif
00257                 }
00258                 
00259                 sha_hash((int *)read_buffer, hashval);
00260                 str+=64;
00261         }
00262 
00263         strprintsha((char *)final, hashval);
00264         free(hashval);
00265         return (char *)final;
00266 }