]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/passwd/pbkdf2/pw-pbkdf2.c
9bf9c95c9357fde32fb85e1629aea3f7c4717f2d
[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-2017 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 #include <stdio.h>
26 #include <stdlib.h>
27
28 #ifdef HAVE_OPENSSL
29 #include <openssl/evp.h>
30 #elif HAVE_GNUTLS
31 #include <nettle/pbkdf2.h>
32 #include <nettle/hmac.h>
33 typedef void (*pbkdf2_hmac_update)(void *, unsigned, const uint8_t *);
34 typedef void (*pbkdf2_hmac_digest)(void *, unsigned, uint8_t *);
35 #else
36 #error Unsupported crypto backend.
37 #endif
38
39 #define PBKDF2_ITERATION 10000
40 #define PBKDF2_SALT_SIZE 16
41 #define PBKDF2_SHA1_DK_SIZE 20
42 #define PBKDF2_SHA256_DK_SIZE 32
43 #define PBKDF2_SHA512_DK_SIZE 64
44 #define PBKDF2_MAX_DK_SIZE 64
45
46 const struct berval pbkdf2_scheme = BER_BVC("{PBKDF2}");
47 const struct berval pbkdf2_sha1_scheme = BER_BVC("{PBKDF2-SHA1}");
48 const struct berval pbkdf2_sha256_scheme = BER_BVC("{PBKDF2-SHA256}");
49 const struct berval pbkdf2_sha512_scheme = BER_BVC("{PBKDF2-SHA512}");
50
51 /*
52  * Converting base64 string to adapted base64 string.
53  * Adapted base64 encode is identical to general base64 encode except
54  * that it uses '.' instead of '+', and omits trailing padding '=' and
55  * whitepsace.
56  * see http://pythonhosted.org/passlib/lib/passlib.utils.html
57  * This is destructive function.
58  */
59 static int b64_to_ab64(char *str)
60 {
61         char *p = str;
62         while(*p++){
63                 if(*p == '+'){
64                         *p = '.';
65                 }
66                 if(*p == '='){
67                         *p = '\0';
68                         break;
69                 }
70         }
71         return 0;
72 }
73
74 /*
75  * Converting adapted base64 string to base64 string.
76  * dstsize will require src length + 2, due to output string have
77  * potential to append "=" or "==".
78  * return -1 if few output buffer.
79  */
80 static int ab64_to_b64(char *src, char *dst, size_t dstsize){
81         int i;
82         char *p = src;
83         for(i=0; p[i] && p[i] != '$'; i++){
84                 if(i >= dstsize){
85                         dst[0] = '\0';
86                         return -1;
87                 }
88                 if(p[i] == '.'){
89                         dst[i] = '+';
90                 }else{
91                         dst[i] = p[i];
92                 }
93         }
94         for(;i%4;i++){
95                 if(i >= dstsize){
96                         dst[0] = '\0';
97                         return -1;
98                 }
99                 dst[i] = '=';
100         }
101         dst[i] = '\0';
102         return 0;
103 }
104
105 static int pbkdf2_format(
106         const struct berval *sc,
107         int iteration,
108         const struct berval *salt,
109         const struct berval *dk,
110         struct berval *msg)
111 {
112
113         int rc, msg_len;
114         char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
115         char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1];
116
117         rc = lutil_b64_ntop((unsigned char *)salt->bv_val, salt->bv_len,
118                                                 salt_b64, sizeof(salt_b64));
119         if(rc < 0){
120                 return LUTIL_PASSWD_ERR;
121         }
122         b64_to_ab64(salt_b64);
123         rc = lutil_b64_ntop((unsigned char *)dk->bv_val, dk->bv_len,
124                                                 dk_b64, sizeof(dk_b64));
125         if(rc < 0){
126                 return LUTIL_PASSWD_ERR;
127         }
128         b64_to_ab64(dk_b64);
129         msg_len = asprintf(&msg->bv_val, "%s%d$%s$%s",
130                                                    sc->bv_val, iteration,
131                                                    salt_b64, dk_b64);
132         if(msg_len < 0){
133                 msg->bv_len = 0;
134                 return LUTIL_PASSWD_ERR;
135         }
136
137         msg->bv_len = msg_len;
138         return LUTIL_PASSWD_OK;
139 }
140
141 static int pbkdf2_encrypt(
142         const struct berval *scheme,
143         const struct berval *passwd,
144         struct berval *msg,
145         const char **text)
146 {
147         unsigned char salt_value[PBKDF2_SALT_SIZE];
148         struct berval salt;
149         unsigned char dk_value[PBKDF2_MAX_DK_SIZE];
150         struct berval dk;
151         int iteration = PBKDF2_ITERATION;
152         int rc;
153 #ifdef HAVE_OPENSSL
154         const EVP_MD *md;
155 #elif HAVE_GNUTLS
156         struct hmac_sha1_ctx sha1_ctx;
157         struct hmac_sha256_ctx sha256_ctx;
158         struct hmac_sha512_ctx sha512_ctx;
159         void * current_ctx = NULL;
160         pbkdf2_hmac_update current_hmac_update = NULL;
161         pbkdf2_hmac_digest current_hmac_digest = NULL;
162 #endif
163
164         salt.bv_val = (char *)salt_value;
165         salt.bv_len = sizeof(salt_value);
166         dk.bv_val = (char *)dk_value;
167
168 #ifdef HAVE_OPENSSL
169         if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
170                 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
171                 md = EVP_sha1();
172         }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
173                 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
174                 md = EVP_sha1();
175         }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
176                 dk.bv_len = PBKDF2_SHA256_DK_SIZE;
177                 md = EVP_sha256();
178         }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
179                 dk.bv_len = PBKDF2_SHA512_DK_SIZE;
180                 md = EVP_sha512();
181         }else{
182                 return LUTIL_PASSWD_ERR;
183         }
184 #elif HAVE_GNUTLS
185         if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
186                 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
187                 current_ctx = &sha1_ctx;
188                 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
189                 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
190                 hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
191         }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
192                 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
193                 current_ctx = &sha1_ctx;
194                 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
195                 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
196                 hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
197         }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
198                 dk.bv_len = PBKDF2_SHA256_DK_SIZE;
199                 current_ctx = &sha256_ctx;
200                 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update;
201                 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest;
202                 hmac_sha256_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
203         }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
204                 dk.bv_len = PBKDF2_SHA512_DK_SIZE;
205                 current_ctx = &sha512_ctx;
206                 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update;
207                 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest;
208                 hmac_sha512_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
209         }else{
210                 return LUTIL_PASSWD_ERR;
211         }
212 #endif
213
214         if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){
215                 return LUTIL_PASSWD_ERR;
216         }
217
218 #ifdef HAVE_OPENSSL
219         if(!PKCS5_PBKDF2_HMAC(passwd->bv_val, passwd->bv_len,
220                                                   (unsigned char *)salt.bv_val, salt.bv_len,
221                                                   iteration, md, dk.bv_len, dk_value)){
222                 return LUTIL_PASSWD_ERR;
223         }
224 #elif HAVE_GNUTLS
225         PBKDF2(current_ctx, current_hmac_update, current_hmac_digest,
226                                                   dk.bv_len, iteration,
227                                                   salt.bv_len, (const uint8_t *) salt.bv_val,
228                                                   dk.bv_len, dk_value);
229 #endif
230
231 #ifdef SLAPD_PBKDF2_DEBUG
232         printf("Encrypt for %s\n", scheme->bv_val);
233         printf("  Password:\t%s\n", passwd->bv_val);
234
235         printf("  Salt:\t\t");
236         int i;
237         for(i=0; i<salt.bv_len; i++){
238                 printf("%02x", salt_value[i]);
239         }
240         printf("\n");
241         printf("  Iteration:\t%d\n", iteration);
242
243         printf("  DK:\t\t");
244         for(i=0; i<dk.bv_len; i++){
245                 printf("%02x", dk_value[i]);
246         }
247         printf("\n");
248 #endif
249
250         rc = pbkdf2_format(scheme, iteration, &salt, &dk, msg);
251
252 #ifdef SLAPD_PBKDF2_DEBUG
253         printf("  Output:\t%s\n", msg->bv_val);
254 #endif
255
256         return rc;
257 }
258
259 static int pbkdf2_check(
260         const struct berval *scheme,
261         const struct berval *passwd,
262         const struct berval *cred,
263         const char **text)
264 {
265         int rc;
266         int iteration;
267
268         /* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
269         unsigned char salt_value[PBKDF2_SALT_SIZE + 1];
270         char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
271         /* dk_value require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
272         unsigned char dk_value[PBKDF2_MAX_DK_SIZE + 1];
273         char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1];
274         unsigned char input_dk_value[PBKDF2_MAX_DK_SIZE];
275         size_t dk_len;
276 #ifdef HAVE_OPENSSL
277         const EVP_MD *md;
278 #elif HAVE_GNUTLS
279         struct hmac_sha1_ctx sha1_ctx;
280         struct hmac_sha256_ctx sha256_ctx;
281         struct hmac_sha512_ctx sha512_ctx;
282         void * current_ctx = NULL;
283         pbkdf2_hmac_update current_hmac_update = NULL;
284         pbkdf2_hmac_digest current_hmac_digest = NULL;
285 #endif
286
287 #ifdef SLAPD_PBKDF2_DEBUG
288         printf("Checking for %s\n", scheme->bv_val);
289         printf("  Stored Value:\t%s\n", passwd->bv_val);
290         printf("  Input Cred:\t%s\n", cred->bv_val);
291 #endif
292
293 #ifdef HAVE_OPENSSL
294         if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
295                 dk_len = PBKDF2_SHA1_DK_SIZE;
296                 md = EVP_sha1();
297         }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
298                 dk_len = PBKDF2_SHA1_DK_SIZE;
299                 md = EVP_sha1();
300         }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
301                 dk_len = PBKDF2_SHA256_DK_SIZE;
302                 md = EVP_sha256();
303         }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
304                 dk_len = PBKDF2_SHA512_DK_SIZE;
305                 md = EVP_sha512();
306         }else{
307                 return LUTIL_PASSWD_ERR;
308         }
309 #elif HAVE_GNUTLS
310         if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
311                 dk_len = PBKDF2_SHA1_DK_SIZE;
312                 current_ctx = &sha1_ctx;
313                 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
314                 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
315                 hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
316         }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
317                 dk_len = PBKDF2_SHA1_DK_SIZE;
318                 current_ctx = &sha1_ctx;
319                 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
320                 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
321                 hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
322         }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
323                 dk_len = PBKDF2_SHA256_DK_SIZE;
324                 current_ctx = &sha256_ctx;
325                 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update;
326                 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest;
327                 hmac_sha256_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
328         }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
329                 dk_len = PBKDF2_SHA512_DK_SIZE;
330                 current_ctx = &sha512_ctx;
331                 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update;
332                 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest;
333                 hmac_sha512_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
334         }else{
335                 return LUTIL_PASSWD_ERR;
336         }
337 #endif
338
339         iteration = atoi(passwd->bv_val);
340         if(iteration < 1){
341                 return LUTIL_PASSWD_ERR;
342         }
343
344         char *ptr;
345         ptr = strchr(passwd->bv_val, '$');
346         if(!ptr){
347                 return LUTIL_PASSWD_ERR;
348         }
349         ptr++; /* skip '$' */
350         rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64));
351         if(rc < 0){
352                 return LUTIL_PASSWD_ERR;
353         }
354
355         ptr = strchr(ptr, '$');
356         if(!ptr){
357                 return LUTIL_PASSWD_ERR;
358         }
359         ptr++; /* skip '$' */
360         rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64));
361         if(rc < 0){
362                 return LUTIL_PASSWD_ERR;
363         }
364
365         /* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
366         rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1);
367         if(rc < 0){
368                 return LUTIL_PASSWD_ERR;
369         }
370
371         /* consistency check */
372         if(rc != PBKDF2_SALT_SIZE){
373                 return LUTIL_PASSWD_ERR;
374         }
375
376         /* The targetsize require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
377         rc = lutil_b64_pton(dk_b64, dk_value, sizeof(dk_value));
378         if(rc < 0){
379                 return LUTIL_PASSWD_ERR;
380         }
381
382         /* consistency check */
383         if(rc != dk_len){
384                 return LUTIL_PASSWD_ERR;
385         }
386
387 #ifdef HAVE_OPENSSL
388         if(!PKCS5_PBKDF2_HMAC(cred->bv_val, cred->bv_len,
389                                                   salt_value, PBKDF2_SALT_SIZE,
390                                                   iteration, md, dk_len, input_dk_value)){
391                 return LUTIL_PASSWD_ERR;
392         }
393 #elif HAVE_GNUTLS
394         PBKDF2(current_ctx, current_hmac_update, current_hmac_digest,
395                                                   dk_len, iteration,
396                                                   PBKDF2_SALT_SIZE, salt_value,
397                                                   dk_len, input_dk_value);
398 #endif
399
400         rc = memcmp(dk_value, input_dk_value, dk_len);
401 #ifdef SLAPD_PBKDF2_DEBUG
402         printf("  Iteration:\t%d\n", iteration);
403         printf("  Base64 Salt:\t%s\n", salt_b64);
404         printf("  Base64 DK:\t%s\n", dk_b64);
405         int i;
406         printf("  Stored Salt:\t");
407         for(i=0; i<PBKDF2_SALT_SIZE; i++){
408                 printf("%02x", salt_value[i]);
409         }
410         printf("\n");
411
412         printf("  Stored DK:\t");
413         for(i=0; i<dk_len; i++){
414                 printf("%02x", dk_value[i]);
415         }
416         printf("\n");
417
418         printf("  Input DK:\t");
419         for(i=0; i<dk_len; i++){
420                 printf("%02x", input_dk_value[i]);
421         }
422         printf("\n");
423         printf("  Result:\t%d\n", rc);
424 #endif
425         return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK;
426 }
427
428 int init_module(int argc, char *argv[]) {
429         int rc;
430         rc = lutil_passwd_add((struct berval *)&pbkdf2_scheme,
431                                                   pbkdf2_check, pbkdf2_encrypt);
432         if(rc) return rc;
433         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha1_scheme,
434                                                   pbkdf2_check, pbkdf2_encrypt);
435         if(rc) return rc;
436
437         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha256_scheme,
438                                                   pbkdf2_check, pbkdf2_encrypt);
439         if(rc) return rc;
440
441         rc = lutil_passwd_add((struct berval *)&pbkdf2_sha512_scheme,
442                                                   pbkdf2_check, pbkdf2_encrypt);
443         return rc;
444 }
445
446 /*
447  * Local variables:
448  * indent-tabs-mode: t
449  * tab-width: 4
450  * c-basic-offset: 4
451  * End:
452  */