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