add support for bcrypt

PR: 49288


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1395255 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Stefan Fritsch
2012-10-07 09:06:10 +00:00
parent 65d07ff463
commit c2eb43db55
5 changed files with 87 additions and 14 deletions

View File

@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache 2.5.0
*) htpasswd, htdbm: Add support for bcrypt algorithm (requires
apr-util 1.5 or higher). PR 49288. [Stefan Fritsch]
*) htpasswd, htdbm: Put full 48bit of entropy into salt, improve
error handling. Add some of htpasswd's improvements to htdbm,
e.g. warn if password is truncated by crypt(). [Stefan Fritsch]

View File

@ -276,29 +276,33 @@ static void htdbm_usage(void)
{
fprintf(stderr,
"htdbm -- program for manipulating DBM password databases.\n\n"
"Usage: htdbm [-cmdpstvx] [-TDBTYPE] database username\n"
" -b[cmdptsv] [-TDBTYPE] database username password\n"
" -n[mdpst] username\n"
" -nb[mdpst] username password\n"
" -v[mdps] [-TDBTYPE] database username\n"
" -vb[mdps] [-TDBTYPE] database username password\n"
" -x [-TDBTYPE] database username\n"
" -l [-TDBTYPE] database\n"
"Usage: htdbm [-cmBdpstvx] [-Ccost] [-TDBTYPE] database username\n"
" -b[cmBdptsv] [-Ccost] [-TDBTYPE] database username password\n"
" -n[mBdpst] [-Ccost] username\n"
" -nb[mBdpst] [-Ccost] username password\n"
" -v[mBdps] [-Ccost] [-TDBTYPE] database username\n"
" -vb[mBdps] [-Ccost] [-TDBTYPE] database username password\n"
" -x [-Ccost] [-TDBTYPE] database username\n"
" -l [-Ccost] [-TDBTYPE] database\n"
"Options:\n"
" -b Use the password from the command line rather than prompting for it.\n"
" -c Create a new database.\n"
" -n Don't update database; display results on stdout.\n"
" -m Force MD5 encryption of the password (default).\n"
" -B Force BCRYPT encryption of the password (very secure).\n"
" -d Force CRYPT encryption of the password (8 chars max, insecure).\n"
" -p Do not encrypt the password (plaintext).\n"
" -s Force SHA encryption of the password (insecure).\n"
" -C Set the computing time used for the bcrypt algorithm.\n"
" (higher is more secure but slower, default: %d, valid: 4 to 31)\n"
" -T DBM Type (SDBM|GDBM|DB|default).\n"
" -l Display usernames from database on stdout.\n"
" -t The last param is username comment.\n"
" -v Verify the username/password.\n"
" -x Remove the username record from database.\n"
"The SHA algorithm does not use a salt and is less secure than the "
"MD5 algorithm.\n");
"MD5 algorithm.\n",
BCRYPT_DEFAULT_COST);
exit(ERR_SYNTAX);
}

View File

@ -92,14 +92,17 @@ static int mkrecord(struct passwd_ctx *ctx, char *user)
static void usage(void)
{
apr_file_printf(errfile, "Usage:" NL
"\thtpasswd [-cmdpsD] passwordfile username" NL
"\thtpasswd -b[cmdpsD] passwordfile username password" NL
"\thtpasswd [-cmBdpsD] [-C cost] passwordfile username" NL
"\thtpasswd -b[cmBdpsD] [-C cost] passwordfile username password" NL
NL
"\thtpasswd -n[mdps] username" NL
"\thtpasswd -nb[mdps] username password" NL
"\thtpasswd -n[mBdps] [-C cost] username" NL
"\thtpasswd -nb[mBdps] [-C cost] username password" NL
" -c Create a new file." NL
" -n Don't update file; display results on stdout." NL
" -m Force MD5 encryption of the password (default)." NL
" -B Force bcrypt encryption of the password (very secure)." NL
" -C Set the computing time used for the bcrypt algorithm" NL
" (higher is more secure but slower, default: %d, valid: 4 to 31)" NL
" -d Force CRYPT encryption of the password (8 chars max, "
"insecure)." NL
" -p Do not encrypt the password (plaintext, insecure)." NL
@ -110,7 +113,8 @@ static void usage(void)
"On other systems than Windows and NetWare the '-p' flag will "
"probably not work." NL
"The SHA algorithm does not use a salt and is less secure than the "
"MD5 algorithm." NL
"MD5 algorithm." NL,
BCRYPT_DEFAULT_COST
);
exit(ERR_SYNTAX);
}

