1570af302Sopenharmony_ci/*
2570af302Sopenharmony_ci * md5 crypt implementation
3570af302Sopenharmony_ci *
4570af302Sopenharmony_ci * original md5 crypt design is from Poul-Henning Kamp
5570af302Sopenharmony_ci * this implementation was created based on the code in freebsd
6570af302Sopenharmony_ci * at least 32bit int is assumed, key is limited and $1$ prefix is mandatory,
7570af302Sopenharmony_ci * on error "*" is returned
8570af302Sopenharmony_ci */
9570af302Sopenharmony_ci#include <string.h>
10570af302Sopenharmony_ci#include <stdint.h>
11570af302Sopenharmony_ci
12570af302Sopenharmony_ci/* public domain md5 implementation based on rfc1321 and libtomcrypt */
13570af302Sopenharmony_ci
14570af302Sopenharmony_cistruct md5 {
15570af302Sopenharmony_ci	uint64_t len;    /* processed message length */
16570af302Sopenharmony_ci	uint32_t h[4];   /* hash state */
17570af302Sopenharmony_ci	uint8_t buf[64]; /* message block buffer */
18570af302Sopenharmony_ci};
19570af302Sopenharmony_ci
20570af302Sopenharmony_cistatic uint32_t rol(uint32_t n, int k) { return (n << k) | (n >> (32-k)); }
21570af302Sopenharmony_ci#define F(x,y,z) (z ^ (x & (y ^ z)))
22570af302Sopenharmony_ci#define G(x,y,z) (y ^ (z & (y ^ x)))
23570af302Sopenharmony_ci#define H(x,y,z) (x ^ y ^ z)
24570af302Sopenharmony_ci#define I(x,y,z) (y ^ (x | ~z))
25570af302Sopenharmony_ci#define FF(a,b,c,d,w,s,t) a += F(b,c,d) + w + t; a = rol(a,s) + b
26570af302Sopenharmony_ci#define GG(a,b,c,d,w,s,t) a += G(b,c,d) + w + t; a = rol(a,s) + b
27570af302Sopenharmony_ci#define HH(a,b,c,d,w,s,t) a += H(b,c,d) + w + t; a = rol(a,s) + b
28570af302Sopenharmony_ci#define II(a,b,c,d,w,s,t) a += I(b,c,d) + w + t; a = rol(a,s) + b
29570af302Sopenharmony_ci
30570af302Sopenharmony_cistatic const uint32_t tab[64] = {
31570af302Sopenharmony_ci0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
32570af302Sopenharmony_ci0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
33570af302Sopenharmony_ci0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
34570af302Sopenharmony_ci0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
35570af302Sopenharmony_ci0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
36570af302Sopenharmony_ci0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
37570af302Sopenharmony_ci0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
38570af302Sopenharmony_ci0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
39570af302Sopenharmony_ci};
40570af302Sopenharmony_ci
41570af302Sopenharmony_cistatic void processblock(struct md5 *s, const uint8_t *buf)
42570af302Sopenharmony_ci{
43570af302Sopenharmony_ci	uint32_t i, W[16], a, b, c, d;
44570af302Sopenharmony_ci
45570af302Sopenharmony_ci	for (i = 0; i < 16; i++) {
46570af302Sopenharmony_ci		W[i] = buf[4*i];
47570af302Sopenharmony_ci		W[i] |= (uint32_t)buf[4*i+1]<<8;
48570af302Sopenharmony_ci		W[i] |= (uint32_t)buf[4*i+2]<<16;
49570af302Sopenharmony_ci		W[i] |= (uint32_t)buf[4*i+3]<<24;
50570af302Sopenharmony_ci	}
51570af302Sopenharmony_ci
52570af302Sopenharmony_ci	a = s->h[0];
53570af302Sopenharmony_ci	b = s->h[1];
54570af302Sopenharmony_ci	c = s->h[2];
55570af302Sopenharmony_ci	d = s->h[3];
56570af302Sopenharmony_ci
57570af302Sopenharmony_ci	i = 0;
58570af302Sopenharmony_ci	while (i < 16) {
59570af302Sopenharmony_ci		FF(a,b,c,d, W[i],  7, tab[i]); i++;
60570af302Sopenharmony_ci		FF(d,a,b,c, W[i], 12, tab[i]); i++;
61570af302Sopenharmony_ci		FF(c,d,a,b, W[i], 17, tab[i]); i++;
62570af302Sopenharmony_ci		FF(b,c,d,a, W[i], 22, tab[i]); i++;
63570af302Sopenharmony_ci	}
64570af302Sopenharmony_ci	while (i < 32) {
65570af302Sopenharmony_ci		GG(a,b,c,d, W[(5*i+1)%16],  5, tab[i]); i++;
66570af302Sopenharmony_ci		GG(d,a,b,c, W[(5*i+1)%16],  9, tab[i]); i++;
67570af302Sopenharmony_ci		GG(c,d,a,b, W[(5*i+1)%16], 14, tab[i]); i++;
68570af302Sopenharmony_ci		GG(b,c,d,a, W[(5*i+1)%16], 20, tab[i]); i++;
69570af302Sopenharmony_ci	}
70570af302Sopenharmony_ci	while (i < 48) {
71570af302Sopenharmony_ci		HH(a,b,c,d, W[(3*i+5)%16],  4, tab[i]); i++;
72570af302Sopenharmony_ci		HH(d,a,b,c, W[(3*i+5)%16], 11, tab[i]); i++;
73570af302Sopenharmony_ci		HH(c,d,a,b, W[(3*i+5)%16], 16, tab[i]); i++;
74570af302Sopenharmony_ci		HH(b,c,d,a, W[(3*i+5)%16], 23, tab[i]); i++;
75570af302Sopenharmony_ci	}
76570af302Sopenharmony_ci	while (i < 64) {
77570af302Sopenharmony_ci		II(a,b,c,d, W[7*i%16],  6, tab[i]); i++;
78570af302Sopenharmony_ci		II(d,a,b,c, W[7*i%16], 10, tab[i]); i++;
79570af302Sopenharmony_ci		II(c,d,a,b, W[7*i%16], 15, tab[i]); i++;
80570af302Sopenharmony_ci		II(b,c,d,a, W[7*i%16], 21, tab[i]); i++;
81570af302Sopenharmony_ci	}
82570af302Sopenharmony_ci
83570af302Sopenharmony_ci	s->h[0] += a;
84570af302Sopenharmony_ci	s->h[1] += b;
85570af302Sopenharmony_ci	s->h[2] += c;
86570af302Sopenharmony_ci	s->h[3] += d;
87570af302Sopenharmony_ci}
88570af302Sopenharmony_ci
89570af302Sopenharmony_cistatic void pad(struct md5 *s)
90570af302Sopenharmony_ci{
91570af302Sopenharmony_ci	unsigned r = s->len % 64;
92570af302Sopenharmony_ci
93570af302Sopenharmony_ci	s->buf[r++] = 0x80;
94570af302Sopenharmony_ci	if (r > 56) {
95570af302Sopenharmony_ci		memset(s->buf + r, 0, 64 - r);
96570af302Sopenharmony_ci		r = 0;
97570af302Sopenharmony_ci		processblock(s, s->buf);
98570af302Sopenharmony_ci	}
99570af302Sopenharmony_ci	memset(s->buf + r, 0, 56 - r);
100570af302Sopenharmony_ci	s->len *= 8;
101570af302Sopenharmony_ci	s->buf[56] = s->len;
102570af302Sopenharmony_ci	s->buf[57] = s->len >> 8;
103570af302Sopenharmony_ci	s->buf[58] = s->len >> 16;
104570af302Sopenharmony_ci	s->buf[59] = s->len >> 24;
105570af302Sopenharmony_ci	s->buf[60] = s->len >> 32;
106570af302Sopenharmony_ci	s->buf[61] = s->len >> 40;
107570af302Sopenharmony_ci	s->buf[62] = s->len >> 48;
108570af302Sopenharmony_ci	s->buf[63] = s->len >> 56;
109570af302Sopenharmony_ci	processblock(s, s->buf);
110570af302Sopenharmony_ci}
111570af302Sopenharmony_ci
112570af302Sopenharmony_cistatic void md5_init(struct md5 *s)
113570af302Sopenharmony_ci{
114570af302Sopenharmony_ci	s->len = 0;
115570af302Sopenharmony_ci	s->h[0] = 0x67452301;
116570af302Sopenharmony_ci	s->h[1] = 0xefcdab89;
117570af302Sopenharmony_ci	s->h[2] = 0x98badcfe;
118570af302Sopenharmony_ci	s->h[3] = 0x10325476;
119570af302Sopenharmony_ci}
120570af302Sopenharmony_ci
121570af302Sopenharmony_cistatic void md5_sum(struct md5 *s, uint8_t *md)
122570af302Sopenharmony_ci{
123570af302Sopenharmony_ci	int i;
124570af302Sopenharmony_ci
125570af302Sopenharmony_ci	pad(s);
126570af302Sopenharmony_ci	for (i = 0; i < 4; i++) {
127570af302Sopenharmony_ci		md[4*i] = s->h[i];
128570af302Sopenharmony_ci		md[4*i+1] = s->h[i] >> 8;
129570af302Sopenharmony_ci		md[4*i+2] = s->h[i] >> 16;
130570af302Sopenharmony_ci		md[4*i+3] = s->h[i] >> 24;
131570af302Sopenharmony_ci	}
132570af302Sopenharmony_ci}
133570af302Sopenharmony_ci
134570af302Sopenharmony_cistatic void md5_update(struct md5 *s, const void *m, unsigned long len)
135570af302Sopenharmony_ci{
136570af302Sopenharmony_ci	const uint8_t *p = m;
137570af302Sopenharmony_ci	unsigned r = s->len % 64;
138570af302Sopenharmony_ci
139570af302Sopenharmony_ci	s->len += len;
140570af302Sopenharmony_ci	if (r) {
141570af302Sopenharmony_ci		if (len < 64 - r) {
142570af302Sopenharmony_ci			memcpy(s->buf + r, p, len);
143570af302Sopenharmony_ci			return;
144570af302Sopenharmony_ci		}
145570af302Sopenharmony_ci		memcpy(s->buf + r, p, 64 - r);
146570af302Sopenharmony_ci		len -= 64 - r;
147570af302Sopenharmony_ci		p += 64 - r;
148570af302Sopenharmony_ci		processblock(s, s->buf);
149570af302Sopenharmony_ci	}
150570af302Sopenharmony_ci	for (; len >= 64; len -= 64, p += 64)
151570af302Sopenharmony_ci		processblock(s, p);
152570af302Sopenharmony_ci	memcpy(s->buf, p, len);
153570af302Sopenharmony_ci}
154570af302Sopenharmony_ci
155570af302Sopenharmony_ci/*-
156570af302Sopenharmony_ci * Copyright (c) 2003 Poul-Henning Kamp
157570af302Sopenharmony_ci * All rights reserved.
158570af302Sopenharmony_ci *
159570af302Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
160570af302Sopenharmony_ci * modification, are permitted provided that the following conditions
161570af302Sopenharmony_ci * are met:
162570af302Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
163570af302Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
164570af302Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
165570af302Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
166570af302Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
167570af302Sopenharmony_ci *
168570af302Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
169570af302Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170570af302Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171570af302Sopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
172570af302Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
173570af302Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
174570af302Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
175570af302Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
176570af302Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
177570af302Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
178570af302Sopenharmony_ci * SUCH DAMAGE.
179570af302Sopenharmony_ci */
180570af302Sopenharmony_ci
181570af302Sopenharmony_ci/* key limit is not part of the original design, added for DoS protection */
182570af302Sopenharmony_ci#define KEY_MAX 30000
183570af302Sopenharmony_ci#define SALT_MAX 8
184570af302Sopenharmony_ci
185570af302Sopenharmony_cistatic const unsigned char b64[] =
186570af302Sopenharmony_ci"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
187570af302Sopenharmony_ci
188570af302Sopenharmony_cistatic char *to64(char *s, unsigned int u, int n)
189570af302Sopenharmony_ci{
190570af302Sopenharmony_ci	while (--n >= 0) {
191570af302Sopenharmony_ci		*s++ = b64[u % 64];
192570af302Sopenharmony_ci		u /= 64;
193570af302Sopenharmony_ci	}
194570af302Sopenharmony_ci	return s;
195570af302Sopenharmony_ci}
196570af302Sopenharmony_ci
197570af302Sopenharmony_cistatic char *md5crypt(const char *key, const char *setting, char *output)
198570af302Sopenharmony_ci{
199570af302Sopenharmony_ci	struct md5 ctx;
200570af302Sopenharmony_ci	unsigned char md[16];
201570af302Sopenharmony_ci	unsigned int i, klen, slen;
202570af302Sopenharmony_ci	const char *salt;
203570af302Sopenharmony_ci	char *p;
204570af302Sopenharmony_ci
205570af302Sopenharmony_ci	/* reject large keys */
206570af302Sopenharmony_ci	klen = strnlen(key, KEY_MAX+1);
207570af302Sopenharmony_ci	if (klen > KEY_MAX)
208570af302Sopenharmony_ci		return 0;
209570af302Sopenharmony_ci
210570af302Sopenharmony_ci	/* setting: $1$salt$ (closing $ is optional) */
211570af302Sopenharmony_ci	if (strncmp(setting, "$1$", 3) != 0)
212570af302Sopenharmony_ci		return 0;
213570af302Sopenharmony_ci	salt = setting + 3;
214570af302Sopenharmony_ci	for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++);
215570af302Sopenharmony_ci	slen = i;
216570af302Sopenharmony_ci
217570af302Sopenharmony_ci	/* md5(key salt key) */
218570af302Sopenharmony_ci	md5_init(&ctx);
219570af302Sopenharmony_ci	md5_update(&ctx, key, klen);
220570af302Sopenharmony_ci	md5_update(&ctx, salt, slen);
221570af302Sopenharmony_ci	md5_update(&ctx, key, klen);
222570af302Sopenharmony_ci	md5_sum(&ctx, md);
223570af302Sopenharmony_ci
224570af302Sopenharmony_ci	/* md5(key $1$ salt repeated-md weird-key[0]-0) */
225570af302Sopenharmony_ci	md5_init(&ctx);
226570af302Sopenharmony_ci	md5_update(&ctx, key, klen);
227570af302Sopenharmony_ci	md5_update(&ctx, setting, 3 + slen);
228570af302Sopenharmony_ci	for (i = klen; i > sizeof md; i -= sizeof md)
229570af302Sopenharmony_ci		md5_update(&ctx, md, sizeof md);
230570af302Sopenharmony_ci	md5_update(&ctx, md, i);
231570af302Sopenharmony_ci	md[0] = 0;
232570af302Sopenharmony_ci	for (i = klen; i; i >>= 1)
233570af302Sopenharmony_ci		if (i & 1)
234570af302Sopenharmony_ci			md5_update(&ctx, md, 1);
235570af302Sopenharmony_ci		else
236570af302Sopenharmony_ci			md5_update(&ctx, key, 1);
237570af302Sopenharmony_ci	md5_sum(&ctx, md);
238570af302Sopenharmony_ci
239570af302Sopenharmony_ci	/* md = f(md, key, salt) iteration */
240570af302Sopenharmony_ci	for (i = 0; i < 1000; i++) {
241570af302Sopenharmony_ci		md5_init(&ctx);
242570af302Sopenharmony_ci		if (i % 2)
243570af302Sopenharmony_ci			md5_update(&ctx, key, klen);
244570af302Sopenharmony_ci		else
245570af302Sopenharmony_ci			md5_update(&ctx, md, sizeof md);
246570af302Sopenharmony_ci		if (i % 3)
247570af302Sopenharmony_ci			md5_update(&ctx, salt, slen);
248570af302Sopenharmony_ci		if (i % 7)
249570af302Sopenharmony_ci			md5_update(&ctx, key, klen);
250570af302Sopenharmony_ci		if (i % 2)
251570af302Sopenharmony_ci			md5_update(&ctx, md, sizeof md);
252570af302Sopenharmony_ci		else
253570af302Sopenharmony_ci			md5_update(&ctx, key, klen);
254570af302Sopenharmony_ci		md5_sum(&ctx, md);
255570af302Sopenharmony_ci	}
256570af302Sopenharmony_ci
257570af302Sopenharmony_ci	/* output is $1$salt$hash */
258570af302Sopenharmony_ci	memcpy(output, setting, 3 + slen);
259570af302Sopenharmony_ci	p = output + 3 + slen;
260570af302Sopenharmony_ci	*p++ = '$';
261570af302Sopenharmony_ci	static const unsigned char perm[][3] = {
262570af302Sopenharmony_ci		0,6,12,1,7,13,2,8,14,3,9,15,4,10,5 };
263570af302Sopenharmony_ci	for (i=0; i<5; i++) p = to64(p,
264570af302Sopenharmony_ci		(md[perm[i][0]]<<16)|(md[perm[i][1]]<<8)|md[perm[i][2]], 4);
265570af302Sopenharmony_ci	p = to64(p, md[11], 2);
266570af302Sopenharmony_ci	*p = 0;
267570af302Sopenharmony_ci
268570af302Sopenharmony_ci	return output;
269570af302Sopenharmony_ci}
270570af302Sopenharmony_ci
271570af302Sopenharmony_cichar *__crypt_md5(const char *key, const char *setting, char *output)
272570af302Sopenharmony_ci{
273570af302Sopenharmony_ci	static const char testkey[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
274570af302Sopenharmony_ci	static const char testsetting[] = "$1$abcd0123$";
275570af302Sopenharmony_ci	static const char testhash[] = "$1$abcd0123$9Qcg8DyviekV3tDGMZynJ1";
276570af302Sopenharmony_ci	char testbuf[64];
277570af302Sopenharmony_ci	char *p, *q;
278570af302Sopenharmony_ci
279570af302Sopenharmony_ci	p = md5crypt(key, setting, output);
280570af302Sopenharmony_ci	/* self test and stack cleanup */
281570af302Sopenharmony_ci	q = md5crypt(testkey, testsetting, testbuf);
282570af302Sopenharmony_ci	if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash))
283570af302Sopenharmony_ci		return "*";
284570af302Sopenharmony_ci	return p;
285570af302Sopenharmony_ci}
286