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