]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c
e0f5dfd74c22ad569f9992985818ba35f7aaf07f
[openldap] / contrib / slapd-modules / passwd / pbkdf2 / pw-pbkdf2.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2009-2015 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* ACKNOWLEDGEMENT:
16  * This work was initially developed by HAMANO Tsukasa <hamano@osstech.co.jp>
17  */
18
19 #define _GNU_SOURCE
20
21 #include "portable.h"
22 #include <ac/string.h>
23 #include "lber_pvt.h"
24 #include "lutil.h"
25
26 #include <openssl/evp.h>
27
28 #define PBKDF2_ITERATION 10000
29 #define PBKDF2_SALT_SIZE 16
30 #define PBKDF2_SHA1_DK_SIZE 20
31 #define PBKDF2_SHA256_DK_SIZE 32
32 #define PBKDF2_SHA512_DK_SIZE 64
33 #define PBKDF2_MAX_DK_SIZE 64
34
35 const struct berval pbkdf2_scheme = BER_BVC("{PBKDF2}");
36 const struct berval pbkdf2_sha1_scheme = BER_BVC("{PBKDF2-SHA1}");
37 const struct berval pbkdf2_sha256_scheme = BER_BVC("{PBKDF2-SHA256}");
38 const struct berval pbkdf2_sha512_scheme = BER_BVC("{PBKDF2-SHA512}");
39
40 /*
41  * Converting base64 string to adapted base64 string.
42  * Adapted base64 encode is identical to general base64 encode except
43  * that it uses '.' instead of '+', and omits trailing padding '=' and
44  * whitepsace.
45  * see http://pythonhosted.org/passlib/lib/passlib.utils.html
46  * This is destructive function.
47  */
48 static int b64_to_ab64(char *str)
49 {
50         char *p = str;
51         while(*p++){
52                 if(*p == '+'){
53                         *p = '.';
54                 }
55                 if(*p == '='){
56                         *p = '\0';
57                         break;
58                 }
59         }
60         return 0;
61 }
62
63 /*
64  * Converting adapted base64 string to base64 string.
65  * dstsize will require src length + 2, due to output string have
66  * potential to append "=" or "==".
67  * return -1 if few output buffer.
68  */
69 static int ab64_to_b64(char *src, char *dst, size_t dstsize){
70         int i;
71         char *p = src;
72         for(i=0; p[i] && p[i] != '$'; i++){
73                 if(i >= dstsize){
74                         dst[0] = '\0';
75                         return -1;
76                 }
77                 if(p[i] == '.'){
78                         dst[i] = '+';
79                 }else{
80                         dst[i] = p[i];
81                 }
82         }
83         for(;i%4;i++){
84                 if(i >= dstsize){
85                         dst[0] = '\0';
86                         return -1;
87                 }
88                 dst[i] = '=';
89         }
90         dst[i] = '\0';
91         return 0;
92 }
93
94 static int pbkdf2_format(
95         const struct berval *sc,
96         int iteration,
97         const struct berval *salt,
98         const struct berval *dk,
99         struct berval *msg)
100 {
101
102         int rc, msg_len;
103         char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
104         char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1];
105
106         rc = lutil_b64_ntop((unsigned char *)salt->bv_val, salt->bv_len,
107                                                 salt_b64, sizeof(salt_b64));
108         if(rc < 0){
109                 return LUTIL_PASSWD_ERR;
110         }
111         b64_to_ab64(salt_b64);
112         rc = lutil_b64_ntop((unsigned char *)dk->bv_val, dk->bv_len,
113                                                 dk_b64, sizeof(dk_b64));
114         if(rc < 0){
115                 return LUTIL_PASSWD_ERR;
116         }
117         b64_to_ab64(dk_b64);
118         msg_len = asprintf(&msg->bv_val, "%s%d$%s$%s",
119                                                    sc->bv_val, iteration,
120                                                    salt_b64, dk_b64);
121         if(msg_len < 0){
122                 msg->bv_len = 0;
123                 return LUTIL_PASSWD_ERR;
124         }
125
126         msg->bv_len = msg_len;
127         return LUTIL_PASSWD_OK;
128 }
129
130 static int pbkdf2_encrypt(
131         const struct berval *scheme,
132         const struct berval *passwd,
133         struct berval *msg,
134         const char **text)
135 {
136         unsigned char salt_value[PBKDF2_SALT_SIZE];
137         struct berval salt;
138         unsigned char dk_value[PBKDF2_MAX_DK_SIZE];
139         struct berval dk;
140         int iteration = PBKDF2_ITERATION;
141         int rc;
142         const EVP_MD *md;
143
144         salt.bv_val = (char *)salt_value;
145         salt.bv_len = sizeof(salt_value);
146         dk.bv_val = (char *)dk_value;
147         if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
148                 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
149                 md = EVP_sha1();
150         }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
151                 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
152                 md = EVP_sha1();
153         }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
154                 dk.bv_len = PBKDF2_SHA256_DK_SIZE;
155                 md = EVP_sha256();
156         }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
157                 dk.bv_len = PBKDF2_SHA512_DK_SIZE;
158                 md = EVP_sha512();
159         }else{
160                 return LUTIL_PASSWD_ERR;
161         }
162
163         if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){
164                 return LUTIL_PASSWD_ERR;
165         }
166
167         if(!PKCS5_PBKDF2_HMAC(passwd->bv_val, passwd->bv_len,
168                                                   (unsigned char *)salt.bv_val, salt.bv_len,
169                                                   iteration, md, dk.bv_len, dk_value)){
170                 return LUTIL_PASSWD_ERR;
171         }
172
173 #ifdef SLAPD_PBKDF2_DEBUG
174         printf("Encrypt for %s\n", scheme->bv_val);
175         printf("  Password:\t%s\n", passwd->bv_val);
176
177         printf("  Salt:\t\t");
178         int i;
179         for(i=0; i<salt.bv_len; i++){
180                 printf("%02x", salt_value[i]);
181         }
182         printf("\n");
183         printf("  Iteration:\t%d\n", iteration);
184
185         printf("  DK:\t\t");
186         for(i=0; i<dk.bv_len; i++){
187                 printf("%02x", dk_value[i]);
188         }
189         printf("\n");
190 #endif
191
192         rc = pbkdf2_format(scheme, iteration, &salt, &dk, msg);
193
194 #ifdef SLAPD_PBKDF2_DEBUG
195         printf("  Output:\t%s\n", msg->bv_val);
196 #endif
197
198         return rc;
199 }
200
201 static int pbkdf2_check(
202         const struct berval *scheme,
203         const struct berval *passwd,
204         const struct berval *cred,
205         const char **text)
206 {
207         int rc;
208         int iteration;
209
210         /* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
211         unsigned char salt_value[PBKDF2_SALT_SIZE + 1];
212         char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
213         /* dk_value require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
214         unsigned char dk_value[PBKDF2_MAX_DK_SIZE + 1];
215         char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1];
216         unsigned char input_dk_value[PBKDF2_MAX_DK_SIZE];
217         size_t dk_len;
218         const EVP_MD *md;
219
220 #ifdef SLAPD_PBKDF2_DEBUG
221         printf("Checking for %s\n", scheme->bv_val);
222         printf("  Stored Value:\t%s\n", passwd->bv_val);
223         printf("  Input Cred:\t%s\n", cred->bv_val);
224 #endif
225
226         if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
227                 dk_len = PBKDF2_SHA1_DK_SIZE;
228                 md = EVP_sha1();
229         }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
230                 dk_len = PBKDF2_SHA1_DK_SIZE;
231                 md = EVP_sha1();
232         }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
233                 dk_len = PBKDF2_SHA256_DK_SIZE;
234                 md = EVP_sha256();
235         }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
236                 dk_len = PBKDF2_SHA512_DK_SIZE;
237                 md = EVP_sha512();
238         }else{
239                 return LUTIL_PASSWD_ERR;
240         }
241
242         iteration = atoi(passwd->bv_val);
243         if(iteration < 1){
244                 return LUTIL_PASSWD_ERR;
245         }
246
247         char *ptr;
248         ptr = strchr(passwd->bv_val, '$');
249         if(!ptr){
250                 return LUTIL_PASSWD_ERR;
251         }
252         ptr++; /* skip '$' */
253         rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64));
254         if(rc < 0){
255                 return LUTIL_PASSWD_ERR;
256         }
257
258         ptr = strchr(ptr, '$');
259         if(!ptr){
260                 return LUTIL_PASSWD_ERR;
261         }
262         ptr++; /* skip '$' */
263         rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64));
264         if(rc < 0){
265                 return LUTIL_PASSWD_ERR;
266         }
267
268         /* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
269         rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1);
270         if(rc < 0){
271                 return LUTIL_PASSWD_ERR;
272         }
273
274         /* consistency check */
275         if(rc != PBKDF2_SALT_SIZE){
276                 return LUTIL_PASSWD_ERR;
277         }
278
279         /* The targetsize require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
280         rc = lutil_b64_pton(dk_b64, dk_value, sizeof(dk_value));
281         if(rc < 0){
282                 return LUTIL_PASSWD_ERR;
283         }
284
285         /* consistency check */
286         if(rc != dk_len){
287                 return LUTIL_PASSWD_ERR;
288         }
289
290         if(!PKCS5_PBKDF2_HMAC(cred->bv_val, cred->bv_len,
291                                                   salt_value, PBKDF2_SALT_SIZE,
292                                                   iteration, md, dk_len, input_dk_value)){
293                 return LUTIL_PASSWD_ERR;
294         }
295
296         rc = memcmp(dk_value, input_dk_value, dk_len);
297 #ifdef SLAPD_PBKDF2_DEBUG
298         printf("  Iteration:\t%d\n", iteration);
299         printf("  Base64 Salt:\t%s\n", salt_b64);
300         printf("  Base64 DK:\t%s\n", dk_b64);
301         int i;
302         printf("  Stored Salt:\t");
303         for(i=0; i<PBKDF2_SALT_SIZE; i++){
304                 printf("%02x", salt_value[i]);
305         }
306         printf("\n");
307
308         printf("  Stored DK:\t");
309         for(i=0; i<dk_len; i++){
310                 printf("%02x", dk_value[i]);
311         }
312         printf("\n");
313
314         printf("  Input DK:\t");
315         for(i=0; i<dk_len; i++){
316                 printf("%02x", input_dk_value[i]);
317         }
318         printf("\n");
319         printf("  Result:\t%d\n", rc);
320 #endif
321         return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK;
322 }
323
324 int init_module(int argc, char *argv[]) {
325         int rc;
326         rc = lutil_passwd_add((struct berval *)&pbkdf2_scheme,
327                                                   pbkdf2_check, pbkdf2_encrypt);
328         if(rc) return rc;
329         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha1_scheme,
330                                                   pbkdf2_check, pbkdf2_encrypt);
331         if(rc) return rc;
332
333         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha256_scheme,
334                                                   pbkdf2_check, pbkdf2_encrypt);
335         if(rc) return rc;
336
337         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha512_scheme,
338                                                   pbkdf2_check, pbkdf2_encrypt);
339         return rc;
340 }
341
342 /*
343  * Local variables:
344  * indent-tabs-mode: t
345  * tab-width: 4
346  * c-basic-offset: 4
347  * End:
348  */