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