crypt: updated/refactored pw hashing function

- updated to recent busybox version
- removed compiler warnings
- properly implemented missing lib functions
This commit is contained in:
Rene Straub 2019-11-11 07:43:39 +01:00
parent 05e24f04fe
commit 1ada49ca8c
1 changed files with 136 additions and 94 deletions

View File

@ -1,26 +1,20 @@
#include <common.h> /*
#include <u-boot/sha256.h> * The crypt source code was ported from busybox sources pw_crypt, file
#include <malloc.h> * libbb/pw_encrypt_sha.c
#include <linux/types.h> *
* 20191108rs: Update to Busybox commit 49ecee0 (Jan 24, 2017)
/* The crypt source code was ported from busybox sources pw_crypt */ * Major cleanup, provide missing functions
*/
/* 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;
}
/* SHA256 and SHA512-based Unix crypt implementation. /* SHA256 and SHA512-based Unix crypt implementation.
* Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>. * Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>.
*/ */
#include <common.h>
#include <u-boot/sha256.h>
#include <malloc.h>
#include <linux/types.h>
/* Prefix for optional rounds specification. */ /* Prefix for optional rounds specification. */
static const char str_rounds[] = "rounds=%u$"; static const char str_rounds[] = "rounds=%u$";
@ -33,50 +27,111 @@ static const char str_rounds[] = "rounds=%u$";
/* Maximum number of rounds. */ /* Maximum number of rounds. */
#define ROUNDS_MAX 999999999 #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_begin)(void *ctx);
void (*sha_hash)(void *ctx, const void *buffer, size_t len); 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; int _32or64;
char *result, *resptr; char *result, *resptr;
/* btw, sha256 needs [32] and uint32_t only */ /* btw, sha256 needs [32] and uint32_t only */
unsigned char alt_result[64] __attribute__((__aligned__(__alignof__(uint64_t)))); struct {
unsigned char temp_result[64] __attribute__((__aligned__(__alignof__(uint64_t)))); unsigned char alt_result[64];
union { unsigned char temp_result[64];
sha256_context x; union {
#if 0 sha256_context x;
sha512_ctx_t y; /* sha512_ctx_t y; */
#endif } ctx;
} ctx; union {
union { sha256_context x;
sha256_context x; /* sha512_ctx_t y; */
#if 0 } alt_ctx;
sha512_ctx_t y; } L;
#endif #define alt_result (L.alt_result )
} alt_ctx; #define temp_result (L.temp_result)
#define ctx (L.ctx )
#define alt_ctx (L.alt_ctx )
unsigned salt_len; unsigned salt_len;
unsigned key_len; unsigned key_len;
unsigned cnt; unsigned cnt;
unsigned rounds; unsigned rounds;
char *cp; char *cp;
char is_sha512;
char *tmp;
/* Analyze salt, construct already known part of result */ /* Analyze salt, construct already known part of result */
cnt = strlen(salt_data) + 1 + 43 + 1; cnt = strlen(salt_data) + 1 + 43 + 1;
is_sha512 = salt_data[1]; _32or64 = 32;
if (is_sha512 == '6') { if (salt_data[1] == '6') { /* sha512 */
printf("SHA-512 is not supported yet"); _32or64 *= 2; /*64*/
return 0; cnt += 43;
/* cnt += 43; */ puts("SHA-512 is not supported");
} return 0;
result = resptr = malloc(cnt); /* will provide NUL terminator */ }
memset(result, 0, cnt); result = resptr = xzalloc(cnt); /* will provide NUL terminator */
*resptr++ = '$'; *resptr++ = '$';
*resptr++ = is_sha512; *resptr++ = salt_data[1];
*resptr++ = '$'; *resptr++ = '$';
rounds = ROUNDS_DEFAULT; rounds = ROUNDS_DEFAULT;
salt_data += 3; salt_data += 3;
@ -95,47 +150,39 @@ char *sha_crypt(const char *key_data, const char *salt_data)
resptr += sprintf(resptr, str_rounds, rounds); resptr += sprintf(resptr, str_rounds, rounds);
} }
} }
{
char *salt_end = strchr(salt_data, '$'); salt_len = (int)strchrnul(salt_data, '$') - (int)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;
if (salt_len > SALT_LEN_MAX) if (salt_len > SALT_LEN_MAX)
salt_len = SALT_LEN_MAX; salt_len = SALT_LEN_MAX;
/* xstrdup assures suitable alignment; also we will use it /* xstrdup assures suitable alignment; also we will use it
as a scratch space later. */ as a scratch space later. */
tmp = malloc(strnlen(salt_data, 128));
memcpy(tmp, salt_data, strnlen(salt_data, 128)); /* NOTE: Something is wrong here.
salt_data = tmp; * when <salt_len> bytes are reserved there is a problem later in
//salt_data = xstrndup(salt_data, salt_len); * 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 */ /* add "salt$" to result */
strcpy(resptr, salt_data); strcpy(resptr, salt_data);
resptr += salt_len; resptr += salt_len;
*resptr++ = '$'; *resptr++ = '$';
/* key data doesn't need much processing */ /* key data doesn't need much processing */
key_len = strlen(key_data); key_len = strlen(key_data);
tmp = malloc(strnlen(key_data, 256)); key_data = xstrdup(key_data);
memcpy(tmp, key_data, strnlen(key_data, 256));
key_data = tmp;
// key_data = xstrdup(key_data);
/* Which flavor of SHAnnn ops to use? */ /* Which flavor of SHAnnn ops to use? */
sha_begin = (void*)sha256_starts; sha_begin = (void*)sha256_starts;
sha_hash = (void*)sha256_update; sha_hash = (void*)sha256_update;
sha_end = (void*)sha256_finish; sha_end = (void*)sha256_finish;
_32or64 = 32;
/* Not supported */
#if 0 #if 0
if (is_sha512 == '6') { /* SHA512 not supported */
if (_32or64 != 32) {
sha_begin = (void*)sha512_begin; sha_begin = (void*)sha512_begin;
sha_hash = (void*)sha512_hash; sha_hash = (void*)sha512_hash;
sha_end = (void*)sha512_end; sha_end = (void*)sha512_end;
_32or64 = 64;
} }
#endif #endif
@ -230,35 +277,30 @@ char *sha_crypt(const char *key_data, const char *salt_data)
sha_end(&ctx, alt_result); sha_end(&ctx, alt_result);
} }
/* Append encrypted password to result buffer */ /* Append encrypted password to result buffer */
//TODO: replace with something like //TODO: replace with something like
// bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64); // bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64);
#define b64_from_24bit(B2, B1, B0, N) \ #define b64_from_24bit(B2, B1, B0, N) \
do { \ do { \
unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \
resptr = to64(resptr, w, N); \ resptr = to64(resptr, w, N); \
} while (0) } while (0)
if (is_sha512 == '5') { if (_32or64 == 32) { /* sha256 */
unsigned i = 0; 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) { 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); b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4);
if (i == 9) if (k == 29)
break; break;
i += 21; i = (((i >> 4) & 2) + i) & 0x1f; i = k + 1;
j += 21; j = (((j >> 4) & 2) + j) & 0x1f;
k += 21; k = (((k >> 4) & 2) + k) & 0x1f;
} }
b64_from_24bit(0, alt_result_31, alt_result[30], 3); b64_from_24bit(0, alt_result[31], alt_result[30], 3);
/* was: /* was:
b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4); 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); 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[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[3], alt_result[13], alt_result[23], 4);
b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4); b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4);
@ -271,15 +313,15 @@ do { \
*/ */
} else { } else {
unsigned i = 0; unsigned i = 0;
unsigned j = 21;
unsigned k = 42;
while (1) { 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); b64_from_24bit(alt_result[i], alt_result[j], alt_result[k], 4);
if (i == 62) if (j == 20)
break; break;
i += 22; i = ((i >> 6) + i) & 0x3f; i = j + 1;
j += 22; j = ((j >> 6) + j) & 0x3f;
k += 22; k = ((k >> 6) + k) & 0x3f;
} }
b64_from_24bit(0, 0, alt_result[63], 2); b64_from_24bit(0, 0, alt_result[63], 2);
/* was: /* was:
@ -313,10 +355,7 @@ do { \
/* Clear the buffer for the intermediate result so that people /* Clear the buffer for the intermediate result so that people
attaching to processes or reading core dumps cannot get any attaching to processes or reading core dumps cannot get any
information. */ information. */
memset(temp_result, 0, sizeof(temp_result)); memset(&L, 0, sizeof(L)); /* [alt]_ctx and XXX_result buffers */
memset(alt_result, 0, sizeof(alt_result));
memset(&ctx, 0, sizeof(ctx));
memset(&alt_ctx, 0, sizeof(alt_ctx));
memset(key_data, 0, key_len); /* also p_bytes */ memset(key_data, 0, key_len); /* also p_bytes */
memset(salt_data, 0, salt_len); /* also s_bytes */ memset(salt_data, 0, salt_len); /* also s_bytes */
free(key_data); free(key_data);
@ -325,5 +364,8 @@ do { \
#undef s_bytes #undef s_bytes
return result; return result;
#undef alt_result
#undef temp_result
#undef ctx
#undef alt_ctx
} }