]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c
Merge remote-tracking branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_4
[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-2013 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_SALT_SIZE 16
29 #define PBKDF2_DK_SIZE   20
30 #define PBKDF2_ITERATION 60000
31
32 const struct berval pbkdf2scheme = BER_BVC("{PBKDF2}");
33
34 /*
35  * Converting base64 string to adapted base64 string.
36  * Adapted base64 encode is identical to general base64 encode except
37  * that it uses '.' instead of '+', and omits trailing padding '=' and
38  * whitepsace.
39  * see http://pythonhosted.org/passlib/lib/passlib.utils.html
40  * This is destructive function.
41  */
42 static int b64_to_ab64(char *str)
43 {
44         char *p = str;
45         while(*p++){
46                 if(*p == '+'){
47                         *p = '.';
48                 }
49                 if(*p == '='){
50                         *p = '\0';
51                         break;
52                 }
53         }
54         return 0;
55 }
56
57 /*
58  * Converting adapted base64 string to base64 string.
59  * dstsize will require src length + 2, due to output string have
60  * potential to append "=" or "==".
61  * return -1 if few output buffer.
62  */
63 static int ab64_to_b64(char *src, char *dst, size_t dstsize){
64         int i;
65         char *p = src;
66         for(i=0; p[i] && p[i] != '$'; i++){
67                 if(i >= dstsize){
68                         dst[0] = '\0';
69                         return -1;
70                 }
71                 if(p[i] == '.'){
72                         dst[i] = '+';
73                 }else{
74                         dst[i] = p[i];
75                 }
76         }
77         for(;i%4;i++){
78                 if(i >= dstsize){
79                         dst[0] = '\0';
80                         return -1;
81                 }
82                 dst[i] = '=';
83         }
84         dst[i] = '\0';
85         return 0;
86 }
87
88 static int pbkdf2_format(
89         const struct berval *sc,
90         int iteration,
91         const struct berval *salt,
92         const struct berval *dk,
93         struct berval *msg)
94 {
95
96         int rc;
97         char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
98         char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_DK_SIZE) + 1];
99
100         rc = lutil_b64_ntop((unsigned char *)salt->bv_val, salt->bv_len,
101                                                 salt_b64, sizeof(salt_b64));
102         if(rc < 0){
103                 return LUTIL_PASSWD_ERR;
104         }
105         b64_to_ab64(salt_b64);
106         rc = lutil_b64_ntop((unsigned char *)dk->bv_val, dk->bv_len,
107                                                 dk_b64, sizeof(dk_b64));
108         if(rc < 0){
109                 return LUTIL_PASSWD_ERR;
110         }
111         b64_to_ab64(dk_b64);
112         msg->bv_len = asprintf(&msg->bv_val, "%s%d$%s$%s",
113                                                    sc->bv_val, iteration,
114                                                    salt_b64, dk_b64);
115         if(msg->bv_len < 0){
116                 return LUTIL_PASSWD_ERR;
117         }
118
119 #ifdef SLAPD_PBKDF2_DEBUG
120         printf("  Output:\t%s\n", msg->bv_val);
121 #endif
122         return LUTIL_PASSWD_OK;
123 }
124
125 static int pbkdf2_encrypt(
126         const struct berval *scheme,
127         const struct berval *passwd,
128         struct berval *msg,
129         const char **text)
130 {
131         unsigned char salt_value[PBKDF2_SALT_SIZE];
132         struct berval salt;
133         unsigned char dk_value[PBKDF2_DK_SIZE];
134         struct berval dk;
135         int iteration = PBKDF2_ITERATION;
136
137         dk.bv_val = (char *)dk_value;
138         dk.bv_len = PBKDF2_DK_SIZE;
139         salt.bv_val = (char *)salt_value;
140         salt.bv_len = sizeof(salt_value);
141
142         if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){
143                 return LUTIL_PASSWD_ERR;
144         }
145
146         if(!PKCS5_PBKDF2_HMAC_SHA1(passwd->bv_val, passwd->bv_len,
147                                                            (unsigned char *)salt.bv_val, salt.bv_len,
148                                                            iteration, PBKDF2_DK_SIZE, dk_value)){
149                 return LUTIL_PASSWD_ERR;
150         }
151
152 #ifdef SLAPD_PBKDF2_DEBUG
153         printf("DEBUG pbkdf2_encrypt()\n");
154         printf("  Password:\t%s\n", passwd->bv_val);
155
156         printf("  Salt:\t\t");
157         int i;
158         for(i=0; i<salt.bv_len; i++){
159                 printf("%02x", salt_value[i]);
160         }
161         printf("\n");
162         printf("  Iteration:\t%d\n", iteration);
163
164         printf("  DK:\t\t");
165         for(i=0; i<PBKDF2_DK_SIZE; i++){
166                 printf("%02x", dk_value[i]);
167         }
168         printf("\n");
169 #endif
170
171         return pbkdf2_format(scheme, iteration, &salt, &dk, msg);
172 }
173
174 static int pbkdf2_check(
175         const struct berval *scheme,
176         const struct berval *passwd,
177         const struct berval *cred,
178         const char **text)
179 {
180         int rc;
181         int iteration;
182
183         /* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
184         unsigned char salt_value[PBKDF2_SALT_SIZE + 1];
185         char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
186         /* dk_value require PBKDF2_DK_SIZE + 1 in lutil_b64_pton. */
187         unsigned char dk_value[PBKDF2_DK_SIZE + 1];
188         char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_DK_SIZE) + 1];
189         unsigned char input_dk_value[PBKDF2_DK_SIZE];
190
191 #ifdef SLAPD_PBKDF2_DEBUG
192         printf("DEBUG pbkdf2_check()\n");
193         printf("  Stored Value:\t%s\n", passwd->bv_val);
194         printf("  Input Cred:\t%s\n", cred->bv_val);
195 #endif
196
197         iteration = atoi(passwd->bv_val);
198         if(iteration < 1){
199                 return LUTIL_PASSWD_ERR;
200         }
201
202         char *ptr;
203         ptr = strchr(passwd->bv_val, '$');
204         if(!ptr){
205                 return LUTIL_PASSWD_ERR;
206         }
207         ptr++; /* skip '$' */
208         rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64));
209         if(rc < 0){
210                 return LUTIL_PASSWD_ERR;
211         }
212
213         ptr = strchr(ptr, '$');
214         if(!ptr){
215                 return LUTIL_PASSWD_ERR;
216         }
217         ptr++; /* skip '$' */
218         rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64));
219         if(rc < 0){
220                 return LUTIL_PASSWD_ERR;
221         }
222
223         /* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
224         rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1);
225         if(rc < 0){
226                 return LUTIL_PASSWD_ERR;
227         }
228
229         /* consistency check */
230         if(rc != PBKDF2_SALT_SIZE){
231                 return LUTIL_PASSWD_ERR;
232         }
233
234         /* The targetsize require PBKDF2_DK_SIZE + 1 in lutil_b64_pton. */
235         rc = lutil_b64_pton(dk_b64, dk_value, PBKDF2_DK_SIZE + 1);
236         if(rc < 0){
237                 return LUTIL_PASSWD_ERR;
238         }
239
240         /* consistency check */
241         if(rc != PBKDF2_DK_SIZE){
242                 return LUTIL_PASSWD_ERR;
243         }
244
245         if(!PKCS5_PBKDF2_HMAC_SHA1(cred->bv_val, cred->bv_len,
246                                                            salt_value, PBKDF2_SALT_SIZE,
247                                                            iteration, PBKDF2_DK_SIZE, input_dk_value)){
248                 return LUTIL_PASSWD_ERR;
249         }
250
251         rc = memcmp(dk_value, input_dk_value, PBKDF2_DK_SIZE);
252 #ifdef SLAPD_PBKDF2_DEBUG
253         printf("  Iteration:\t%d\n", iteration);
254         printf("  Base64 Salt:\t%s\n", salt_b64);
255         printf("  Base64 DK:\t%s\n", dk_b64);
256         int i;
257         printf("  Stored Salt:\t");
258         for(i=0; i<PBKDF2_SALT_SIZE; i++){
259                 printf("%02x", salt_value[i]);
260         }
261         printf("\n");
262
263         printf("  Stored DK:\t");
264         for(i=0; i<PBKDF2_DK_SIZE; i++){
265                 printf("%02x", dk_value[i]);
266         }
267         printf("\n");
268
269         printf("  Input DK:\t");
270         for(i=0; i<PBKDF2_DK_SIZE; i++){
271                 printf("%02x", input_dk_value[i]);
272         }
273         printf("\n");
274         printf("  Result:\t%d\n", rc);
275 #endif
276         return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK;
277 }
278
279 int init_module(int argc, char *argv[]) {
280         int rc;
281         rc = lutil_passwd_add((struct berval *)&pbkdf2scheme,
282                                                   pbkdf2_check, pbkdf2_encrypt);
283         if(!rc) return rc;
284
285         /* TODO: add {PBKDF2-SHA256} and {PBKDF2-SHA512} schemes. */
286         return rc;
287 }
288
289 /*
290  * Local variables:
291  * indent-tabs-mode: t
292  * tab-width: 4
293  * c-basic-offset: 4
294  * End:
295  */