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