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