]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libtransport/sha.c
sha.* is necessary for the component authentication, component is just an
[OpenSRF.git] / src / libtransport / 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
197         return 0;
198 }
199
200 char *shahash(const char *str) 
201 {
202         char read_buffer[65];
203         //int read_buffer[64];
204         int c=1, i;
205        
206         INT64 length=0;
207
208         int strsz;
209         static char final[40];
210         int *hashval;
211
212         hashval = (int *)malloc(20);
213
214         sha_init(hashval);
215
216         strsz = strlen(str);
217
218         if(strsz == 0) 
219         {
220              memset(read_buffer, 0, 65);
221              read_buffer[0] = 0x80;
222              sha_hash((int *)read_buffer, hashval);
223         }
224
225         while (strsz>0) 
226         {
227                 memset(read_buffer, 0, 65);
228                 strncpy((char*)read_buffer, str, 64);
229                 c = strlen((char *)read_buffer);
230                 length+=c;
231                 strsz-=c;
232                 if (strsz<=0) 
233                 {
234                         length<<=3;     
235                         read_buffer[c]=(char)0x80;
236                         for (i=c+1; i<64; i++) 
237                                 read_buffer[i]=0;
238                         if (c>55) 
239                         {
240                                 /* we need to do an entire new block */
241                                 sha_hash((int *)read_buffer, hashval);
242                                 for (i=0; i<14; i++) 
243                                         ((int*)read_buffer)[i]=0;
244                         }      
245 #ifndef WORDS_BIGENDIAN
246                         for (i=0; i<8; i++) 
247                         {
248                                 read_buffer[56+i]=(char)(length>>(56-(i*8))) & 0xff;
249                         }
250 #else   
251                         memcpy(read_buffer+56, &length, 8);
252 #endif
253                 }
254                 
255                 sha_hash((int *)read_buffer, hashval);
256                 str+=64;
257         }
258
259         strprintsha((char *)final, hashval);
260         free(hashval);
261         return (char *)final;
262 }