svn commit: r262501 - head/secure/lib/libcrypt
Xin LI
delphij at FreeBSD.org
Tue Feb 25 23:03:49 UTC 2014
Author: delphij
Date: Tue Feb 25 23:03:48 2014
New Revision: 262501
URL: http://svnweb.freebsd.org/changeset/base/262501
Log:
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 $02a$ format of password
but we will migrate to the new format once the format is formally
finalized.
MFC after: 1 month
Modified:
head/secure/lib/libcrypt/crypt-blowfish.c
Modified: head/secure/lib/libcrypt/crypt-blowfish.c
==============================================================================
--- head/secure/lib/libcrypt/crypt-blowfish.c Tue Feb 25 22:13:51 2014 (r262500)
+++ head/secure/lib/libcrypt/crypt-blowfish.c Tue Feb 25 23:03:48 2014 (r262501)
@@ -1,3 +1,5 @@
+/* $OpenBSD: bcrypt.c,v 1.29 2014/02/24 19:45:43 tedu Exp $ */
+
/*
* Copyright 1997 Niels Provos <provos at physnet.uni-hamburg.de>
* All rights reserved.
@@ -35,10 +37,10 @@ __FBSDID("$FreeBSD$");
* <dm at 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 at frenchfries.net>
+ * and updated by Xin Li <delphij at 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);
More information about the svn-src-all
mailing list