Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afsweb / securehash.c
CommitLineData
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
34static int big_endian;
35
36static 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
44static sha_int
45f(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
91static 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 */
99static void
100transform(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 */
141static void
142buildInts(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 */
164void
165sha_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 */
224void
225sha_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 */
256void
257sha_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 */
271void
272sha_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 */
284void
285sha_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}