From owner-svn-src-all@FreeBSD.ORG Thu Mar 27 00:24:49 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 45D96CE7; Thu, 27 Mar 2014 00:24:49 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 313DA145; Thu, 27 Mar 2014 00:24:49 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s2R0Onr0070754; Thu, 27 Mar 2014 00:24:49 GMT (envelope-from delphij@svn.freebsd.org) Received: (from delphij@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s2R0Onrn070753; Thu, 27 Mar 2014 00:24:49 GMT (envelope-from delphij@svn.freebsd.org) Message-Id: <201403270024.s2R0Onrn070753@svn.freebsd.org> From: Xin LI Date: Thu, 27 Mar 2014 00:24:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r263784 - in stable: 8/secure/lib/libcrypt 9/secure/lib/libcrypt X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 27 Mar 2014 00:24:49 -0000 Author: delphij Date: Thu Mar 27 00:24:48 2014 New Revision: 263784 URL: http://svnweb.freebsd.org/changeset/base/263784 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/8/secure/lib/libcrypt/crypt-blowfish.c Directory Properties: stable/8/secure/lib/libcrypt/ (props changed) Changes in other areas also in this revision: Modified: stable/9/secure/lib/libcrypt/crypt-blowfish.c Directory Properties: stable/9/secure/lib/libcrypt/ (props changed) Modified: stable/8/secure/lib/libcrypt/crypt-blowfish.c ============================================================================== --- stable/8/secure/lib/libcrypt/crypt-blowfish.c Thu Mar 27 00:23:44 2014 (r263783) +++ stable/8/secure/lib/libcrypt/crypt-blowfish.c Thu Mar 27 00:24:48 2014 (r263784) @@ -1,3 +1,5 @@ +/* $OpenBSD: bcrypt.c,v 1.29 2014/02/24 19:45:43 tedu Exp $ */ + /* * Copyright 1997 Niels Provos * All rights reserved. @@ -35,10 +37,10 @@ __FBSDID("$FreeBSD$"); * 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 + * and updated by Xin Li */ #include @@ -66,7 +69,8 @@ __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 *); @@ -74,11 +78,10 @@ static void decode_base64(u_int8_t *, u_ static char encrypted[_PASSWORD_LEN]; static char error[] = ":"; -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, @@ -109,7 +112,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; @@ -139,23 +142,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++; @@ -167,9 +166,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: @@ -185,21 +184,38 @@ crypt_blowfish(const char *key, const ch /* Out of sync with passwd entry */ return error; - /* 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 error; + 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); @@ -234,7 +250,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); @@ -242,6 +258,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; } @@ -274,7 +294,6 @@ encode_base64(u_int8_t *buffer, u_int8_t } *bp = '\0'; } - #if 0 void main() @@ -289,11 +308,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);