Home | History | Annotate | Line # | Download | only in pbkdf2
pw-pbkdf2.c revision 1.1.1.2.6.1
      1 /*	$NetBSD: pw-pbkdf2.c,v 1.1.1.2.6.1 2019/08/10 06:17:10 martin Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 2009-2019 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 (at) 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.2.6.1 2019/08/10 06:17:10 martin 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 	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  */
     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 
    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 
    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 
    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 
    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