xref: /freebsd/sys/crypto/md5c.c (revision 90fa789cfab54294d4c3a0ac74e01747ce074386)
1 /*-
2  * Copyright (c) 2024, 2025 Robert Clausecker <fuz@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <sys/endian.h>
8 #include <sys/types.h>
9 #include <sys/md5.h>
10 
11 #ifdef _KERNEL
12 #include <sys/param.h>
13 #include <sys/stdint.h>
14 #include <sys/systm.h>
15 #define assert(expr) MPASS(expr)
16 #else
17 #include <assert.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <strings.h>
21 #endif /* defined(_KERNEL) */
22 
23 #define md5block _libmd_md5block
24 #ifdef MD5_ASM
25 extern void	md5block(MD5_CTX *, const void *, size_t);
26 #else
27 static void	md5block(MD5_CTX *, const void *, size_t);
28 #endif
29 
30 /* don't unroll in bootloader */
31 #ifdef STANDALONE_SMALL
32 #define UNROLL
33 #else
34 #define UNROLL _Pragma("unroll")
35 #endif
36 
37 void
MD5Init(MD5_CTX * ctx)38 MD5Init(MD5_CTX *ctx)
39 {
40 	ctx->state[0] = 0x67452301;
41 	ctx->state[1] = 0xefcdab89;
42 	ctx->state[2] = 0x98badcfe;
43 	ctx->state[3] = 0x10325476;
44 
45 	ctx->count[0] = 0;
46 	ctx->count[1] = 0;
47 }
48 
49 void
MD5Update(MD5_CTX * ctx,const void * data,unsigned int len)50 MD5Update(MD5_CTX *ctx, const void *data, unsigned int len)
51 {
52 	uint64_t nn;
53 	const char *p = data;
54 	unsigned num;
55 
56 	num = ctx->count[0] % MD5_BLOCK_LENGTH;
57 	nn = (uint64_t)ctx->count[0] | (uint64_t)ctx->count[1] << 32;
58 	nn += len;
59 	ctx->count[0] = (uint32_t)nn;
60 	ctx->count[1] = (uint32_t)(nn >> 32);
61 
62 	if (num > 0) {
63 		unsigned int n = MD5_BLOCK_LENGTH - num;
64 
65 		if (n > len)
66 			n = len;
67 
68 		memcpy((char *)ctx->buffer + num, p, n);
69 		num += n;
70 		if (num == MD5_BLOCK_LENGTH)
71 			md5block(ctx, (void *)ctx->buffer, MD5_BLOCK_LENGTH);
72 
73 		p += n;
74 		len -= n;
75 	}
76 
77 	if (len >= MD5_BLOCK_LENGTH) {
78 		unsigned n = len & ~(unsigned)(MD5_BLOCK_LENGTH - 1);
79 
80 		md5block(ctx, p, n);
81 		p += n;
82 		len -= n;
83 	}
84 
85 	if (len > 0)
86 		memcpy((void *)ctx->buffer, p, len);
87 }
88 
89 static void
MD5Pad(MD5_CTX * ctx)90 MD5Pad(MD5_CTX *ctx)
91 {
92 	uint64_t len;
93 	unsigned t;
94 	unsigned char tmp[MD5_BLOCK_LENGTH + sizeof(uint64_t)] = {0x80, 0};
95 
96 	len = (uint64_t)ctx->count[0] | (uint64_t)ctx->count[1] << 32;
97 	t = 64 + 56 - ctx->count[0] % 64;
98 	if (t > 64)
99 		t -= 64;
100 
101 	/* length in bits */
102 	len <<= 3;
103 	le64enc(tmp + t, len);
104 	MD5Update(ctx, tmp, t + 8);
105 	assert(ctx->count[0] % MD5_BLOCK_LENGTH == 0);
106 }
107 
108 void
MD5Final(unsigned char md[16],MD5_CTX * ctx)109 MD5Final(unsigned char md[16], MD5_CTX *ctx)
110 {
111 	MD5Pad(ctx);
112 
113 	le32enc(md +  0, ctx->state[0]);
114 	le32enc(md +  4, ctx->state[1]);
115 	le32enc(md +  8, ctx->state[2]);
116 	le32enc(md + 12, ctx->state[3]);
117 
118 	explicit_bzero(ctx, sizeof(ctx));
119 }
120 
121 #ifndef MD5_ASM
122 static const uint32_t K[64] = {
123 	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
124 	0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
125 	0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
126 	0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
127 	0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
128 	0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
129 	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
130 	0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
131 	0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
132 	0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
133 	0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
134 	0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
135 	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
136 	0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
137 	0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
138 	0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
139 };
140 
141 static inline uint32_t
rol32(uint32_t a,int b)142 rol32(uint32_t a, int b)
143 {
144 	return (a << b | a >> (32 - b));
145 }
146 
147 static void
md5block(MD5_CTX * ctx,const void * data,size_t len)148 md5block(MD5_CTX *ctx, const void *data, size_t len)
149 {
150 	uint32_t m[16], a0, b0, c0, d0;
151 	const char *p = data;
152 
153 	a0 = ctx->state[0];
154 	b0 = ctx->state[1];
155 	c0 = ctx->state[2];
156 	d0 = ctx->state[3];
157 
158 	while (len >= MD5_BLOCK_LENGTH) {
159 		size_t i;
160 		uint32_t a = a0, b = b0, c = c0, d = d0, f, tmp;
161 
162 		UNROLL
163 		for (i = 0; i < 16; i++)
164 			m[i] = le32dec(p + 4*i);
165 
166 		UNROLL
167 		for (i = 0; i < 16; i += 4) {
168 			f = d ^ (b & (c ^ d));
169 			tmp = d;
170 			d = c;
171 			c = b;
172 			b += rol32(a + f + K[i] + m[i], 7);
173 			a = tmp;
174 
175 			f = d ^ (b & (c ^ d));
176 			tmp = d;
177 			d = c;
178 			c = b;
179 			b += rol32(a + f + K[i + 1] + m[i + 1], 12);
180 			a = tmp;
181 
182 			f = d ^ (b & (c ^ d));
183 			tmp = d;
184 			d = c;
185 			c = b;
186 			b += rol32(a + f + K[i + 2] + m[i + 2], 17);
187 			a = tmp;
188 
189 			f = d ^ (b & (c ^ d));
190 			tmp = d;
191 			d = c;
192 			c = b;
193 			b += rol32(a + f + K[i + 3] + m[i + 3], 22);
194 			a = tmp;
195 		}
196 
197 		UNROLL
198 		for (; i < 32; i += 4) {
199 			f = c ^ (d & (b ^ c));
200 			tmp = d;
201 			d = c;
202 			c = b;
203 			b += rol32(a + f + K[i] + m[(5*i + 1) % 16], 5);
204 			a = tmp;
205 
206 			f = c ^ (d & (b ^ c));
207 			tmp = d;
208 			d = c;
209 			c = b;
210 			b += rol32(a + f + K[i + 1] + m[(5*i + 6) % 16], 9);
211 			a = tmp;
212 
213 			f = c ^ (d & (b ^ c));
214 			tmp = d;
215 			d = c;
216 			c = b;
217 			b += rol32(a + f + K[i + 2] + m[(5*i + 11) % 16], 14);
218 			a = tmp;
219 
220 			f = c ^ (d & (b ^ c));
221 			tmp = d;
222 			d = c;
223 			c = b;
224 			b += rol32(a + f + K[i + 3] + m[5*i % 16], 20);
225 			a = tmp;
226 		}
227 
228 		UNROLL
229 		for (; i < 48; i += 4) {
230 			f = b ^ c ^ d;
231 			tmp = d;
232 			d = c;
233 			c = b;
234 			b += rol32(a + f + K[i] + m[(3*i + 5) % 16], 4);
235 			a = tmp;
236 
237 			f = b ^ c ^ d;
238 			tmp = d;
239 			d = c;
240 			c = b;
241 			b += rol32(a + f + K[i + 1] + m[(3*i + 8) % 16], 11);
242 			a = tmp;
243 
244 			f = b ^ c ^ d;
245 			tmp = d;
246 			d = c;
247 			c = b;
248 			b += rol32(a + f + K[i + 2] + m[(3*i + 11) % 16], 16);
249 			a = tmp;
250 
251 			f = b ^ c ^ d;
252 			tmp = d;
253 			d = c;
254 			c = b;
255 			b += rol32(a + f + K[i + 3] + m[(3*i + 14) % 16], 23);
256 			a = tmp;
257 		}
258 
259 		UNROLL
260 		for (; i < 64; i += 4) {
261 			f = c ^ (b | ~d);
262 			tmp = d;
263 			d = c;
264 			c = b;
265 			b += rol32(a + f + K[i] + m[7*i % 16], 6);
266 			a = tmp;
267 
268 			f = c ^ (b | ~d);
269 			tmp = d;
270 			d = c;
271 			c = b;
272 			b += rol32(a + f + K[i + 1] + m[(7*i + 7) % 16], 10);
273 			a = tmp;
274 
275 			f = c ^ (b | ~d);
276 			tmp = d;
277 			d = c;
278 			c = b;
279 			b += rol32(a + f + K[i + 2] + m[(7*i + 14) % 16], 15);
280 			a = tmp;
281 
282 			f = c ^ (b | ~d);
283 			tmp = d;
284 			d = c;
285 			c = b;
286 			b += rol32(a + f + K[i + 3] + m[(7*i + 5) % 16], 21);
287 			a = tmp;
288 		}
289 
290 		a0 += a;
291 		b0 += b;
292 		c0 += c;
293 		d0 += d;
294 
295 		p += MD5_BLOCK_LENGTH;
296 		len -= MD5_BLOCK_LENGTH;
297 	}
298 
299 	ctx->state[0] = a0;
300 	ctx->state[1] = b0;
301 	ctx->state[2] = c0;
302 	ctx->state[3] = d0;
303 }
304 #endif /* !defined(MD5_ASM) */
305 
306 #ifdef WEAK_REFS
307 /* When building libmd, provide weak references. Note: this is not
308    activated in the context of compiling these sources for internal
309    use in libcrypt.
310  */
311 #undef MD5Init
312 __weak_reference(_libmd_MD5Init, MD5Init);
313 #undef MD5Update
314 __weak_reference(_libmd_MD5Update, MD5Update);
315 #undef MD5Final
316 __weak_reference(_libmd_MD5Final, MD5Final);
317 #endif
318