apr1.c revision 1.1 1 /* $NetBSD: apr1.c,v 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 (at) 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 (at) 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