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