xref: /freebsd/lib/libmd/sha1c.c (revision 181a04415a8b3a3fe8be4b986dce550f09cbb415)
1 /*-
2  * Copyright (c) 2009 The Go Authors. All rights reserved.
3  * Copyright (c) 2024 Robert Clausecker <fuz@freebsd.org>
4  *
5  * Adapted from Go's crypto/sha1/sha1.go.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following disclaimer
15  * in the documentation and/or other materials provided with the
16  * distribution.
17  *   * Neither the name of Google Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <assert.h>
35 #include <sha.h>
36 #include <stdint.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <sys/endian.h>
40 
41 #ifdef SHA1_ASM
42 extern void	sha1_block(SHA1_CTX *, const void *, size_t);
43 #else
44 static void	sha1_block(SHA1_CTX *, const void *, size_t);
45 #endif
46 
47 #define INIT0 0x67452301
48 #define INIT1 0xEFCDAB89
49 #define INIT2 0x98BADCFE
50 #define INIT3 0x10325476
51 #define INIT4 0xC3D2E1F0
52 
53 #define K0 0x5A827999
54 #define K1 0x6ED9EBA1
55 #define K2 0x8F1BBCDC
56 #define K3 0xCA62C1D6
57 
58 void
SHA1_Init(SHA1_CTX * c)59 SHA1_Init(SHA1_CTX *c)
60 {
61 	c->h0 = INIT0;
62 	c->h1 = INIT1;
63 	c->h2 = INIT2;
64 	c->h3 = INIT3;
65 	c->h4 = INIT4;
66 	c->Nl = 0;
67 	c->Nh = 0;
68 	c->num = 0;
69 }
70 
71 void
SHA1_Update(SHA1_CTX * c,const void * data,size_t len)72 SHA1_Update(SHA1_CTX *c, const void *data, size_t len)
73 {
74 	uint64_t nn;
75 	const char *p = data;
76 
77 	nn = (uint64_t)c->Nl | (uint64_t)c->Nh << 32;
78 	nn += len;
79 	c->Nl = (uint32_t)nn;
80 	c->Nh = (uint32_t)(nn >> 32);
81 
82 	if (c->num > 0) {
83 		size_t n = SHA_CBLOCK - c->num;
84 
85 		if (n > len)
86 			n = len;
87 
88 		memcpy((char *)c->data + c->num, p, n);
89 		c->num += n;
90 		if (c->num == SHA_CBLOCK) {
91 			sha1_block(c, (void *)c->data, SHA_CBLOCK);
92 			c->num = 0;
93 		}
94 
95 		p += n;
96 		len -= n;
97 	}
98 
99 	if (len >= SHA_CBLOCK) {
100 		size_t n = len & ~(size_t)(SHA_CBLOCK - 1);
101 
102 		sha1_block(c, p, n);
103 		p += n;
104 		len -= n;
105 	}
106 
107 	if (len > 0) {
108 		memcpy(c->data, p, len);
109 		c->num = len;
110 	}
111 }
112 
113 void
SHA1_Final(unsigned char * md,SHA1_CTX * c)114 SHA1_Final(unsigned char *md, SHA1_CTX *c)
115 {
116 	uint64_t len;
117 	size_t t;
118 	unsigned char tmp[SHA_CBLOCK + sizeof(uint64_t)] = {0x80, 0};
119 
120 	len = (uint64_t)c->Nl | (uint64_t)c->Nh << 32;
121 	t = 64 + 56 - c->Nl % 64;
122 	if (t > 64)
123 		t -= 64;
124 
125 	/* length in bits */
126 	len <<= 3;
127 	be64enc(tmp + t, len);
128 	SHA1_Update(c, tmp, t + 8);
129 	assert(c->num == 0);
130 
131 	be32enc(md +  0, c->h0);
132 	be32enc(md +  4, c->h1);
133 	be32enc(md +  8, c->h2);
134 	be32enc(md + 12, c->h3);
135 	be32enc(md + 16, c->h4);
136 
137 	explicit_bzero(c, sizeof(*c));
138 }
139 
140 #ifndef SHA1_ASM
141 static void
142 /* invariant: len is a multiple of SHA_CBLOCK */
sha1_block(SHA1_CTX * c,const void * data,size_t len)143 sha1_block(SHA1_CTX *c, const void *data, size_t len)
144 {
145 	uint32_t w[16];
146 	uint32_t h0 = c->h0, h1 = c->h1, h2 = c->h2, h3 = c->h3, h4 = c->h4;
147 	const char *p = data;
148 
149 	while (len >= SHA_CBLOCK) {
150 		size_t i;
151 		uint32_t a = h0, b = h1, c = h2, d = h3, e = h4;
152 		uint32_t f, t, tmp;
153 
154 #		pragma unroll
155 		for (i = 0; i < 16; i++)
156 			w[i] = be32dec(p + 4*i);
157 
158 #		pragma unroll
159 		for (i = 0; i < 16; i++) {
160 			f = b & c | ~b & d;
161 			t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K0;
162 			e = d;
163 			d = c;
164 			c = b << 30 | b >> 32 - 30;
165 			b = a;
166 			a = t;
167 		}
168 
169 #		pragma unroll
170 		for (; i < 20; i++) {
171 			tmp = w[i - 3 & 0xf] ^ w[i - 8 & 0xf] ^ w[i - 14 & 0xf] ^ w[i & 0xf];
172 			w[i & 0xf] = tmp << 1 | tmp >> 32 - 1;
173 
174 			f = b & c | ~b & d;
175 			t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K0;
176 			e = d;
177 			d = c;
178 			c = b << 30 | b >> 32 - 30;
179 			b = a;
180 			a = t;
181 		}
182 
183 #		pragma unroll
184 		for (; i < 40; i++) {
185 			tmp = w[i - 3 & 0xf] ^ w[i - 8 & 0xf] ^ w[i - 14 & 0xf] ^ w[i & 0xf];
186 			w[i & 0xf] = tmp << 1 | tmp >> 32 - 1;
187 
188 			f = b ^ c ^ d;
189 			t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K1;
190 			e = d;
191 			d = c;
192 			c = b << 30 | b >> 32 - 30;
193 			b = a;
194 			a = t;
195 		}
196 
197 #		pragma unroll
198 		for (; i < 60; i++) {
199 			tmp = w[i - 3 & 0xf] ^ w[i - 8 & 0xf] ^ w[i - 14 & 0xf] ^ w[i & 0xf];
200 			w[i & 0xf] = tmp << 1 | tmp >> 32 - 1;
201 
202 			f = (b | c) & d | b & c;
203 			t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K2;
204 			e = d;
205 			d = c;
206 			c = b << 30 | b >> 32 - 30;
207 			b = a;
208 			a = t;
209 		}
210 
211 #		pragma unroll
212 		for (; i < 80; i++) {
213 			tmp = w[i - 3 & 0xf] ^ w[i - 8 & 0xf] ^ w[i - 14 & 0xf] ^ w[i & 0xf];
214 			w[i & 0xf] = tmp << 1 | tmp >> 32 - 1;
215 
216 			f = b ^ c ^ d;
217 			t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K3;
218 			e = d;
219 			d = c;
220 			c = b << 30 | b >> 32 - 30;
221 			b = a;
222 			a = t;
223 		}
224 
225 		h0 += a;
226 		h1 += b;
227 		h2 += c;
228 		h3 += d;
229 		h4 += e;
230 
231 		p += SHA_CBLOCK;
232 		len -= SHA_CBLOCK;
233 	}
234 
235 	c->h0 = h0;
236 	c->h1 = h1;
237 	c->h2 = h2;
238 	c->h3 = h3;
239 	c->h4 = h4;
240 }
241 #endif
242 
243 #ifdef WEAK_REFS
244 /* When building libmd, provide weak references. Note: this is not
245    activated in the context of compiling these sources for internal
246    use in libcrypt.
247  */
248 #undef SHA_Init
249 __weak_reference(_libmd_SHA_Init, SHA_Init);
250 #undef SHA_Update
251 __weak_reference(_libmd_SHA_Update, SHA_Update);
252 #undef SHA_Final
253 __weak_reference(_libmd_SHA_Final, SHA_Final);
254 #undef SHA1_Init
255 __weak_reference(_libmd_SHA1_Init, SHA1_Init);
256 #undef SHA1_Update
257 __weak_reference(_libmd_SHA1_Update, SHA1_Update);
258 #undef SHA1_Final
259 __weak_reference(_libmd_SHA1_Final, SHA1_Final);
260 #endif
261