7fcb23a065579db4bf4ecda07daf511ed5350c69
[openafs.git] / src / afsweb / securehash.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * All Rights Reserved
12  * Licensed Materials - Property of Transarc
13  *
14  * For copyright information, see IPL which you accepted in order to
15  * download this software.
16  *
17  * COMPONENT_NAME: nsafs
18  *
19  * ORIGINS: Transarc Corp.
20  *
21  */
22
23 /*
24  * HISTORY
25  * Revision 1.1  1998/04/07  17:51:02
26  * User space cache manager and netscape plugin
27  *
28  * Revision 1.2  1998/01/31  20:55:31
29  * Port of AFS client to user space. This delta replaces the previous
30  * delta, which had too many merge problems after I tried to change
31  * some of the files back to their originals after the review.
32  *
33  * Revision 1.1  1998/01/23  20:36:14
34  * Implemented login cache, cleaned up some bugs, and added
35  * directory index generation.
36  */
37
38 /*
39  * This module implements the Secure Hash Algorithm (SHA) as specified in
40  * the Secure Hash Standard (SHS, FIPS PUB 180.1).
41  */
42
43 #include "../afs/param.h"       /* Should be always first */
44 #include "../afs/sysincludes.h" /* Standard vendor system headers */
45 #include <net/if.h>
46 #include "../afs/afsincludes.h" /* Afs-based standard headers */
47 #include "../afs/afs_stats.h"
48 #include "../afs/auth.h"
49 #include "../afs/cellconfig.h"
50 #include "../afs/vice.h"
51 #include "../afs/nsafs.h"
52
53 static int big_endian;
54
55 static const sha_int hashinit[] = {
56     0x67452301, 0xEFCDAB89, 0x98BADCFE,
57     0x10325476, 0xC3D2E1F0
58 };
59
60 #define ROTL(n, x) (((x) << (n)) | ((x) >> (SHA_BITS_PER_INT - (n))))
61
62 #ifdef DISABLED_CODE_HERE
63 static sha_int f(int t, sha_int x, sha_int y, sha_int z)
64 {
65     if (t < 0 || t >= SHA_ROUNDS) return 0;
66     if (t < 20)
67         return (z ^ (x & (y ^ z)));
68     if (t < 40)
69         return (x ^ y ^ z);
70     if (t < 60)
71         return ((x & y) | (z & (x | y))); /* saves 1 boolean op */
72     return (x ^ y ^ z);         /* 60-79 same as 40-59 */
73 }
74 #endif
75
76 /* This is the "magic" function used for each round.         */
77 /* Were this a C function, the interface would be:           */
78 /* static sha_int f(int t, sha_int x, sha_int y, sha_int z) */
79 /* The function call version preserved above until stable    */
80
81 #define f_a(x, y, z) (z ^ (x & (y ^ z)))
82 #define f_b(x, y, z) (x ^ y ^ z)
83 #define f_c(x, y, z) (( (x & y) | (z & (x | y))))
84
85 #define f(t, x, y, z)                     \
86       ( (t < 0 || t >= SHA_ROUNDS) ? 0 :  \
87           ( (t < 20) ? f_a(x, y, z) :     \
88               ( (t < 40) ? f_b(x, y, z) : \
89                   ( (t < 60) ? f_c(x, y, z) : f_b(x, y, z)))))
90
91 /*
92  *static sha_int K(int t)
93  *{
94  *    if (t < 0 || t >= SHA_ROUNDS) return 0;
95  *   if (t < 20)
96  *      return 0x5A827999;
97  *   if (t < 40)
98  *      return 0x6ED9EBA1;
99  *   if (t < 60)
100  *      return 0x8F1BBCDC;
101  *   return 0xCA62C1D6;
102  * }
103  */
104
105 /* This macro/function supplies the "magic" constant for each round. */
106 /* The function call version preserved above until stable            */
107
108 static const sha_int k_vals[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6};
109
110 #define K(t) ( (t < 0 || t >= SHA_ROUNDS) ? 0 : k_vals[ t/20 ] )
111
112 /*
113  * Update the internal state based on the given chunk.
114  */
115 static void transform(shaState *shaStateP, sha_int *chunk)
116 {
117     sha_int A = shaStateP->digest[0];
118     sha_int B = shaStateP->digest[1];
119     sha_int C = shaStateP->digest[2];
120     sha_int D = shaStateP->digest[3];
121     sha_int E = shaStateP->digest[4];
122     sha_int TEMP = 0;
123
124     int t;
125     sha_int W[SHA_ROUNDS];
126
127     for (t = 0; t < SHA_CHUNK_INTS; t++)
128         W[t] = chunk[t];
129     for (; t < SHA_ROUNDS; t++) {
130         TEMP = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
131         W[t] = ROTL(1, TEMP);
132     }
133
134     for (t = 0; t < SHA_ROUNDS; t++) {
135         TEMP = ROTL(5, A) + f(t, B, C, D) + E + W[t] + K(t);
136         E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
137     }
138
139     shaStateP->digest[0] += A;
140     shaStateP->digest[1] += B;
141     shaStateP->digest[2] += C;
142     shaStateP->digest[3] += D;
143     shaStateP->digest[4] += E;
144 }
145
146
147 /*
148  * This function takes an array of SHA_CHUNK_BYTES bytes
149  * as input and produces an output array of ints that is
150  * SHA_CHUNK_INTS long.
151  */
152 static void buildInts(const char *data, sha_int *chunk)
153 {
154     /*
155      * Need to copy the data because we can't be certain that
156      * the input buffer will be aligned correctly.
157      */
158     memcpy((void *)chunk, (void *)data, SHA_CHUNK_BYTES);
159
160     if (!big_endian) {
161         /* This loop does nothing but waste time on a big endian machine. */
162         int i;
163
164         for (i = 0; i < SHA_CHUNK_INTS; i++)
165             chunk[i] = ntohl(chunk[i]);
166     }
167 }
168
169 /*
170  * This function updates the internal state of the hash by using
171  * buildInts to break the input up into chunks and repeatedly passing
172  * these chunks to transform().
173  */
174 void sha_update(shaState *shaStateP, const char *buffer, int bufferLen)
175 {
176     int i;
177     sha_int chunk[SHA_CHUNK_INTS];
178     sha_int newLo;
179
180     if (buffer == NULL || bufferLen == 0)
181         return;
182
183     newLo = shaStateP->bitcountLo + (bufferLen << 3);
184     if (newLo < shaStateP->bitcountLo)
185         shaStateP->bitcountHi++;
186     shaStateP->bitcountLo = newLo;
187     shaStateP->bitcountHi += ((bufferLen >> (SHA_BITS_PER_INT - 3)) & 0x07);
188     
189     /*
190      * If we won't have enough for a full chunk, just tack this
191      * buffer onto the leftover piece and return.
192      */
193     if (shaStateP->leftoverLen + bufferLen < SHA_CHUNK_BYTES) {
194         memcpy((void *)&(shaStateP->leftover[shaStateP->leftoverLen]),
195                (void *)buffer, bufferLen);
196         shaStateP->leftoverLen += bufferLen;
197         return;
198     }
199
200     /* If we have a leftover chunk, process it first. */
201     if (shaStateP->leftoverLen > 0) {
202         i = (SHA_CHUNK_BYTES - shaStateP->leftoverLen);
203         memcpy((void *)&(shaStateP->leftover[shaStateP->leftoverLen]),
204                (void *)buffer, i);
205         buffer += i;
206         bufferLen -= i;
207         buildInts(shaStateP->leftover, chunk);
208         shaStateP->leftoverLen = 0;
209         transform(shaStateP, chunk);
210     }
211
212     while (bufferLen >= SHA_CHUNK_BYTES) {
213         buildInts(buffer, chunk);
214         transform(shaStateP, chunk);
215         buffer += SHA_CHUNK_BYTES;
216         bufferLen -= SHA_CHUNK_BYTES;
217     }
218     assert((bufferLen >= 0) && (bufferLen < SHA_CHUNK_BYTES));
219
220     if (bufferLen > 0) {
221         memcpy((void *)&shaStateP->leftover[0], (void *)buffer, bufferLen);
222         shaStateP->leftoverLen = bufferLen;
223     }
224 }
225
226
227 /*
228  * This method updates the internal state of the hash using
229  * any leftover data plus appropriate padding and incorporation
230  * of the hash bitcount to finish the hash.  The hash value
231  * is not valid until finish() has been called.
232  */
233 void sha_finish(shaState *shaStateP)
234 {
235     sha_int chunk[SHA_CHUNK_INTS];
236     int i;
237
238     if (shaStateP->leftoverLen > (SHA_CHUNK_BYTES - 9)) {
239         shaStateP->leftover[shaStateP->leftoverLen++] = 0x80;
240         memset(&(shaStateP->leftover[shaStateP->leftoverLen]), 0,
241                (SHA_CHUNK_BYTES - shaStateP->leftoverLen));
242         buildInts(shaStateP->leftover, chunk);
243         transform(shaStateP, chunk);
244         memset(chunk, 0, SHA_CHUNK_BYTES);
245     } else {
246         shaStateP->leftover[shaStateP->leftoverLen++] = 0x80;
247         memset(&(shaStateP->leftover[shaStateP->leftoverLen]), 0,
248                (SHA_CHUNK_BYTES - shaStateP->leftoverLen));
249         buildInts(shaStateP->leftover, chunk);
250     }
251     shaStateP->leftoverLen = 0;
252
253     chunk[SHA_CHUNK_INTS - 2] = shaStateP->bitcountHi;
254     chunk[SHA_CHUNK_INTS - 1] = shaStateP->bitcountLo;
255     transform(shaStateP, chunk);
256 }
257
258
259 /*
260  * Initialize the hash to its "magic" initial value specified by the
261  * SHS standard, and clear out the bitcount and leftover vars.
262  * This should be used to initialize an shaState.
263  */
264 void sha_clear(shaState *shaStateP)
265 {
266     big_endian = (0x01020304 == htonl(0x01020304));
267
268     memcpy((void *)&shaStateP->digest[0], (void *)&hashinit[0], SHA_HASH_BYTES);
269     shaStateP->bitcountLo = shaStateP->bitcountHi = 0;
270     shaStateP->leftoverLen = 0;
271 }
272
273
274 /*
275  * Hash the buffer and place the result in *shaStateP.
276  */
277 void sha_hash(shaState *shaStateP, const char *buffer, int bufferLen)
278 {
279     sha_clear(shaStateP);
280     sha_update(shaStateP, buffer, bufferLen);
281     sha_finish(shaStateP);
282 }
283
284
285 /*
286  * Returns the current state of the hash as an array of 20 bytes.
287  * This will be an interim result if finish() has not yet been called.
288  */
289 void sha_bytes(const shaState *shaStateP, char *bytes)
290 {
291     sha_int temp[SHA_HASH_INTS];
292     int  i;
293
294     for (i = 0; i < SHA_HASH_INTS; i++)
295         temp[i] = htonl(shaStateP->digest[i]);
296     memcpy(bytes, (void *)&temp[0], SHA_HASH_BYTES);
297 }