blob: a707a9689ce74c1308fb9b8a9175c8f500400ba8 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Modified 2/07
4 * By Benny Prijono <benny@prijono.org>
5 * Still 100% Public Domain
6 *
7 * This is the implementation of SHA-1 encryption algorithm based on
8 * Steve Reid work. Modified to work with PJLIB.
9 */
10
11/*
12SHA-1 in C
13By Steve Reid <sreid@sea-to-sky.net>
14100% Public Domain
15
16-----------------
17Modified 7/98
18By James H. Brown <jbrown@burgoyne.com>
19Still 100% Public Domain
20
21Corrected a problem which generated improper hash values on 16 bit machines
22Routine SHA1Update changed from
23 void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
24len)
25to
26 void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
27long len)
28
29The 'len' parameter was declared an int which works fine on 32 bit machines.
30However, on 16 bit machines an int is too small for the shifts being done
31against
32it. This caused the hash function to generate incorrect values if len was
33greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
34
35Since the file IO in main() reads 16K at a time, any file 8K or larger would
36be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
37"a"s).
38
39I also changed the declaration of variables i & j in SHA1Update to
40unsigned long from unsigned int for the same reason.
41
42These changes should make no difference to any 32 bit implementations since
43an
44int and a long are the same size in those environments.
45
46--
47I also corrected a few compiler warnings generated by Borland C.
481. Added #include <process.h> for exit() prototype
492. Removed unused variable 'j' in SHA1Final
503. Changed exit(0) to return(0) at end of main.
51
52ALL changes I made can be located by searching for comments containing 'JHB'
53-----------------
54Modified 8/98
55By Steve Reid <sreid@sea-to-sky.net>
56Still 100% public domain
57
581- Removed #include <process.h> and used return() instead of exit()
592- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
603- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
61
62-----------------
63Modified 4/01
64By Saul Kravitz <Saul.Kravitz@celera.com>
65Still 100% PD
66Modified to run on Compaq Alpha hardware.
67
68-----------------
69Modified 07/2002
70By Ralph Giles <giles@ghostscript.com>
71Still 100% public domain
72modified for use with stdint types, autoconf
73code cleanup, removed attribution comments
74switched SHA1Final() argument order for consistency
75use SHA1_ prefix for public api
76move public api to sha1.h
77*/
78
79/*
80Test Vectors (from FIPS PUB 180-1)
81"abc"
82 A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
83"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
85A million repetitions of "a"
86 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
87*/
88
89/* #define SHA1HANDSOFF */
90/* blp:
91#ifdef HAVE_CONFIG_H
92#include "config.h"
93#endif
94
95#include <stdio.h>
96#include <string.h>
97
98#include "os_types.h"
99
100#include "sha1.h"
101*/
102#include <pjlib-util/sha1.h>
103#include <pj/string.h>
104
105#undef SHA1HANDSOFF
106
107
108static void SHA1_Transform(pj_uint32_t state[5], pj_uint8_t buffer[64]);
109
110#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
111
112/* blk0() and blk() perform the initial expand. */
113/* I got the idea of expanding during the round function from SSLeay */
114/* FIXME: can we do this in an endian-proof way? */
115/* #ifdef WORDS_BIGENDIAN */
116#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN != 0
117#define blk0(i) block->l[i]
118#else
119#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
120 |(rol(block->l[i],8)&0x00FF00FF))
121#endif
122#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
123 ^block->l[(i+2)&15]^block->l[i&15],1))
124
125/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
126#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
127#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
128#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
129#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
130#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
131
132
133/* Hash a single 512-bit block. This is the core of the algorithm. */
134static void SHA1_Transform(pj_uint32_t state[5], pj_uint8_t buffer[64])
135{
136 pj_uint32_t a, b, c, d, e;
137 typedef union {
138 pj_uint8_t c[64];
139 pj_uint32_t l[16];
140 } CHAR64LONG16;
141 CHAR64LONG16* block;
142
143#ifdef SHA1HANDSOFF
144 static pj_uint8_t workspace[64];
145 block = (CHAR64LONG16*)workspace;
146 pj_memcpy(block, buffer, 64);
147#else
148 block = (CHAR64LONG16*)buffer;
149#endif
150
151 /* Copy context->state[] to working vars */
152 a = state[0];
153 b = state[1];
154 c = state[2];
155 d = state[3];
156 e = state[4];
157
158 /* 4 rounds of 20 operations each. Loop unrolled. */
159 R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
160 R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
161 R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
162 R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
163 R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
164 R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
165 R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
166 R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
167 R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
168 R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
169 R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
170 R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
171 R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
172 R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
173 R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
174 R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
175 R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
176 R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
177 R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
178 R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
179
180 /* Add the working vars back into context.state[] */
181 state[0] += a;
182 state[1] += b;
183 state[2] += c;
184 state[3] += d;
185 state[4] += e;
186
187 /* Wipe variables */
188 a = b = c = d = e = 0;
189}
190
191
192/* SHA1Init - Initialize new context */
193PJ_DEF(void) pj_sha1_init(pj_sha1_context* context)
194{
195 /* SHA1 initialization constants */
196 context->state[0] = 0x67452301;
197 context->state[1] = 0xEFCDAB89;
198 context->state[2] = 0x98BADCFE;
199 context->state[3] = 0x10325476;
200 context->state[4] = 0xC3D2E1F0;
201 context->count[0] = context->count[1] = 0;
202}
203
204
205/* Run your data through this. */
206PJ_DEF(void) pj_sha1_update(pj_sha1_context* context,
207 const pj_uint8_t* data, const pj_size_t len)
208{
209 pj_size_t i, j;
210
211 j = (context->count[0] >> 3) & 63;
212 if ((context->count[0] += (pj_uint32_t)len << 3) < (len << 3))
213 context->count[1]++;
214 context->count[1] += ((pj_uint32_t)len >> 29);
215 if ((j + len) > 63) {
216 pj_memcpy(&context->buffer[j], data, (i = 64-j));
217 SHA1_Transform(context->state, context->buffer);
218 for ( ; i + 63 < len; i += 64) {
219 pj_uint8_t tmp[64];
220 pj_memcpy(tmp, data + i, 64);
221 SHA1_Transform(context->state, tmp);
222 }
223 j = 0;
224 }
225 else i = 0;
226 pj_memcpy(&context->buffer[j], &data[i], len - i);
227
228}
229
230
231/* Add padding and return the message digest. */
232PJ_DEF(void) pj_sha1_final(pj_sha1_context* context,
233 pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE])
234{
235 pj_uint32_t i;
236 pj_uint8_t finalcount[8];
237
238 for (i = 0; i < 8; i++) {
239 finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
240 >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
241 }
242 pj_sha1_update(context, (pj_uint8_t *)"\200", 1);
243 while ((context->count[0] & 504) != 448) {
244 pj_sha1_update(context, (pj_uint8_t *)"\0", 1);
245 }
246 pj_sha1_update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
247 for (i = 0; i < PJ_SHA1_DIGEST_SIZE; i++) {
248 digest[i] = (pj_uint8_t)
249 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
250 }
251
252 /* Wipe variables */
253 i = 0;
254 pj_memset(context->buffer, 0, 64);
255 pj_memset(context->state, 0, 20);
256 pj_memset(context->count, 0, 8);
257 pj_memset(finalcount, 0, 8); /* SWR */
258
259#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
260 SHA1_Transform(context->state, context->buffer);
261#endif
262}
263