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