From 1ada49ca8c4b17cf4568490d9b008d1558927baa Mon Sep 17 00:00:00 2001 From: Rene Straub Date: Mon, 11 Nov 2019 07:43:39 +0100 Subject: [PATCH] crypt: updated/refactored pw hashing function - updated to recent busybox version - removed compiler warnings - properly implemented missing lib functions --- lib/crypt.c | 230 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 136 insertions(+), 94 deletions(-) diff --git a/lib/crypt.c b/lib/crypt.c index 1bc19b4183..ed9035fab1 100755 --- a/lib/crypt.c +++ b/lib/crypt.c @@ -1,26 +1,20 @@ -#include -#include -#include -#include - -/* The crypt source code was ported from busybox sources pw_crypt */ - -/* Used by pw_encrypt_XXX.c */ -static const uint8_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -static char* -to64(char *s, unsigned v, int n) -{ - while (--n >= 0) { - *s++ = ascii64[v & 0x3f]; - v >>= 6; - } - return s; -} +/* + * The crypt source code was ported from busybox sources pw_crypt, file + * libbb/pw_encrypt_sha.c + * + * 20191108rs: Update to Busybox commit 49ecee0 (Jan 24, 2017) + * Major cleanup, provide missing functions + */ /* SHA256 and SHA512-based Unix crypt implementation. * Released into the Public Domain by Ulrich Drepper . */ +#include +#include +#include +#include + /* Prefix for optional rounds specification. */ static const char str_rounds[] = "rounds=%u$"; @@ -33,50 +27,111 @@ static const char str_rounds[] = "rounds=%u$"; /* Maximum number of rounds. */ #define ROUNDS_MAX 999999999 -char *sha_crypt(const char *key_data, const char *salt_data) + +/* Missing busybox functions */ + +static char* to64(char *s, unsigned v, int n) +{ + static const uint8_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + while (--n >= 0) { + *s++ = ascii64[v & 0x3f]; + v >>= 6; + } + return s; +} + +void* xzalloc(size_t size) +{ + void *ptr = malloc(size); + /* note: error check left out */ + + memset(ptr, 0, size); + return ptr; +} + +static char *xstrdup(const char *s) +{ + size_t len = strlen (s) + 1; + char *ret = malloc (len); + /* note: error check left out */ + + memcpy (ret, s, len); + return ret; +} + +#if 0 /* currently not required, see note below */ +static char *xstrndup(const char *s, size_t n) +{ + char *result; + size_t len = strlen (s); + + if (n < len) + len = n; + + printf("allocating %d bytes\n", len+1); + + result = malloc (len + 1); + /* note: error check left out */ + + result[len] = '\0'; + memcpy (result, s, len); + return (char *)result; +} +#endif + +static char *strchrnul(const char *s, int c) +{ + while (*s && *s != (char)c) + s++; + return (char *)s; +} + + +char *sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) { void (*sha_begin)(void *ctx); void (*sha_hash)(void *ctx, const void *buffer, size_t len); - void* (*sha_end)( void *ctx, void *resbuf); + void (*sha_end)(void *ctx, void *resbuf); int _32or64; char *result, *resptr; /* btw, sha256 needs [32] and uint32_t only */ - unsigned char alt_result[64] __attribute__((__aligned__(__alignof__(uint64_t)))); - unsigned char temp_result[64] __attribute__((__aligned__(__alignof__(uint64_t)))); - union { - sha256_context x; - #if 0 - sha512_ctx_t y; - #endif - } ctx; - union { - sha256_context x; - #if 0 - sha512_ctx_t y; - #endif - } alt_ctx; + struct { + unsigned char alt_result[64]; + unsigned char temp_result[64]; + union { + sha256_context x; +/* sha512_ctx_t y; */ + } ctx; + union { + sha256_context x; +/* sha512_ctx_t y; */ + } alt_ctx; + } L; +#define alt_result (L.alt_result ) +#define temp_result (L.temp_result) +#define ctx (L.ctx ) +#define alt_ctx (L.alt_ctx ) unsigned salt_len; unsigned key_len; unsigned cnt; unsigned rounds; char *cp; - char is_sha512; - char *tmp; /* Analyze salt, construct already known part of result */ cnt = strlen(salt_data) + 1 + 43 + 1; - is_sha512 = salt_data[1]; - if (is_sha512 == '6') { - printf("SHA-512 is not supported yet"); - return 0; - /* cnt += 43; */ - } - result = resptr = malloc(cnt); /* will provide NUL terminator */ - memset(result, 0, cnt); + _32or64 = 32; + if (salt_data[1] == '6') { /* sha512 */ + _32or64 *= 2; /*64*/ + cnt += 43; + puts("SHA-512 is not supported"); + return 0; + } + result = resptr = xzalloc(cnt); /* will provide NUL terminator */ *resptr++ = '$'; - *resptr++ = is_sha512; + *resptr++ = salt_data[1]; *resptr++ = '$'; rounds = ROUNDS_DEFAULT; salt_data += 3; @@ -95,47 +150,39 @@ char *sha_crypt(const char *key_data, const char *salt_data) resptr += sprintf(resptr, str_rounds, rounds); } } - { - char *salt_end = strchr(salt_data, '$'); - if (salt_end != 0) { - salt_len = salt_end - salt_data; - } - else { - salt_len = strnlen(salt_data, SALT_LEN_MAX); - } - } - // salt_len = (int)strchrnul(salt_data, '$') - (int)salt_data; + + salt_len = (int)strchrnul(salt_data, '$') - (int)salt_data; if (salt_len > SALT_LEN_MAX) salt_len = SALT_LEN_MAX; /* xstrdup assures suitable alignment; also we will use it as a scratch space later. */ - tmp = malloc(strnlen(salt_data, 128)); - memcpy(tmp, salt_data, strnlen(salt_data, 128)); - salt_data = tmp; - //salt_data = xstrndup(salt_data, salt_len); + + /* NOTE: Something is wrong here. + * when bytes are reserved there is a problem later in + * the code and computations are incorrect. + * So far it is not clear what the root problem is. + * By not truncating the buffer the code works fine + */ +/* salt_data = xstrndup(salt_data, salt_len); */ + salt_data = xstrdup(salt_data); /* add "salt$" to result */ strcpy(resptr, salt_data); resptr += salt_len; *resptr++ = '$'; /* key data doesn't need much processing */ key_len = strlen(key_data); - tmp = malloc(strnlen(key_data, 256)); - memcpy(tmp, key_data, strnlen(key_data, 256)); - key_data = tmp; - // key_data = xstrdup(key_data); + key_data = xstrdup(key_data); /* Which flavor of SHAnnn ops to use? */ sha_begin = (void*)sha256_starts; sha_hash = (void*)sha256_update; sha_end = (void*)sha256_finish; - _32or64 = 32; - /* Not supported */ #if 0 - if (is_sha512 == '6') { + /* SHA512 not supported */ + if (_32or64 != 32) { sha_begin = (void*)sha512_begin; sha_hash = (void*)sha512_hash; sha_end = (void*)sha512_end; - _32or64 = 64; } #endif @@ -230,35 +277,30 @@ char *sha_crypt(const char *key_data, const char *salt_data) sha_end(&ctx, alt_result); } - /* Append encrypted password to result buffer */ //TODO: replace with something like // bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64); #define b64_from_24bit(B2, B1, B0, N) \ -do { \ - unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ - resptr = to64(resptr, w, N); \ +do { \ + unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ + resptr = to64(resptr, w, N); \ } while (0) - if (is_sha512 == '5') { + if (_32or64 == 32) { /* sha256 */ unsigned i = 0; - unsigned j = 10; - unsigned k = 20; - /* strange swap of one byte (see below why) */ - unsigned char alt_result_31 = alt_result[31]; - alt_result[31] = alt_result[1]; while (1) { + unsigned j = i + 10; + unsigned k = i + 20; + if (j >= 30) j -= 30; + if (k >= 30) k -= 30; b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4); - if (i == 9) + if (k == 29) break; - i += 21; i = (((i >> 4) & 2) + i) & 0x1f; - j += 21; j = (((j >> 4) & 2) + j) & 0x1f; - k += 21; k = (((k >> 4) & 2) + k) & 0x1f; + i = k + 1; } - b64_from_24bit(0, alt_result_31, alt_result[30], 3); + b64_from_24bit(0, alt_result[31], alt_result[30], 3); /* was: b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4); b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4); - ...............................^^^^^^^^^^^^^ why [1] and not [31]? b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4); b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4); b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4); @@ -271,15 +313,15 @@ do { \ */ } else { unsigned i = 0; - unsigned j = 21; - unsigned k = 42; while (1) { + unsigned j = i + 21; + unsigned k = i + 42; + if (j >= 63) j -= 63; + if (k >= 63) k -= 63; b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4); - if (i == 62) + if (j == 20) break; - i += 22; i = ((i >> 6) + i) & 0x3f; - j += 22; j = ((j >> 6) + j) & 0x3f; - k += 22; k = ((k >> 6) + k) & 0x3f; + i = j + 1; } b64_from_24bit(0, 0, alt_result[63], 2); /* was: @@ -313,10 +355,7 @@ do { \ /* Clear the buffer for the intermediate result so that people attaching to processes or reading core dumps cannot get any information. */ - memset(temp_result, 0, sizeof(temp_result)); - memset(alt_result, 0, sizeof(alt_result)); - memset(&ctx, 0, sizeof(ctx)); - memset(&alt_ctx, 0, sizeof(alt_ctx)); + memset(&L, 0, sizeof(L)); /* [alt]_ctx and XXX_result buffers */ memset(key_data, 0, key_len); /* also p_bytes */ memset(salt_data, 0, salt_len); /* also s_bytes */ free(key_data); @@ -325,5 +364,8 @@ do { \ #undef s_bytes return result; +#undef alt_result +#undef temp_result +#undef ctx +#undef alt_ctx } -