1 /* $NetBSD: apr1.c,v 1.1.1.1 2014/05/28 09:58:28 tron Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* 5 * This file is derived from OpenLDAP Software. All of the modifications to 6 * OpenLDAP Software represented in the following file were developed by 7 * Devin J. Pohly <djpohly@gmail.com>. I have not assigned rights and/or 8 * interest in this work to any party. 9 * 10 * The extensions to OpenLDAP Software herein are subject to the following 11 * notice: 12 * 13 * Copyright 2011 Devin J. Pohly 14 * Portions Copyright 2011 Howard Chu 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted only as authorized by the OpenLDAP Public 17 * License. 18 * 19 * A portion of this code is used in accordance with the Beer-ware License, 20 * revision 42, as noted. 21 * 22 */ 23 #include <lber.h> 24 #include <lber_pvt.h> 25 #include "lutil.h" 26 #include "lutil_md5.h" 27 #include <ac/string.h> 28 29 #include <assert.h> 30 31 /* the only difference between this and straight PHK is the magic */ 32 static LUTIL_PASSWD_CHK_FUNC chk_apr1; 33 static LUTIL_PASSWD_HASH_FUNC hash_apr1; 34 static const struct berval scheme_apr1 = BER_BVC("{APR1}"); 35 static const struct berval magic_apr1 = BER_BVC("$apr1$"); 36 37 static LUTIL_PASSWD_CHK_FUNC chk_bsdmd5; 38 static LUTIL_PASSWD_HASH_FUNC hash_bsdmd5; 39 static const struct berval scheme_bsdmd5 = BER_BVC("{BSDMD5}"); 40 static const struct berval magic_bsdmd5 = BER_BVC("$1$"); 41 42 static const unsigned char apr64[] = 43 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 44 45 #define APR_SALT_SIZE 8 46 47 /* The algorithm implemented in this function was created by Poul-Henning 48 * Kamp and released under the following license: 49 * ---------------------------------------------------------------------------- 50 * "THE BEER-WARE LICENSE" (Revision 42): 51 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 52 * can do whatever you want with this stuff. If we meet some day, and you think 53 * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp 54 * ---------------------------------------------------------------------------- 55 */ 56 static void do_phk_hash( 57 const struct berval *passwd, 58 const struct berval *salt, 59 const struct berval *magic, 60 unsigned char *digest) 61 { 62 lutil_MD5_CTX ctx, ctx1; 63 int n; 64 65 /* Start hashing */ 66 lutil_MD5Init(&ctx); 67 lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, passwd->bv_len); 68 lutil_MD5Update(&ctx, (const unsigned char *) magic->bv_val, magic->bv_len); 69 lutil_MD5Update(&ctx, (const unsigned char *) salt->bv_val, salt->bv_len); 70 /* Inner hash */ 71 lutil_MD5Init(&ctx1); 72 lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); 73 lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len); 74 lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); 75 lutil_MD5Final(digest, &ctx1); 76 /* Nom start mixing things up */ 77 for (n = passwd->bv_len; n > 0; n -= LUTIL_MD5_BYTES) 78 lutil_MD5Update(&ctx, digest, 79 (n > LUTIL_MD5_BYTES ? LUTIL_MD5_BYTES : n)); 80 memset(digest, 0, LUTIL_MD5_BYTES); 81 /* Curiouser and curiouser... */ 82 for (n = passwd->bv_len; n; n >>= 1) 83 if (n & 1) 84 lutil_MD5Update(&ctx, digest, 1); 85 else 86 lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, 1); 87 lutil_MD5Final(digest, &ctx); 88 /* 89 * Repeatedly hash things into the final value. This was originally 90 * intended to slow the algorithm down. 91 */ 92 for (n = 0; n < 1000; n++) { 93 lutil_MD5Init(&ctx1); 94 if (n & 1) 95 lutil_MD5Update(&ctx1, 96 (const unsigned char *) passwd->bv_val, passwd->bv_len); 97 else 98 lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); 99 100 if (n % 3) 101 lutil_MD5Update(&ctx1, 102 (const unsigned char *) salt->bv_val, salt->bv_len); 103 if (n % 7) 104 lutil_MD5Update(&ctx1, 105 (const unsigned char *) passwd->bv_val, passwd->bv_len); 106 107 if (n & 1) 108 lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); 109 else 110 lutil_MD5Update(&ctx1, 111 (const unsigned char *) passwd->bv_val, passwd->bv_len); 112 lutil_MD5Final(digest, &ctx1); 113 } 114 } 115 116 static int chk_phk( 117 const struct berval *magic, 118 const struct berval *passwd, 119 const struct berval *cred, 120 const char **text) 121 { 122 unsigned char digest[LUTIL_MD5_BYTES]; 123 unsigned char *orig_pass; 124 int rc, n; 125 struct berval salt; 126 127 /* safety check */ 128 n = LUTIL_BASE64_DECODE_LEN(passwd->bv_len); 129 if (n <= sizeof(digest)) 130 return LUTIL_PASSWD_ERR; 131 132 /* base64 un-encode password hash */ 133 orig_pass = (unsigned char *) ber_memalloc((size_t) (n + 1)); 134 135 if (orig_pass == NULL) 136 return LUTIL_PASSWD_ERR; 137 138 rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len); 139 140 if (rc <= (int) sizeof(digest)) { 141 ber_memfree(orig_pass); 142 return LUTIL_PASSWD_ERR; 143 } 144 145 salt.bv_val = (char *) &orig_pass[sizeof(digest)]; 146 salt.bv_len = rc - sizeof(digest); 147 148 do_phk_hash(cred, magic, &salt, digest); 149 150 if (text) 151 *text = NULL; 152 153 /* compare */ 154 rc = memcmp((char *) orig_pass, (char *) digest, sizeof(digest)); 155 ber_memfree(orig_pass); 156 return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; 157 } 158 159 static int chk_apr1( 160 const struct berval *scheme, 161 const struct berval *passwd, 162 const struct berval *cred, 163 const char **text) 164 { 165 return chk_phk(&magic_apr1, passwd, cred, text); 166 } 167 168 static int chk_bsdmd5( 169 const struct berval *scheme, 170 const struct berval *passwd, 171 const struct berval *cred, 172 const char **text) 173 { 174 return chk_phk(&magic_bsdmd5, passwd, cred, text); 175 } 176 177 static int hash_phk( 178 const struct berval *scheme, 179 const struct berval *magic, 180 const struct berval *passwd, 181 struct berval *hash, 182 const char **text) 183 { 184 unsigned char digest_buf[LUTIL_MD5_BYTES]; 185 char salt_buf[APR_SALT_SIZE]; 186 struct berval digest; 187 struct berval salt; 188 int n; 189 190 digest.bv_val = (char *) digest_buf; 191 digest.bv_len = sizeof(digest_buf); 192 salt.bv_val = salt_buf; 193 salt.bv_len = APR_SALT_SIZE; 194 195 /* generate random salt */ 196 if (lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0) 197 return LUTIL_PASSWD_ERR; 198 /* limit it to characters in the 64-char set */ 199 for (n = 0; n < salt.bv_len; n++) 200 salt.bv_val[n] = apr64[salt.bv_val[n] % (sizeof(apr64) - 1)]; 201 202 do_phk_hash(passwd, magic, &salt, digest_buf); 203 204 if (text) 205 *text = NULL; 206 207 return lutil_passwd_string64(scheme, &digest, hash, &salt); 208 } 209 210 static int hash_apr1( 211 const struct berval *scheme, 212 const struct berval *passwd, 213 struct berval *hash, 214 const char **text) 215 { 216 return hash_phk(scheme, &magic_apr1, passwd, hash, text); 217 } 218 219 static int hash_bsdmd5( 220 const struct berval *scheme, 221 const struct berval *passwd, 222 struct berval *hash, 223 const char **text) 224 { 225 return hash_phk(scheme, &magic_bsdmd5, passwd, hash, text); 226 } 227 228 int init_module(int argc, char *argv[]) { 229 int rc; 230 rc = lutil_passwd_add((struct berval *) &scheme_apr1, chk_apr1, hash_apr1); 231 if ( !rc ) 232 rc = lutil_passwd_add((struct berval *) &scheme_bsdmd5, 233 chk_bsdmd5, hash_bsdmd5); 234 return rc; 235 } 236