Back to index

openldap  2.4.31
apr1.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /*
00003  * This file is derived from OpenLDAP Software. All of the modifications to
00004  * OpenLDAP Software represented in the following file were developed by
00005  * Devin J. Pohly <djpohly@gmail.com>. I have not assigned rights and/or
00006  * interest in this work to any party. 
00007  *
00008  * The extensions to OpenLDAP Software herein are subject to the following
00009  * notice:
00010  *
00011  * Copyright 2011 Devin J. Pohly
00012  * Portions Copyright 2011 Howard Chu
00013  * Redistribution and use in source and binary forms, with or without
00014  * modification, are permitted only as authorized by the OpenLDAP Public
00015  * License. 
00016  *
00017  * A portion of this code is used in accordance with the Beer-ware License,
00018  * revision 42, as noted.
00019  *
00020  */
00021 #include <lber.h>
00022 #include <lber_pvt.h>
00023 #include "lutil.h"
00024 #include "lutil_md5.h"
00025 #include <ac/string.h>
00026 
00027 #include <assert.h>
00028 
00029 /* the only difference between this and straight PHK is the magic */
00030 static LUTIL_PASSWD_CHK_FUNC chk_apr1;
00031 static LUTIL_PASSWD_HASH_FUNC hash_apr1;
00032 static const struct berval scheme_apr1 = BER_BVC("{APR1}");
00033 static const struct berval magic_apr1 = BER_BVC("$apr1$");
00034 
00035 static LUTIL_PASSWD_CHK_FUNC chk_bsdmd5;
00036 static LUTIL_PASSWD_HASH_FUNC hash_bsdmd5;
00037 static const struct berval scheme_bsdmd5 = BER_BVC("{BSDMD5}");
00038 static const struct berval magic_bsdmd5 = BER_BVC("$1$");
00039 
00040 static const unsigned char apr64[] =
00041        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
00042 
00043 #define APR_SALT_SIZE       8
00044 
00045 /* The algorithm implemented in this function was created by Poul-Henning
00046  * Kamp and released under the following license:
00047  * ----------------------------------------------------------------------------
00048  * "THE BEER-WARE LICENSE" (Revision 42):
00049  * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
00050  * can do whatever you want with this stuff. If we meet some day, and you think
00051  * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp
00052  * ----------------------------------------------------------------------------
00053  */
00054 static void do_phk_hash(
00055        const struct berval *passwd,
00056        const struct berval *salt,
00057        const struct berval *magic,
00058        unsigned char *digest)
00059 {
00060        lutil_MD5_CTX ctx, ctx1;
00061        int n;
00062 
00063        /* Start hashing */
00064        lutil_MD5Init(&ctx);
00065        lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, passwd->bv_len);
00066        lutil_MD5Update(&ctx, (const unsigned char *) magic->bv_val, magic->bv_len);
00067        lutil_MD5Update(&ctx, (const unsigned char *) salt->bv_val, salt->bv_len);
00068        /* Inner hash */
00069        lutil_MD5Init(&ctx1);
00070        lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len);
00071        lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len);
00072        lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len);
00073        lutil_MD5Final(digest, &ctx1);
00074        /* Nom start mixing things up */
00075        for (n = passwd->bv_len; n > 0; n -= LUTIL_MD5_BYTES)
00076               lutil_MD5Update(&ctx, digest,
00077                             (n > LUTIL_MD5_BYTES ? LUTIL_MD5_BYTES : n));
00078        memset(digest, 0, LUTIL_MD5_BYTES);
00079        /* Curiouser and curiouser... */
00080        for (n = passwd->bv_len; n; n >>= 1)
00081               if (n & 1)
00082                      lutil_MD5Update(&ctx, digest, 1);
00083               else
00084                      lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, 1);
00085        lutil_MD5Final(digest, &ctx);
00086        /*
00087         * Repeatedly hash things into the final value. This was originally
00088         * intended to slow the algorithm down.
00089         */
00090        for (n = 0; n < 1000; n++) {
00091               lutil_MD5Init(&ctx1);
00092               if (n & 1)
00093                      lutil_MD5Update(&ctx1,
00094                             (const unsigned char *) passwd->bv_val, passwd->bv_len);
00095               else
00096                      lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES);
00097 
00098               if (n % 3)
00099                      lutil_MD5Update(&ctx1,
00100                             (const unsigned char *) salt->bv_val, salt->bv_len);
00101               if (n % 7)
00102                      lutil_MD5Update(&ctx1,
00103                             (const unsigned char *) passwd->bv_val, passwd->bv_len);
00104 
00105               if (n & 1)
00106                      lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES);
00107               else
00108                      lutil_MD5Update(&ctx1,
00109                             (const unsigned char *) passwd->bv_val, passwd->bv_len);
00110               lutil_MD5Final(digest, &ctx1);
00111        }
00112 }
00113 
00114 static int chk_phk(
00115        const struct berval *magic,
00116        const struct berval *passwd,
00117        const struct berval *cred,
00118        const char **text)
00119 {
00120        unsigned char digest[LUTIL_MD5_BYTES];
00121        unsigned char *orig_pass;
00122        int rc, n;
00123        struct berval salt;
00124 
00125        /* safety check */
00126        n = LUTIL_BASE64_DECODE_LEN(passwd->bv_len);
00127        if (n <= sizeof(digest))
00128               return LUTIL_PASSWD_ERR;
00129 
00130        /* base64 un-encode password hash */
00131        orig_pass = (unsigned char *) ber_memalloc((size_t) (n + 1));
00132 
00133        if (orig_pass == NULL)
00134               return LUTIL_PASSWD_ERR;
00135 
00136        rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
00137 
00138        if (rc <= (int) sizeof(digest)) {
00139               ber_memfree(orig_pass);
00140               return LUTIL_PASSWD_ERR;
00141        }
00142 
00143        salt.bv_val = (char *) &orig_pass[sizeof(digest)];
00144        salt.bv_len = rc - sizeof(digest);
00145 
00146        do_phk_hash(cred, magic, &salt, digest);
00147 
00148        if (text)
00149               *text = NULL;
00150 
00151        /* compare */
00152        rc = memcmp((char *) orig_pass, (char *) digest, sizeof(digest));
00153        ber_memfree(orig_pass);
00154        return rc ?  LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
00155 }
00156 
00157 static int chk_apr1(
00158        const struct berval *scheme,
00159        const struct berval *passwd,
00160        const struct berval *cred,
00161        const char **text)
00162 {
00163        return chk_phk(&magic_apr1, passwd, cred, text);
00164 }
00165 
00166 static int chk_bsdmd5(
00167        const struct berval *scheme,
00168        const struct berval *passwd,
00169        const struct berval *cred,
00170        const char **text)
00171 {
00172        return chk_phk(&magic_bsdmd5, passwd, cred, text);
00173 }
00174 
00175 static int hash_phk(
00176        const struct berval *scheme,
00177        const struct berval *magic,
00178        const struct berval *passwd,
00179        struct berval *hash,
00180        const char **text)
00181 {
00182        unsigned char digest_buf[LUTIL_MD5_BYTES];
00183        char salt_buf[APR_SALT_SIZE];
00184        struct berval digest;
00185        struct berval salt;
00186        int n;
00187 
00188        digest.bv_val = (char *) digest_buf;
00189        digest.bv_len = sizeof(digest_buf);
00190        salt.bv_val = salt_buf;
00191        salt.bv_len = APR_SALT_SIZE;
00192 
00193        /* generate random salt */
00194        if (lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0)
00195               return LUTIL_PASSWD_ERR; 
00196        /* limit it to characters in the 64-char set */
00197        for (n = 0; n < salt.bv_len; n++)
00198               salt.bv_val[n] = apr64[salt.bv_val[n] % (sizeof(apr64) - 1)];
00199 
00200        do_phk_hash(passwd, magic, &salt, digest_buf);
00201 
00202        if (text)
00203               *text = NULL;
00204 
00205        return lutil_passwd_string64(scheme, &digest, hash, &salt);
00206 }
00207 
00208 static int hash_apr1(
00209        const struct berval *scheme,
00210        const struct berval *passwd,
00211        struct berval *hash,
00212        const char **text)
00213 {
00214        return hash_phk(scheme, &magic_apr1, passwd, hash, text);
00215 }
00216 
00217 static int hash_bsdmd5(
00218        const struct berval *scheme,
00219        const struct berval *passwd,
00220        struct berval *hash,
00221        const char **text)
00222 {
00223        return hash_phk(scheme, &magic_bsdmd5, passwd, hash, text);
00224 }
00225 
00226 int init_module(int argc, char *argv[]) {
00227        int rc;
00228        rc = lutil_passwd_add((struct berval *) &scheme_apr1, chk_apr1, hash_apr1);
00229        if ( !rc )
00230               rc = lutil_passwd_add((struct berval *) &scheme_bsdmd5,
00231                      chk_bsdmd5, hash_bsdmd5);
00232        return rc;
00233 }