diff options
Diffstat (limited to 'src/misc/crypt_sha256.c')
| -rw-r--r-- | src/misc/crypt_sha256.c | 322 | 
1 files changed, 0 insertions, 322 deletions
| diff --git a/src/misc/crypt_sha256.c b/src/misc/crypt_sha256.c deleted file mode 100644 index 2dc27ee7..00000000 --- a/src/misc/crypt_sha256.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * public domain sha256 crypt implementation - * - * original sha crypt design: http://people.redhat.com/drepper/SHA-crypt.txt - * in this implementation at least 32bit int is assumed, - * key length is limited, the $5$ prefix is mandatory, '\n' and ':' is rejected - * in the salt and rounds= setting must contain a valid iteration count, - * on error "*" is returned. - */ -#include <ctype.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stdint.h> - -/* public domain sha256 implementation based on fips180-3 */ - -struct sha256 { -	uint64_t len;    /* processed message length */ -	uint32_t h[8];   /* hash state */ -	uint8_t buf[64]; /* message block buffer */ -}; - -static uint32_t ror(uint32_t n, int k) { return (n >> k) | (n << (32-k)); } -#define Ch(x,y,z)  (z ^ (x & (y ^ z))) -#define Maj(x,y,z) ((x & y) | (z & (x | y))) -#define S0(x)      (ror(x,2) ^ ror(x,13) ^ ror(x,22)) -#define S1(x)      (ror(x,6) ^ ror(x,11) ^ ror(x,25)) -#define R0(x)      (ror(x,7) ^ ror(x,18) ^ (x>>3)) -#define R1(x)      (ror(x,17) ^ ror(x,19) ^ (x>>10)) - -static const uint32_t K[64] = { -0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, -0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, -0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, -0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, -0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, -0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, -0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, -0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -static void processblock(struct sha256 *s, const uint8_t *buf) -{ -	uint32_t W[64], t1, t2, a, b, c, d, e, f, g, h; -	int i; - -	for (i = 0; i < 16; i++) { -		W[i] = (uint32_t)buf[4*i]<<24; -		W[i] |= (uint32_t)buf[4*i+1]<<16; -		W[i] |= (uint32_t)buf[4*i+2]<<8; -		W[i] |= buf[4*i+3]; -	} -	for (; i < 64; i++) -		W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16]; -	a = s->h[0]; -	b = s->h[1]; -	c = s->h[2]; -	d = s->h[3]; -	e = s->h[4]; -	f = s->h[5]; -	g = s->h[6]; -	h = s->h[7]; -	for (i = 0; i < 64; i++) { -		t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i]; -		t2 = S0(a) + Maj(a,b,c); -		h = g; -		g = f; -		f = e; -		e = d + t1; -		d = c; -		c = b; -		b = a; -		a = t1 + t2; -	} -	s->h[0] += a; -	s->h[1] += b; -	s->h[2] += c; -	s->h[3] += d; -	s->h[4] += e; -	s->h[5] += f; -	s->h[6] += g; -	s->h[7] += h; -} - -static void pad(struct sha256 *s) -{ -	unsigned r = s->len % 64; - -	s->buf[r++] = 0x80; -	if (r > 56) { -		memset(s->buf + r, 0, 64 - r); -		r = 0; -		processblock(s, s->buf); -	} -	memset(s->buf + r, 0, 56 - r); -	s->len *= 8; -	s->buf[56] = s->len >> 56; -	s->buf[57] = s->len >> 48; -	s->buf[58] = s->len >> 40; -	s->buf[59] = s->len >> 32; -	s->buf[60] = s->len >> 24; -	s->buf[61] = s->len >> 16; -	s->buf[62] = s->len >> 8; -	s->buf[63] = s->len; -	processblock(s, s->buf); -} - -static void sha256_init(struct sha256 *s) -{ -	s->len = 0; -	s->h[0] = 0x6a09e667; -	s->h[1] = 0xbb67ae85; -	s->h[2] = 0x3c6ef372; -	s->h[3] = 0xa54ff53a; -	s->h[4] = 0x510e527f; -	s->h[5] = 0x9b05688c; -	s->h[6] = 0x1f83d9ab; -	s->h[7] = 0x5be0cd19; -} - -static void sha256_sum(struct sha256 *s, uint8_t md[20]) -{ -	int i; - -	pad(s); -	for (i = 0; i < 8; i++) { -		md[4*i] = s->h[i] >> 24; -		md[4*i+1] = s->h[i] >> 16; -		md[4*i+2] = s->h[i] >> 8; -		md[4*i+3] = s->h[i]; -	} -} - -static void sha256_update(struct sha256 *s, const void *m, unsigned long len) -{ -	const uint8_t *p = m; -	unsigned r = s->len % 64; - -	s->len += len; -	if (r) { -		if (len < 64 - r) { -			memcpy(s->buf + r, p, len); -			return; -		} -		memcpy(s->buf + r, p, 64 - r); -		len -= 64 - r; -		p += 64 - r; -		processblock(s, s->buf); -	} -	for (; len >= 64; len -= 64, p += 64) -		processblock(s, p); -	memcpy(s->buf, p, len); -} - -static unsigned char b64[] = -"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static char *to64(char *s, unsigned int u, int n) -{ -	while (--n >= 0) { -		*s++ = b64[u % 64]; -		u /= 64; -	} -	return s; -} - -/* key limit is not part of the original design, added for DoS protection. - * rounds limit has been lowered (versus the reference/spec), also for DoS - * protection. runtime is O(klen^2 + klen*rounds) */ -#define KEY_MAX 256 -#define SALT_MAX 16 -#define ROUNDS_DEFAULT 5000 -#define ROUNDS_MIN 1000 -#define ROUNDS_MAX 50000 - -/* hash n bytes of the repeated md message digest */ -static void hashmd(struct sha256 *s, unsigned int n, const void *md) -{ -	unsigned int i; - -	for (i = n; i > 32; i -= 32) -		sha256_update(s, md, 32); -	sha256_update(s, md, i); -} - -static char *sha256crypt(const char *key, const char *setting, char *output) -{ -	struct sha256 ctx; -	unsigned char md[32], kmd[32], smd[32]; -	unsigned int i, r, klen, slen; -	char rounds[20] = ""; -	const char *salt; -	char *p; - -	/* reject large keys */ -	klen = strnlen(key, KEY_MAX+1); -	if (klen > KEY_MAX) -		return 0; - -	/* setting: $5$rounds=n$salt$ (rounds=n$ and closing $ are optional) */ -	if (strncmp(setting, "$5$", 3) != 0) -		return 0; -	salt = setting + 3; - -	r = ROUNDS_DEFAULT; -	if (strncmp(salt, "rounds=", sizeof "rounds=" - 1) == 0) { -		unsigned long u; -		char *end; - -		/* -		 * this is a deviation from the reference: -		 * bad rounds setting is rejected if it is -		 * - empty -		 * - unterminated (missing '$') -		 * - begins with anything but a decimal digit -		 * the reference implementation treats these bad -		 * rounds as part of the salt or parse them with -		 * strtoul semantics which may cause problems -		 * including non-portable hashes that depend on -		 * the host's value of ULONG_MAX. -		 */ -		salt += sizeof "rounds=" - 1; -		if (!isdigit(*salt)) -			return 0; -		u = strtoul(salt, &end, 10); -		if (*end != '$') -			return 0; -		salt = end+1; -		if (u < ROUNDS_MIN) -			r = ROUNDS_MIN; -		else if (u > ROUNDS_MAX) -			r = ROUNDS_MAX; -		else -			r = u; -		/* needed when rounds is zero prefixed or out of bounds */ -		sprintf(rounds, "rounds=%u$", r); -	} - -	for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++) -		/* reject characters that interfere with /etc/shadow parsing */ -		if (salt[i] == '\n' || salt[i] == ':') -			return 0; -	slen = i; - -	/* B = sha(key salt key) */ -	sha256_init(&ctx); -	sha256_update(&ctx, key, klen); -	sha256_update(&ctx, salt, slen); -	sha256_update(&ctx, key, klen); -	sha256_sum(&ctx, md); - -	/* A = sha(key salt repeat-B alternate-B-key) */ -	sha256_init(&ctx); -	sha256_update(&ctx, key, klen); -	sha256_update(&ctx, salt, slen); -	hashmd(&ctx, klen, md); -	for (i = klen; i > 0; i >>= 1) -		if (i & 1) -			sha256_update(&ctx, md, sizeof md); -		else -			sha256_update(&ctx, key, klen); -	sha256_sum(&ctx, md); - -	/* DP = sha(repeat-key), this step takes O(klen^2) time */ -	sha256_init(&ctx); -	for (i = 0; i < klen; i++) -		sha256_update(&ctx, key, klen); -	sha256_sum(&ctx, kmd); - -	/* DS = sha(repeat-salt) */ -	sha256_init(&ctx); -	for (i = 0; i < 16 + md[0]; i++) -		sha256_update(&ctx, salt, slen); -	sha256_sum(&ctx, smd); - -	/* iterate A = f(A,DP,DS), this step takes O(rounds*klen) time */ -	for (i = 0; i < r; i++) { -		sha256_init(&ctx); -		if (i % 2) -			hashmd(&ctx, klen, kmd); -		else -			sha256_update(&ctx, md, sizeof md); -		if (i % 3) -			sha256_update(&ctx, smd, slen); -		if (i % 7) -			hashmd(&ctx, klen, kmd); -		if (i % 2) -			sha256_update(&ctx, md, sizeof md); -		else -			hashmd(&ctx, klen, kmd); -		sha256_sum(&ctx, md); -	} - -	/* output is $5$rounds=n$salt$hash */ -	p = output; -	p += sprintf(p, "$5$%s%.*s$", rounds, slen, salt); -	static const unsigned char perm[][3] = { -		0,10,20,21,1,11,12,22,2,3,13,23,24,4,14, -		15,25,5,6,16,26,27,7,17,18,28,8,9,19,29 }; -	for (i=0; i<10; i++) p = to64(p, -		(md[perm[i][0]]<<16)|(md[perm[i][1]]<<8)|md[perm[i][2]], 4); -	p = to64(p, (md[31]<<8)|md[30], 3); -	*p = 0; -	return output; -} - -char *__crypt_sha256(const char *key, const char *setting, char *output) -{ -	static const char testkey[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !"; -	static const char testsetting[] = "$5$rounds=1234$abc0123456789$"; -	static const char testhash[] = "$5$rounds=1234$abc0123456789$3VfDjPt05VHFn47C/ojFZ6KRPYrOjj1lLbH.dkF3bZ6"; -	char testbuf[128]; -	char *p, *q; - -	p = sha256crypt(key, setting, output); -	/* self test and stack cleanup */ -	q = sha256crypt(testkey, testsetting, testbuf); -	if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash)) -		return "*"; -	return p; -} | 
