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>
38typedef void (*pbkdf2_hmac_update)(void *, unsigned, const uint8_t *);
39typedef 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
51const struct berval pbkdf2_scheme = BER_BVC("{PBKDF2}");
52const struct berval pbkdf2_sha1_scheme = BER_BVC("{PBKDF2-SHA1}");
53const struct berval pbkdf2_sha256_scheme = BER_BVC("{PBKDF2-SHA256}");
54const 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 */
64static 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 */
84static 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
109static 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
145static 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
263static 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
432int 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