View File

@ -131,6 +131,11 @@ int mkhash(struct passwd_ctx *ctx)
char *cbuf;
#endif
if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) {
apr_file_printf(errfile,
"Warning: Ignoring -C argument for this algorithm." NL);
}
if (ctx->passwd != NULL) {
pw = ctx->passwd;
}
@ -189,6 +194,30 @@ int mkhash(struct passwd_ctx *ctx)
}
break;
#endif /* CRYPT_ALGO_SUPPORTED */
#if BCRYPT_ALGO_SUPPORTED
case ALG_BCRYPT:
rv = apr_generate_random_bytes((unsigned char*)salt, 16);
if (rv != APR_SUCCESS) {
ctx->errstr = apr_psprintf(ctx->pool, "Unable to generate random "
"bytes: %pm", &rv);
ret = ERR_RANDOM;
break;
}
if (ctx->cost == 0)
ctx->cost = BCRYPT_DEFAULT_COST;
rv = apr_bcrypt_encode(pw, ctx->cost, (unsigned char*)salt, 16,
ctx->out, ctx->out_len);
if (rv != APR_SUCCESS) {
ctx->errstr = apr_psprintf(ctx->pool, "Unable to encode with "
"bcrypt: %pm", &rv);
ret = ERR_PWMISMATCH;
break;
}
break;
#endif /* BCRYPT_ALGO_SUPPORTED */
default:
apr_file_printf(errfile, "%s: BUG: invalid algorithm %d", __func__,
ctx->alg);
@ -232,6 +261,25 @@ int parse_common_options(struct passwd_ctx *ctx, char opt,
ctx->alg = ALG_APMD5;
#endif
break;
case 'B':
#if BCRYPT_ALGO_SUPPORTED
ctx->alg = ALG_BCRYPT;
#else
/* Don't fall back to something less secure */
ctx->errstr = "BCRYPT algorithm not supported on this platform";
return ERR_ALG_NOT_SUPP;
#endif
break;
case 'C': {
char *endptr;
long num = strtol(opt_arg, &endptr, 10);
if (*endptr != '\0' || num <= 0) {
ctx->errstr = "argument to -C must be a positive integer";
return ERR_SYNTAX;
}
ctx->cost = num;
break;
}
default:
apr_file_printf(errfile, "%s: BUG: invalid option %c", __func__, opt);
abort();

View File

@ -21,6 +21,9 @@
#include "apr_file_io.h"
#include "apr_general.h"
#include "apr_version.h"
#if !APR_VERSION_AT_LEAST(2,0,0)
#include "apu_version.h"
#endif
#define MAX_STRING_LEN 256
@ -28,6 +31,9 @@
#define ALG_CRYPT 1
#define ALG_APMD5 2
#define ALG_APSHA 3
#define ALG_BCRYPT 4
#define BCRYPT_DEFAULT_COST 5
#define ERR_FILEPERM 1
#define ERR_SYNTAX 2
@ -50,6 +56,13 @@
#define PLAIN_ALGO_SUPPORTED 0
#endif
#if APR_VERSION_AT_LEAST(2,0,0) || \
(APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 5)
#define BCRYPT_ALGO_SUPPORTED 1
#else
#define BCRYPT_ALGO_SUPPORTED 0
#endif
/*
* Must be initialized with apr_file_open_stderr() before using any of the
* below functions.
@ -63,6 +76,7 @@ struct passwd_ctx {
apr_size_t out_len;
char *passwd;
int alg;
int cost;
enum {
PW_PROMPT = 0,
PW_ARG