blob: a4fbd673bbe89fd8bf60cd850a433d6656a545c5 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/* $NetBSD: sha1.c,v 1.1 2005/12/20 20:29:40 christos Exp $ */
2/* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */
3
4/*
5 * SHA-1 in C
6 * By Steve Reid <steve@edmweb.com>
7 * 100% Public Domain
8 *
9 * Test Vectors (from FIPS PUB 180-1)
10 * "abc"
11 * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
12 * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
13 * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
14 * A million repetitions of "a"
15 * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
16 */
17
18#define SHA1HANDSOFF /* Copies data before messing with it. */
19
20#include <sys/cdefs.h>
21#include <sys/types.h>
22#include <assert.h>
23#include <sha1.h>
24#include <string.h>
Jim Huang82932ef2011-12-12 16:34:56 +080025#include <endian.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080026
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080027#if !HAVE_SHA1_H
28
29#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
30
31/*
32 * blk0() and blk() perform the initial expand.
33 * I got the idea of expanding during the round function from SSLeay
34 */
35#if BYTE_ORDER == LITTLE_ENDIAN
Jim Huang82932ef2011-12-12 16:34:56 +080036# define blk0(i) swap32(block->l[i])
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080037#else
38# define blk0(i) block->l[i]
39#endif
40#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
41 ^block->l[(i+2)&15]^block->l[i&15],1))
42
43/*
44 * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
45 */
46#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
47#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
48#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
49#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
50#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
51
52typedef union {
Jim Huang82932ef2011-12-12 16:34:56 +080053 uint8_t c[SHA1_BLOCK_SIZE];
54 uint32_t l[SHA1_BLOCK_SIZE/4];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080055} CHAR64LONG16;
56
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080057/*
58 * Hash a single 512-bit block. This is the core of the algorithm.
59 */
Jim Huang82932ef2011-12-12 16:34:56 +080060void SHA1Transform(uint32_t state[SHA1_DIGEST_LENGTH/4],
61 const uint8_t buffer[SHA1_BLOCK_SIZE])
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080062{
Jim Huang0dd8c792011-12-12 16:34:08 +080063 uint32_t a, b, c, d, e;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080064 CHAR64LONG16 *block;
65
66#ifdef SHA1HANDSOFF
67 CHAR64LONG16 workspace;
68#endif
69
70 assert(buffer != 0);
71 assert(state != 0);
72
73#ifdef SHA1HANDSOFF
74 block = &workspace;
Jim Huang82932ef2011-12-12 16:34:56 +080075 (void)memcpy(block, buffer, SHA1_BLOCK_SIZE);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080076#else
77 block = (CHAR64LONG16 *)(void *)buffer;
78#endif
79
80 /* Copy context->state[] to working vars */
81 a = state[0];
82 b = state[1];
83 c = state[2];
84 d = state[3];
85 e = state[4];
86
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080087 /* 4 rounds of 20 operations each. Loop unrolled. */
88 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);
89 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);
90 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);
91 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);
92 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);
93 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);
94 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);
95 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);
96 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);
97 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);
98 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);
99 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);
100 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);
101 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);
102 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);
103 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);
104 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);
105 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);
106 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);
107 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);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800108
109 /* Add the working vars back into context.state[] */
110 state[0] += a;
111 state[1] += b;
112 state[2] += c;
113 state[3] += d;
114 state[4] += e;
115
116 /* Wipe variables */
117 a = b = c = d = e = 0;
118}
119
120
121/*
122 * SHA1Init - Initialize new context
123 */
Jim Huang0dd8c792011-12-12 16:34:08 +0800124void SHA1Init(SHA1_CTX *context)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800125{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800126 assert(context != 0);
127
128 /* SHA1 initialization constants */
Jim Huang82932ef2011-12-12 16:34:56 +0800129 *context = (SHA1_CTX) {
130 .state = {
131 0x67452301,
132 0xEFCDAB89,
133 0x98BADCFE,
134 0x10325476,
135 0xC3D2E1F0,
136 },
137 .count = 0,
138 };
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800139}
140
141
142/*
143 * Run your data through this.
144 */
Jim Huang0dd8c792011-12-12 16:34:08 +0800145void SHA1Update(SHA1_CTX *context, const uint8_t *data, unsigned int len)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800146{
Jim Huang0dd8c792011-12-12 16:34:08 +0800147 unsigned int i, j;
Jim Huang82932ef2011-12-12 16:34:56 +0800148 unsigned int partial, done;
149 const uint8_t *src;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800150
151 assert(context != 0);
152 assert(data != 0);
153
Jim Huang82932ef2011-12-12 16:34:56 +0800154 partial = context->count % SHA1_BLOCK_SIZE;
155 context->count += len;
156 done = 0;
157 src = data;
158
159 if ((partial + len) >= SHA1_BLOCK_SIZE) {
160 if (partial) {
161 done = -partial;
162 memcpy(context->buffer + partial, data, done + SHA1_BLOCK_SIZE);
163 src = context->buffer;
164 }
165 do {
166 SHA1Transform(context->state, src);
167 done += SHA1_BLOCK_SIZE;
168 src = data + done;
169 } while (done + SHA1_BLOCK_SIZE <= len);
170 partial = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800171 }
Jim Huang82932ef2011-12-12 16:34:56 +0800172 memcpy(context->buffer + partial, src, len - done);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800173}
174
175
176/*
177 * Add padding and return the message digest.
178 */
Jim Huang82932ef2011-12-12 16:34:56 +0800179void SHA1Final(uint8_t digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800180{
Jim Huang82932ef2011-12-12 16:34:56 +0800181 uint32_t i, index, pad_len;
182 uint64_t bits;
183 static const uint8_t padding[SHA1_BLOCK_SIZE] = { 0x80, };
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800184
185 assert(digest != 0);
186 assert(context != 0);
187
Jim Huang82932ef2011-12-12 16:34:56 +0800188#if BYTE_ORDER == LITTLE_ENDIAN
189 bits = swap64(context->count << 3);
190#else
191 bits = context->count << 3;
192#endif
193
194 /* Pad out to 56 mod 64 */
195 index = context->count & 0x3f;
196 pad_len = (index < 56) ? (56 - index) : ((64 + 56) - index);
197 SHA1Update(context, padding, pad_len);
198
199 /* Append length */
200 SHA1Update(context, (const uint8_t *)&bits, sizeof(bits));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800201
202 if (digest) {
Jim Huang82932ef2011-12-12 16:34:56 +0800203 for (i = 0; i < SHA1_DIGEST_LENGTH/4; i++)
204#if BYTE_ORDER == LITTLE_ENDIAN
205 ((uint32_t *)digest)[i] = swap32(context->state[i]);
206#else
207 ((uint32_t *)digest)[i] = context->state[i];
208#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800209 }
210}
211
212#endif /* HAVE_SHA1_H */