]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c
e7c300ee89393b12d5cff1680447fb0442591b07
[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;
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->bv_len = asprintf(&msg->bv_val, "%s%d$%s$%s",
119                                                    sc->bv_val, iteration,
120                                                    salt_b64, dk_b64);
121         if(msg->bv_len < 0){
122                 return LUTIL_PASSWD_ERR;
123         }
124
125         return LUTIL_PASSWD_OK;
126 }
127
128 static int pbkdf2_encrypt(
129         const struct berval *scheme,
130         const struct berval *passwd,
131         struct berval *msg,
132         const char **text)
133 {
134         unsigned char salt_value[PBKDF2_SALT_SIZE];
135         struct berval salt;
136         unsigned char dk_value[PBKDF2_MAX_DK_SIZE];
137         struct berval dk;
138         int iteration = PBKDF2_ITERATION;
139         int rc;
140         const EVP_MD *md;
141
142         salt.bv_val = (char *)salt_value;
143         salt.bv_len = sizeof(salt_value);
144         dk.bv_val = (char *)dk_value;
145         if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
146                 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
147                 md = EVP_sha1();
148         }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
149                 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
150                 md = EVP_sha1();
151         }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
152                 dk.bv_len = PBKDF2_SHA256_DK_SIZE;
153                 md = EVP_sha256();
154         }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
155                 dk.bv_len = PBKDF2_SHA512_DK_SIZE;
156                 md = EVP_sha512();
157         }else{
158                 return LUTIL_PASSWD_ERR;
159         }
160
161         if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){
162                 return LUTIL_PASSWD_ERR;
163         }
164
165         if(!PKCS5_PBKDF2_HMAC(passwd->bv_val, passwd->bv_len,
166                                                   (unsigned char *)salt.bv_val, salt.bv_len,
167                                                   iteration, md, dk.bv_len, dk_value)){
168                 return LUTIL_PASSWD_ERR;
169         }
170
171 #ifdef SLAPD_PBKDF2_DEBUG
172         printf("Encrypt for %s\n", scheme->bv_val);
173         printf("  Password:\t%s\n", passwd->bv_val);
174
175         printf("  Salt:\t\t");
176         int i;
177         for(i=0; i<salt.bv_len; i++){
178                 printf("%02x", salt_value[i]);
179         }
180         printf("\n");
181         printf("  Iteration:\t%d\n", iteration);
182
183         printf("  DK:\t\t");
184         for(i=0; i<dk.bv_len; i++){
185                 printf("%02x", dk_value[i]);
186         }
187         printf("\n");
188 #endif
189
190         rc = pbkdf2_format(scheme, iteration, &salt, &dk, msg);
191
192 #ifdef SLAPD_PBKDF2_DEBUG
193         printf("  Output:\t%s\n", msg->bv_val);
194 #endif
195
196         return rc;
197 }
198
199 static int pbkdf2_check(
200         const struct berval *scheme,
201         const struct berval *passwd,
202         const struct berval *cred,
203         const char **text)
204 {
205         int rc;
206         int iteration;
207
208         /* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
209         unsigned char salt_value[PBKDF2_SALT_SIZE + 1];
210         char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
211         /* dk_value require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
212         unsigned char dk_value[PBKDF2_MAX_DK_SIZE + 1];
213         char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1];
214         unsigned char input_dk_value[PBKDF2_MAX_DK_SIZE];
215         size_t dk_len;
216         const EVP_MD *md;
217
218 #ifdef SLAPD_PBKDF2_DEBUG
219         printf("Checking for %s\n", scheme->bv_val);
220         printf("  Stored Value:\t%s\n", passwd->bv_val);
221         printf("  Input Cred:\t%s\n", cred->bv_val);
222 #endif
223
224         if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
225                 dk_len = PBKDF2_SHA1_DK_SIZE;
226                 md = EVP_sha1();
227         }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
228                 dk_len = PBKDF2_SHA1_DK_SIZE;
229                 md = EVP_sha1();
230         }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
231                 dk_len = PBKDF2_SHA256_DK_SIZE;
232                 md = EVP_sha256();
233         }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
234                 dk_len = PBKDF2_SHA512_DK_SIZE;
235                 md = EVP_sha512();
236         }else{
237                 return LUTIL_PASSWD_ERR;
238         }
239
240         iteration = atoi(passwd->bv_val);
241         if(iteration < 1){
242                 return LUTIL_PASSWD_ERR;
243         }
244
245         char *ptr;
246         ptr = strchr(passwd->bv_val, '$');
247         if(!ptr){
248                 return LUTIL_PASSWD_ERR;
249         }
250         ptr++; /* skip '$' */
251         rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64));
252         if(rc < 0){
253                 return LUTIL_PASSWD_ERR;
254         }
255
256         ptr = strchr(ptr, '$');
257         if(!ptr){
258                 return LUTIL_PASSWD_ERR;
259         }
260         ptr++; /* skip '$' */
261         rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64));
262         if(rc < 0){
263                 return LUTIL_PASSWD_ERR;
264         }
265
266         /* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
267         rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1);
268         if(rc < 0){
269                 return LUTIL_PASSWD_ERR;
270         }
271
272         /* consistency check */
273         if(rc != PBKDF2_SALT_SIZE){
274                 return LUTIL_PASSWD_ERR;
275         }
276
277         /* The targetsize require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
278         rc = lutil_b64_pton(dk_b64, dk_value, sizeof(dk_value));
279         if(rc < 0){
280                 return LUTIL_PASSWD_ERR;
281         }
282
283         /* consistency check */
284         if(rc != dk_len){
285                 return LUTIL_PASSWD_ERR;
286         }
287
288         if(!PKCS5_PBKDF2_HMAC(cred->bv_val, cred->bv_len,
289                                                   salt_value, PBKDF2_SALT_SIZE,
290                                                   iteration, md, dk_len, input_dk_value)){
291                 return LUTIL_PASSWD_ERR;
292         }
293
294         rc = memcmp(dk_value, input_dk_value, dk_len);
295 #ifdef SLAPD_PBKDF2_DEBUG
296         printf("  Iteration:\t%d\n", iteration);
297         printf("  Base64 Salt:\t%s\n", salt_b64);
298         printf("  Base64 DK:\t%s\n", dk_b64);
299         int i;
300         printf("  Stored Salt:\t");
301         for(i=0; i<PBKDF2_SALT_SIZE; i++){
302                 printf("%02x", salt_value[i]);
303         }
304         printf("\n");
305
306         printf("  Stored DK:\t");
307         for(i=0; i<dk_len; i++){
308                 printf("%02x", dk_value[i]);
309         }
310         printf("\n");
311
312         printf("  Input DK:\t");
313         for(i=0; i<dk_len; i++){
314                 printf("%02x", input_dk_value[i]);
315         }
316         printf("\n");
317         printf("  Result:\t%d\n", rc);
318 #endif
319         return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK;
320 }
321
322 int init_module(int argc, char *argv[]) {
323         int rc;
324         rc = lutil_passwd_add((struct berval *)&pbkdf2_scheme,
325                                                   pbkdf2_check, pbkdf2_encrypt);
326         if(rc) return rc;
327         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha1_scheme,
328                                                   pbkdf2_check, pbkdf2_encrypt);
329         if(rc) return rc;
330
331         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha256_scheme,
332                                                   pbkdf2_check, pbkdf2_encrypt);
333         if(rc) return rc;
334
335         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha512_scheme,
336                                                   pbkdf2_check, pbkdf2_encrypt);
337         return rc;
338 }
339
340 /*
341  * Local variables:
342  * indent-tabs-mode: t
343  * tab-width: 4
344  * c-basic-offset: 4
345  * End:
346  */