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