updated mailing address of the FSF
[OpenSRF.git] / src / libopensrf / sha.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or
5  *  (at your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *  GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
15  * 
16  *  Gabber
17  *  Copyright (C) 1999-2000 Dave Smith & Julian Missig
18  */
19
20
21 /* 
22    Implements the Secure Hash Algorithm (SHA1)
23
24    Copyright (C) 1999 Scott G. Miller
25
26    Released under the terms of the GNU General Public License v2
27    see file COPYING for details
28
29    Credits: 
30       Robert Klep <robert@ilse.nl>  -- Expansion function fix 
31           Thomas "temas" Muldowney <temas@box5.net>:
32                         -- shahash() for string fun
33                         -- Will add the int32 stuff in a few
34                         
35    ---
36    FIXME: This source takes int to be a 32 bit integer.  This
37    may vary from system to system.  I'd use autoconf if I was familiar
38    with it.  Anyone want to help me out?
39 */
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <fcntl.h>
48 #ifdef MACOS
49 #  include <string.h>
50 #else
51 #  include <sys/stat.h>
52 #  include <sys/types.h>
53 #endif
54
55 #include <string.h>
56
57 #ifndef WIN32
58 #  include <unistd.h>
59 #  define INT64 long long
60 #else
61 #  include <string.h>
62 #  define snprintf _snprintf
63 #  define INT64 __int64
64 #endif
65
66 #define switch_endianness(x) (x<<24 & 0xff000000) | \
67                              (x<<8  & 0x00ff0000) | \
68                              (x>>8  & 0x0000ff00) | \
69                              (x>>24 & 0x000000ff)
70
71 /* Initial hash values */
72 #define Ai 0x67452301 
73 #define Bi 0xefcdab89
74 #define Ci 0x98badcfe
75 #define Di 0x10325476
76 #define Ei 0xc3d2e1f0
77
78 /* SHA1 round constants */
79 #define K1 0x5a827999
80 #define K2 0x6ed9eba1
81 #define K3 0x8f1bbcdc 
82 #define K4 0xca62c1d6
83
84 /* Round functions.  Note that f2() is used in both rounds 2 and 4 */
85 #define f1(B,C,D) ((B & C) | ((~B) & D))
86 #define f2(B,C,D) (B ^ C ^ D)
87 #define f3(B,C,D) ((B & C) | (B & D) | (C & D))
88
89 /* left circular shift functions (rotate left) */
90 #define rol1(x) ((x<<1) | ((x>>31) & 1))
91 #define rol5(A) ((A<<5) | ((A>>27) & 0x1f))
92 #define rol30(B) ((B<<30) | ((B>>2) & 0x3fffffff))
93
94 /*
95   Hashes 'data', which should be a pointer to 512 bits of data (sixteen
96   32 bit ints), into the ongoing 160 bit hash value (five 32 bit ints)
97   'hash'
98 */
99 int 
100 sha_hash(int *data, int *hash)  
101 {
102   int W[80];
103   unsigned int A=hash[0], B=hash[1], C=hash[2], D=hash[3], E=hash[4];
104   unsigned int t, x, TEMP;
105
106   for (t=0; t<16; t++) 
107     {
108 #ifndef WORDS_BIGENDIAN
109       W[t]=switch_endianness(data[t]);
110 #else 
111       W[t]=data[t];
112 #endif
113     }
114
115
116   /* SHA1 Data expansion */
117   for (t=16; t<80; t++) 
118     {
119       x=W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
120       W[t]=rol1(x);
121     }
122
123   /* SHA1 main loop (t=0 to 79) 
124    This is broken down into four subloops in order to use
125    the correct round function and constant */
126   for (t=0; t<20; t++) 
127     {
128       TEMP=rol5(A) + f1(B,C,D) + E + W[t] + K1;
129       E=D;
130       D=C;
131       C=rol30(B);
132       B=A;
133       A=TEMP;
134     }
135   for (; t<40; t++) 
136     {
137       TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K2;
138       E=D;
139       D=C;
140       C=rol30(B);
141       B=A;
142       A=TEMP;
143     }
144   for (; t<60; t++) 
145     {
146       TEMP=rol5(A) + f3(B,C,D) + E + W[t] + K3;
147       E=D;
148       D=C;
149       C=rol30(B);
150       B=A;
151       A=TEMP;
152     }
153   for (; t<80; t++) 
154     {
155       TEMP=rol5(A) + f2(B,C,D) + E + W[t] + K4;
156       E=D;
157       D=C;
158       C=rol30(B);
159       B=A;
160       A=TEMP;
161     }
162   hash[0]+=A; 
163   hash[1]+=B;
164   hash[2]+=C;
165   hash[3]+=D;
166   hash[4]+=E;
167   return 0;
168 }
169
170 /*
171   Takes a pointer to a 160 bit block of data (five 32 bit ints) and
172   intializes it to the start constants of the SHA1 algorithm.  This
173   must be called before using hash in the call to sha_hash
174 */
175 int 
176 sha_init(int *hash) 
177 {
178   hash[0]=Ai;
179   hash[1]=Bi;
180   hash[2]=Ci;
181   hash[3]=Di;
182   hash[4]=Ei;
183   return 0;
184 }
185
186 int strprintsha(char *dest, int *hashval) 
187 {
188         int x;
189         char *hashstr = dest;
190         for (x=0; x<5; x++) 
191         {
192                 snprintf(hashstr, 9, "%08x", hashval[x]);
193                 hashstr+=8;
194         }
195         //snprintf(hashstr++, 1, "\0");
196         hashstr[0] = '\0';
197         hashstr++;
198
199         return 0;
200 }
201
202 char *shahash(const char *str) 
203 {
204         char read_buffer[65];
205         //int read_buffer[64];
206         int c=1, i;
207        
208         INT64 length=0;
209
210         int strsz;
211         static char final[41];
212         int *hashval;
213
214         hashval = (int *)malloc(20);
215
216         sha_init(hashval);
217
218         strsz = strlen(str);
219
220         if(strsz == 0) 
221         {
222              memset(read_buffer, 0, 65);
223              read_buffer[0] = 0x80;
224              sha_hash((int *)read_buffer, hashval);
225         }
226
227         while (strsz>0) 
228         {
229                 memset(read_buffer, 0, 65);
230                 strncpy((char*)read_buffer, str, 64);
231                 c = strlen((char *)read_buffer);
232                 length+=c;
233                 strsz-=c;
234                 if (strsz<=0) 
235                 {
236                         length<<=3;     
237                         read_buffer[c]=(char)0x80;
238                         for (i=c+1; i<64; i++) 
239                                 read_buffer[i]=0;
240                         if (c>55) 
241                         {
242                                 /* we need to do an entire new block */
243                                 sha_hash((int *)read_buffer, hashval);
244                                 for (i=0; i<14; i++) 
245                                         ((int*)read_buffer)[i]=0;
246                         }      
247 #ifndef WORDS_BIGENDIAN
248                         for (i=0; i<8; i++) 
249                         {
250                                 read_buffer[56+i]=(char)(length>>(56-(i*8))) & 0xff;
251                         }
252 #else   
253                         memcpy(read_buffer+56, &length, 8);
254 #endif
255                 }
256                 
257                 sha_hash((int *)read_buffer, hashval);
258                 str+=64;
259         }
260
261         strprintsha((char *)final, hashval);
262         free(hashval);
263         return (char *)final;
264 }