--- blowfish-bcrypt.c | 85 ++++++++++++++++++++++++++--------------------- blowfish.h | 14 ++++---- nettle.texinfo | 27 ++++++++------- 3 files changed, 71 insertions(+), 55 deletions(-)
diff --git a/blowfish-bcrypt.c b/blowfish-bcrypt.c index c06f9e90..bfee8e44 100644 --- a/blowfish-bcrypt.c +++ b/blowfish-bcrypt.c @@ -76,14 +76,15 @@ static const char radix64_encode_table[64] = "0123456789";
int -blowfish_bcrypt_verify(const char *key, - const char *hashed) +blowfish_bcrypt_verify(size_t lenkey, const uint8_t *key, + size_t lenhashed, const uint8_t *hashed) { - char newhash[BLOWFISH_BCRYPT_HASH_SIZE]; + uint8_t newhash[BLOWFISH_BCRYPT_HASH_SIZE];
- return blowfish_bcrypt_hash(sizeof newhash, - newhash, key, hashed, -1, (void*)0) - && !strcmp(newhash, hashed); + return blowfish_bcrypt_hash(newhash, + lenkey, key, lenhashed, hashed, + -1, (void*)0) + && !strcmp((const char*)newhash, (const char*)hashed); }
static char *encode_radix64(char *dst, size_t len, const uint8_t *src) @@ -159,10 +160,12 @@ static void swap32(uint32_t *x, int count) #endif }
-static void set_xkey(const char *key, bf_key expanded, bf_key initial, - unsigned bug, uint32_t safety) +static void set_xkey(size_t lenkey, const uint8_t *key, + bf_key expanded, bf_key initial, + unsigned bug, uint32_t safety) { - const char *ptr = key; + const uint8_t *ptr = key; + size_t n = lenkey; unsigned i, j; uint32_t sign, diff, tmp[2];
@@ -219,10 +222,10 @@ static void set_xkey(const char *key, bf_key expanded, bf_key initial, */ if (j) sign |= tmp[1] & 0x80; - if (!*ptr) - ptr = key; - else + if (n--) ptr++; + else + ptr = key, n = lenkey; } diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
@@ -259,8 +262,9 @@ static void set_xkey(const char *key, bf_key expanded, bf_key initial, initial[0] ^= sign; }
-static int ibcrypt(size_t length, char *dst, - const char *key, const char *scheme, +static int ibcrypt(uint8_t *dst, + size_t lenkey, const uint8_t *key, + size_t lenscheme, const uint8_t *scheme, int minlog2rounds, int log2rounds, const uint8_t *salt) { @@ -277,12 +281,10 @@ static int ibcrypt(size_t length, char *dst, uint32_t *ptr; uint32_t count; int i; - size_t lenscheme = strlen(scheme); unsigned cscheme; unsigned bug = 0; uint32_t safety = 0; - if (length < BLOWFISH_BCRYPT_HASH_SIZE || - lenscheme < 2) + if (lenscheme < 2) return 0;
if (lenscheme >= 3 && *scheme++ != '$') @@ -305,8 +307,16 @@ static int ibcrypt(size_t length, char *dst, if (*scheme++ != '$') return 0; if (lenscheme >= 6) { - if (log2rounds < 0) - log2rounds = atoi(scheme); + if (log2rounds < 0) { + unsigned c = *scheme - '0'; + if (c > 9) + return 0; + log2rounds = c * 10; + c = *scheme - '0'; + if (c > 9) + return 0; + log2rounds += c; + } scheme += 2; if (lenscheme >= CRYPTPLEN && *scheme++ != '$') return 0; @@ -318,7 +328,7 @@ static int ibcrypt(size_t length, char *dst, ctx.table = radix64_decode_table;
if (!base64_decode_update(&ctx, &saltlen, (uint8_t *) data.binary.salt, - SALTLEN, scheme) + SALTLEN, (const char*) scheme) || saltlen != BLOWFISH_BCRYPT_BINSALT_SIZE) return 0; } @@ -336,7 +346,7 @@ static int ibcrypt(size_t length, char *dst, return 0; count = (uint32_t)1 << log2rounds;
- set_xkey(key, data.expanded_key, data.ctx.p, bug, safety); + set_xkey(lenkey, key, data.expanded_key, data.ctx.p, bug, safety); memcpy(data.ctx.s, _nettle_blowfish_initial_ctx.s, sizeof(data.ctx.s));
L = R = 0; @@ -432,12 +442,13 @@ static int ibcrypt(size_t length, char *dst, *dst++ = '0' + log2rounds / 10; *dst++ = '0' + log2rounds % 10; *dst++ = '$'; - dst = encode_radix64(dst, BLOWFISH_BCRYPT_BINSALT_SIZE, psalt) - 1; + dst = (uint8_t*) + encode_radix64((char*) dst, BLOWFISH_BCRYPT_BINSALT_SIZE, psalt) - 1;
swap32(data.binary.output, 6); /* This has to be bug-compatible with the original implementation, so only encode 23 of the 24 bytes. */ - encode_radix64(dst, 23, (uint8_t *) data.binary.output); + encode_radix64((char*) dst, 23, (uint8_t *) data.binary.output); return cscheme; }
@@ -461,12 +472,13 @@ static int ibcrypt(size_t length, char *dst, * The performance cost of this quick self-test is around 0.6% at the "$2a$08" * setting. */ -int blowfish_bcrypt_hash(size_t length, char *dst, - const char *key, const char *scheme, +int blowfish_bcrypt_hash(uint8_t *dst, + size_t lenkey, const uint8_t *key, + size_t lenscheme, const uint8_t *scheme, int log2rounds, const uint8_t *salt) { - const char *test_pw = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; - const char *test_scheme = "$2a$00$abcdefghijklmnopqrstuu"; + const uint8_t test_pw[] = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; + const uint8_t test_scheme[] = "$2a$00$abcdefghijklmnopqrstuu"; static const char * const test_hashes[2] = {"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */ "VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */ @@ -474,14 +486,13 @@ int blowfish_bcrypt_hash(size_t length, char *dst, int cscheme; int ok; struct { - char s[HASHOFFSET + 1]; - char o[HASHOFFSET + 31 + 1 + 1 + 1]; + uint8_t s[HASHOFFSET + 1]; + uint8_t o[HASHOFFSET + 31 + 1 + 1 + 1]; } buf;
- if (length) - *dst = '\0'; + *dst = '\0'; /* Hash the supplied password */ - cscheme = ibcrypt(length, dst, key, scheme, 4, log2rounds, salt); + cscheme = ibcrypt(dst, lenkey, key, lenscheme, scheme, 4, log2rounds, salt);
/* * Do a quick self-test. It is important that we make both calls to ibcrypt() @@ -497,18 +508,18 @@ int blowfish_bcrypt_hash(size_t length, char *dst,
memset(buf.o, 0x55, sizeof(buf.o)); buf.o[sizeof(buf.o) - 1] = 0; - ok = ibcrypt(sizeof(buf.o) - (1 + 1), buf.o, test_pw, - buf.s, 0, -1, (void*)0); + ok = ibcrypt(buf.o, sizeof(test_pw), test_pw, + sizeof(buf.s), buf.s, 0, -1, (void*)0);
ok = (ok && !memcmp(buf.o, buf.s, HASHOFFSET) && !memcmp(buf.o + HASHOFFSET, test_hash, 31 + 1 + 1 + 1));
{ - const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; + const uint8_t k[] = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; bf_key ae, ai, ye, yi; - set_xkey(k, ae, ai, 0, 0x10000); /* $2a$ */ - set_xkey(k, ye, yi, 0, 0); /* $2y$ */ + set_xkey(sizeof(k), k, ae, ai, 0, 0x10000); /* $2a$ */ + set_xkey(sizeof(k), k, ye, yi, 0, 0); /* $2y$ */ ai[0] ^= 0x10000; /* undo the safety (for comparison) */ ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && !memcmp(ae, ye, sizeof(ae)) && diff --git a/blowfish.h b/blowfish.h index af48e20f..01813cbc 100644 --- a/blowfish.h +++ b/blowfish.h @@ -86,16 +86,18 @@ void blowfish_decrypt(const struct blowfish_ctx *ctx, size_t length, uint8_t *dst, const uint8_t *src); + +/* dst parameter must point to a buffer of minimally + * BLOWFISH_BCRYPT_HASH_SIZE bytes */ int -blowfish_bcrypt_hash(size_t length, - char *dst, - const char *key, - const char *scheme, +blowfish_bcrypt_hash(uint8_t *dst, + size_t lenkey, const uint8_t *key, + size_t lenscheme, const uint8_t *scheme, int log2rounds, const uint8_t *salt); int -blowfish_bcrypt_verify(const char *key, - const char *hashed); +blowfish_bcrypt_verify(size_t lenkey, const uint8_t *key, + size_t lenhashed, const uint8_t *hashed);
#ifdef __cplusplus } diff --git a/nettle.texinfo b/nettle.texinfo index 75e18b58..2269e11d 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -1513,7 +1513,7 @@ in any other way. Analogous to @code{blowfish_encrypt} @end deftypefun
-@deftypefun int blowfish_bcrypt_hash (size_t @var{length}, char *@var{dst}, const char *@var{key}, const char *@var{scheme}, int @var{log2rounds}, const uint8_t *@var{salt}) +@deftypefun int blowfish_bcrypt_hash (char *@var{dst}, size_t @var{lenkey}, const char *@var{key}, size_t @var{lenscheme}, const char *@var{scheme}, int @var{log2rounds}, const uint8_t *@var{salt}) Compute the bcrypt password hash. The function will return @code{0} if the hash cannot be computed due to invalid input. @@ -1522,13 +1522,13 @@ in the array pointed to by @var{dst}. The hash is computed based on the chosen @var{scheme}, number of rounds @var{log2rounds} and specified @var{salt}.
-@var{length} must be at least @code{BLOWFISH_BCRYPT_HASH_SIZE}. +@var{dst} must point to a character array of at least + @code{BLOWFISH_BCRYPT_HASH_SIZE} bytes.
-@var{dst} must point to a character array of the specified @var{length}. +@var{key} contains the plaintext password string of size @var{lenkey}.
-@var{key} contains the zero terminated plaintext password string. - -@var{scheme} contains either just the chosen scheme (valid schemes +@var{scheme} is of size @var{lenscheme} and contains either just the +chosen scheme (valid schemes are: @code{2a}, @code{2b}, @code{2x} or @code{2y}), or (the prefix of) an existing hashed password (typically @code{$2b$10$...}).
@@ -1543,26 +1543,28 @@ the salt will be extracted from @var{scheme}. Sample code to generate a bcrypt hash: @example char cleartxtpassword[] = "ExamplePassword"; +char scheme[] = "2b"; uint8_t salt[BLOWFISH_BCRYPT_BINSALT_SIZE]; @dots{} /* Make sure that salt is filled with random bytes */ @dots{} char hashedresult[BLOWFISH_BCRYPT_HASH_SIZE]; -int result = blowfish_bcrypt(sizeof(hashedresult), hashedresult, - cleartxtpassword, "2b", 10, salt); +int result = blowfish_bcrypt(hashedresult, + sizeof(cleartxtpassword), cleartxtpassword, + sizeof(scheme), scheme, 10, salt); if (result) printf("%s\n", hashedresult); @end example @end deftypefun
-@deftypefun int blowfish_bcrypt_verify (const char *@var{key}, const char *@var{hashed}) +@deftypefun int blowfish_bcrypt_verify (size_t @var{lenkey}, const char *@var{key}, size_t @var{lenhashed}, const char *@var{hashed}) Verifies the bcrypt password hash against the supplied plaintext password. The function will return @code{0} if the password does not match. The function will return @code{1} if the password matches.
-@var{key} contains the zero terminated plaintext password string. +@var{key} contains the plaintext password string of size @var{lenkey}.
-@var{hashed} contains the zero terminated hashed string to compare with. +@var{hashed} contains the hashed string of size @var{lenhashed} to compare with.
Sample code to verify a bcrypt hash: @example @@ -1573,7 +1575,8 @@ char existinghashed[] = "$" /* separator */ "1b2lPgo4XumibnJGN3r3sO" /* base64 encoded 16-byte salt */ "u7wE7xNfYDKlAxZffJDCJdVfFTAyevu"; /* Hashedpart */ -if (blowfish_bcrypt_verify(cleartxtpassword, existinghashed)) +if (blowfish_bcrypt_verify(sizeof(cleartxtpassword), cleartxtpassword, + sizeof(existinghashed), existinghashed)) printf("Password is correct."); else printf("Password is incorrect.");