Date: Thu, 27 Mar 2014 00:23:45 +0000 (UTC) From: Xin LI <delphij@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r263783 - stable/10/secure/lib/libcrypt Message-ID: <201403270023.s2R0NjLL070580@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: delphij Date: Thu Mar 27 00:23:44 2014 New Revision: 263783 URL: http://svnweb.freebsd.org/changeset/base/263783 Log: MFC r262501: Refresh our implementation of OpenBSD's Blowfish password format. Notable changes: - Support of $2b$ password format to address a problem where very long passwords (more than 256 characters, when an integer overflow would happen and cause the length to wrap at 256). - Updated pseudo code in comments to reflect the reality. - Removed our local shortcut of processing magic string and rely on the centralized and tigntened validation. - Diff reduction from upstream. For now we are still generating the older $2a$ format of password but we will migrate to the new format once the format is formally finalized. Modified: stable/10/secure/lib/libcrypt/crypt-blowfish.c Directory Properties: stable/10/ (props changed) Modified: stable/10/secure/lib/libcrypt/crypt-blowfish.c ============================================================================== --- stable/10/secure/lib/libcrypt/crypt-blowfish.c Wed Mar 26 23:58:17 2014 (r263782) +++ stable/10/secure/lib/libcrypt/crypt-blowfish.c Thu Mar 27 00:23:44 2014 (r263783) @@ -1,3 +1,5 @@ +/* $OpenBSD: bcrypt.c,v 1.29 2014/02/24 19:45:43 tedu Exp $ */ + /* * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> * All rights reserved. @@ -35,10 +37,10 @@ __FBSDID("$FreeBSD$"); * <dm@lcs.mit.edu> and works as follows: * * 1. state := InitState () - * 2. state := ExpandKey (state, salt, password) 3. - * REPEAT rounds: + * 2. state := ExpandKey (state, salt, password) + * 3. REPEAT rounds: + * state := ExpandKey (state, 0, password) * state := ExpandKey (state, 0, salt) - * state := ExpandKey(state, 0, password) * 4. ctext := "OrpheanBeholderScryDoubt" * 5. REPEAT 64: * ctext := Encrypt_ECB (state, ctext); @@ -48,6 +50,7 @@ __FBSDID("$FreeBSD$"); /* * FreeBSD implementation by Paul Herman <pherman@frenchfries.net> + * and updated by Xin Li <delphij@FreeBSD.org> */ #include <stdio.h> @@ -66,18 +69,18 @@ __FBSDID("$FreeBSD$"); #define BCRYPT_VERSION '2' #define BCRYPT_MAXSALT 16 /* Precomputation is just so nice */ #define BCRYPT_BLOCKS 6 /* Ciphertext blocks */ -#define BCRYPT_MINROUNDS 16 /* we have log2(rounds) in salt */ +#define BCRYPT_MINLOGROUNDS 4 /* we have log2(rounds) in salt */ + static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t); static void decode_base64(u_int8_t *, u_int16_t, const u_int8_t *); static char encrypted[_PASSWORD_LEN]; -static const u_int8_t Base64Code[] = +const static u_int8_t Base64Code[] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; -static const u_int8_t index_64[128] = -{ +const static u_int8_t index_64[128] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -108,7 +111,7 @@ decode_base64(u_int8_t *buffer, u_int16_ if (c1 == 255 || c2 == 255) break; - *bp++ = (u_int8_t)((c1 << 2) | ((c2 & 0x30) >> 4)); + *bp++ = (c1 << 2) | ((c2 & 0x30) >> 4); if (bp >= buffer + len) break; @@ -138,23 +141,19 @@ crypt_blowfish(const char *key, const ch blf_ctx state; u_int32_t rounds, i, k; u_int16_t j; - u_int8_t key_len, salt_len, logr, minr; + size_t key_len; + u_int8_t salt_len, logr, minr; u_int8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt"; u_int8_t csalt[BCRYPT_MAXSALT]; u_int32_t cdata[BCRYPT_BLOCKS]; - static const char *magic = "$2a$04$"; - - /* Defaults */ - minr = 'a'; - logr = 4; - rounds = 1 << logr; + char arounds[3]; - /* If it starts with the magic string, then skip that */ - if(!strncmp(salt, magic, strlen(magic))) { - salt += strlen(magic); - } - else if (*salt == '$') { + /* Defaults */ + minr = 'a'; + logr = BCRYPT_MINLOGROUNDS; + rounds = 1U << logr; + if (*salt == '$') { /* Discard "$" identifier */ salt++; @@ -166,9 +165,9 @@ crypt_blowfish(const char *key, const ch /* Check for minor versions */ if (salt[1] != '$') { switch (salt[1]) { - case 'a': - /* 'ab' should not yield the same as 'abab' */ - minr = (u_int8_t)salt[1]; + case 'a': /* 'ab' should not yield the same as 'abab' */ + case 'b': /* cap input length at 72 bytes */ + minr = salt[1]; salt++; break; default: @@ -184,21 +183,38 @@ crypt_blowfish(const char *key, const ch /* Out of sync with passwd entry */ return NULL; - /* Computer power doesnt increase linear, 2^x should be fine */ - logr = (u_int8_t)atoi(salt); - rounds = 1 << logr; - if (rounds < BCRYPT_MINROUNDS) + memcpy(arounds, salt, sizeof(arounds)); + if (arounds[sizeof(arounds) - 1] != '$') + return NULL; + arounds[sizeof(arounds) - 1] = 0; + logr = strtonum(arounds, BCRYPT_MINLOGROUNDS, 31, NULL); + if (logr == 0) return NULL; + /* Computer power doesn't increase linearly, 2^x should be fine */ + rounds = 1U << logr; /* Discard num rounds + "$" identifier */ salt += 3; } + if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) + return NULL; /* We dont want the base64 salt but the raw data */ - decode_base64(csalt, BCRYPT_MAXSALT, (const u_int8_t *)salt); + decode_base64(csalt, BCRYPT_MAXSALT, (const u_int8_t *) salt); salt_len = BCRYPT_MAXSALT; - key_len = (u_int8_t)(strlen(key) + (minr >= 'a' ? 1 : 0)); + if (minr <= 'a') + key_len = (u_int8_t)(strlen(key) + (minr >= 'a' ? 1 : 0)); + else { + /* strlen() returns a size_t, but the function calls + * below result in implicit casts to a narrower integer + * type, so cap key_len at the actual maximum supported + * length here to avoid integer wraparound */ + key_len = strlen(key); + if (key_len > 72) + key_len = 72; + key_len++; /* include the NUL */ + } /* Setting up S-Boxes and Subkeys */ Blowfish_initstate(&state); @@ -233,7 +249,7 @@ crypt_blowfish(const char *key, const ch encrypted[i++] = '$'; encrypted[i++] = BCRYPT_VERSION; if (minr) - encrypted[i++] = (int8_t)minr; + encrypted[i++] = minr; encrypted[i++] = '$'; snprintf(encrypted + i, 4, "%2.2u$", logr); @@ -241,6 +257,10 @@ crypt_blowfish(const char *key, const ch encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT); encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext, 4 * BCRYPT_BLOCKS - 1); + memset(&state, 0, sizeof(state)); + memset(ciphertext, 0, sizeof(ciphertext)); + memset(csalt, 0, sizeof(csalt)); + memset(cdata, 0, sizeof(cdata)); return encrypted; } @@ -273,7 +293,6 @@ encode_base64(u_int8_t *buffer, u_int8_t } *bp = '\0'; } - #if 0 void main() @@ -288,11 +307,11 @@ main() snprintf(salt + 3, 4, "%2.2u$", 5); printf("24 bytes of salt: "); - fgets(salt + 6, 94, stdin); + fgets(salt + 6, sizeof(salt) - 6, stdin); salt[99] = 0; printf("72 bytes of password: "); fpurge(stdin); - fgets(blubber, 73, stdin); + fgets(blubber, sizeof(blubber), stdin); blubber[72] = 0; p = crypt(blubber, salt);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201403270023.s2R0NjLL070580>