]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/passwd/apr1.c
Add APR1 to Makefile/README. Add {BSDMD5} mechanism.
[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 *scheme,\r
113         const struct berval *magic,\r
114         const struct berval *passwd,\r
115         const struct berval *cred,\r
116         const char **text)\r
117 {\r
118         unsigned char digest[LUTIL_MD5_BYTES];\r
119         unsigned char *orig_pass;\r
120         int rc, n;\r
121         struct berval salt;\r
122 \r
123         /* safety check */\r
124         n = LUTIL_BASE64_DECODE_LEN(passwd->bv_len);\r
125         if (n <= sizeof(digest))\r
126                 return LUTIL_PASSWD_ERR;\r
127 \r
128         /* base64 un-encode password hash */\r
129         orig_pass = (unsigned char *) ber_memalloc((size_t) (n + 1));\r
130 \r
131         if (orig_pass == NULL)\r
132                 return LUTIL_PASSWD_ERR;\r
133 \r
134         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);\r
135 \r
136         if (rc <= (int) sizeof(digest)) {\r
137                 ber_memfree(orig_pass);\r
138                 return LUTIL_PASSWD_ERR;\r
139         }\r
140 \r
141         salt.bv_val = (char *) &orig_pass[sizeof(digest)];\r
142         salt.bv_len = rc - sizeof(digest);\r
143 \r
144         /* the only difference between this and straight PHK is the magic */\r
145         do_phk_hash(cred, magic, &salt, digest);\r
146 \r
147         if (text)\r
148                 *text = NULL;\r
149 \r
150         /* compare */\r
151         rc = memcmp((char *) orig_pass, (char *) digest, sizeof(digest));\r
152         ber_memfree(orig_pass);\r
153         return rc ?  LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;\r
154 }\r
155 \r
156 static int chk_apr1(\r
157         const struct berval *scheme,\r
158         const struct berval *passwd,\r
159         const struct berval *cred,\r
160         const char **text)\r
161 {\r
162         return chk_phk(scheme, &magic_apr1, passwd, cred, text);\r
163 }\r
164 \r
165 static int chk_bsdmd5(\r
166         const struct berval *scheme,\r
167         const struct berval *passwd,\r
168         const struct berval *cred,\r
169         const char **text)\r
170 {\r
171         return chk_phk(scheme, &magic_bsdmd5, passwd, cred, text);\r
172 }\r
173 \r
174 static int hash_phk(\r
175         const struct berval *scheme,\r
176         const struct berval *magic,\r
177         const struct berval *passwd,\r
178         struct berval *hash,\r
179         const char **text)\r
180 {\r
181         unsigned char digest_buf[LUTIL_MD5_BYTES];\r
182         char salt_buf[APR_SALT_SIZE];\r
183         struct berval digest;\r
184         struct berval salt;\r
185         int n;\r
186 \r
187         digest.bv_val = (char *) digest_buf;\r
188         digest.bv_len = sizeof(digest_buf);\r
189         salt.bv_val = salt_buf;\r
190         salt.bv_len = APR_SALT_SIZE;\r
191 \r
192         /* generate random salt */\r
193         if (lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0)\r
194                 return LUTIL_PASSWD_ERR; \r
195         /* limit it to characters in the 64-char set */\r
196         for (n = 0; n < salt.bv_len; n++)\r
197                 salt.bv_val[n] = apr64[salt.bv_val[n] % (sizeof(apr64) - 1)];\r
198 \r
199         do_phk_hash(passwd, magic, &salt, digest_buf);\r
200 \r
201         if (text)\r
202                 *text = NULL;\r
203 \r
204         return lutil_passwd_string64(scheme, &digest, hash, &salt);\r
205 }\r
206 \r
207 static int hash_apr1(\r
208         const struct berval *scheme,\r
209         const struct berval *passwd,\r
210         struct berval *hash,\r
211         const char **text)\r
212 {\r
213         return hash_phk(scheme, &magic_apr1, passwd, hash, text);\r
214 }\r
215 \r
216 static int hash_bsdmd5(\r
217         const struct berval *scheme,\r
218         const struct berval *passwd,\r
219         struct berval *hash,\r
220         const char **text)\r
221 {\r
222         return hash_phk(scheme, &magic_bsdmd5, passwd, hash, text);\r
223 }\r
224 \r
225 int init_module(int argc, char *argv[]) {\r
226         int rc;\r
227         rc = lutil_passwd_add((struct berval *) &scheme_apr1, chk_apr1, hash_apr1);\r
228         if ( !rc )\r
229                 rc = lutil_passwd_add((struct berval *) &scheme_bsdmd5,\r
230                         chk_bsdmd5, hash_bsdmd5);\r
231         return rc;\r
232 }\r