2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2009-2015 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
16 * This work was initially developed by HAMANO Tsukasa <hamano@osstech.co.jp>
22 #include <ac/string.h>
29 #include <openssl/evp.h>
31 #include <nettle/pbkdf2.h>
32 #include <nettle/hmac.h>
33 typedef void (*pbkdf2_hmac_update)(void *, unsigned, const uint8_t *);
34 typedef void (*pbkdf2_hmac_digest)(void *, unsigned, uint8_t *);
36 #error Unsupported crypto backend.
39 #define PBKDF2_ITERATION 10000
40 #define PBKDF2_SALT_SIZE 16
41 #define PBKDF2_SHA1_DK_SIZE 20
42 #define PBKDF2_SHA256_DK_SIZE 32
43 #define PBKDF2_SHA512_DK_SIZE 64
44 #define PBKDF2_MAX_DK_SIZE 64
46 const struct berval pbkdf2_scheme = BER_BVC("{PBKDF2}");
47 const struct berval pbkdf2_sha1_scheme = BER_BVC("{PBKDF2-SHA1}");
48 const struct berval pbkdf2_sha256_scheme = BER_BVC("{PBKDF2-SHA256}");
49 const struct berval pbkdf2_sha512_scheme = BER_BVC("{PBKDF2-SHA512}");
52 * Converting base64 string to adapted base64 string.
53 * Adapted base64 encode is identical to general base64 encode except
54 * that it uses '.' instead of '+', and omits trailing padding '=' and
56 * see http://pythonhosted.org/passlib/lib/passlib.utils.html
57 * This is destructive function.
59 static int b64_to_ab64(char *str)
75 * Converting adapted base64 string to base64 string.
76 * dstsize will require src length + 2, due to output string have
77 * potential to append "=" or "==".
78 * return -1 if few output buffer.
80 static int ab64_to_b64(char *src, char *dst, size_t dstsize){
83 for(i=0; p[i] && p[i] != '$'; i++){
105 static int pbkdf2_format(
106 const struct berval *sc,
108 const struct berval *salt,
109 const struct berval *dk,
114 char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
115 char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1];
117 rc = lutil_b64_ntop((unsigned char *)salt->bv_val, salt->bv_len,
118 salt_b64, sizeof(salt_b64));
120 return LUTIL_PASSWD_ERR;
122 b64_to_ab64(salt_b64);
123 rc = lutil_b64_ntop((unsigned char *)dk->bv_val, dk->bv_len,
124 dk_b64, sizeof(dk_b64));
126 return LUTIL_PASSWD_ERR;
129 msg_len = asprintf(&msg->bv_val, "%s%d$%s$%s",
130 sc->bv_val, iteration,
134 return LUTIL_PASSWD_ERR;
137 msg->bv_len = msg_len;
138 return LUTIL_PASSWD_OK;
141 static int pbkdf2_encrypt(
142 const struct berval *scheme,
143 const struct berval *passwd,
147 unsigned char salt_value[PBKDF2_SALT_SIZE];
149 unsigned char dk_value[PBKDF2_MAX_DK_SIZE];
151 int iteration = PBKDF2_ITERATION;
156 struct hmac_sha1_ctx sha1_ctx;
157 struct hmac_sha256_ctx sha256_ctx;
158 struct hmac_sha512_ctx sha512_ctx;
159 void * current_ctx = NULL;
160 pbkdf2_hmac_update current_hmac_update = NULL;
161 pbkdf2_hmac_digest current_hmac_digest = NULL;
164 salt.bv_val = (char *)salt_value;
165 salt.bv_len = sizeof(salt_value);
166 dk.bv_val = (char *)dk_value;
169 if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
170 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
172 }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
173 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
175 }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
176 dk.bv_len = PBKDF2_SHA256_DK_SIZE;
178 }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
179 dk.bv_len = PBKDF2_SHA512_DK_SIZE;
182 return LUTIL_PASSWD_ERR;
185 if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
186 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
187 current_ctx = &sha1_ctx;
188 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
189 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
190 hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
191 }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
192 dk.bv_len = PBKDF2_SHA1_DK_SIZE;
193 current_ctx = &sha1_ctx;
194 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
195 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
196 hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
197 }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
198 dk.bv_len = PBKDF2_SHA256_DK_SIZE;
199 current_ctx = &sha256_ctx;
200 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update;
201 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest;
202 hmac_sha256_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
203 }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
204 dk.bv_len = PBKDF2_SHA512_DK_SIZE;
205 current_ctx = &sha512_ctx;
206 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update;
207 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest;
208 hmac_sha512_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
210 return LUTIL_PASSWD_ERR;
214 if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){
215 return LUTIL_PASSWD_ERR;
219 if(!PKCS5_PBKDF2_HMAC(passwd->bv_val, passwd->bv_len,
220 (unsigned char *)salt.bv_val, salt.bv_len,
221 iteration, md, dk.bv_len, dk_value)){
222 return LUTIL_PASSWD_ERR;
225 PBKDF2(current_ctx, current_hmac_update, current_hmac_digest,
226 dk.bv_len, iteration,
227 salt.bv_len, (const uint8_t *) salt.bv_val,
228 dk.bv_len, dk_value);
231 #ifdef SLAPD_PBKDF2_DEBUG
232 printf("Encrypt for %s\n", scheme->bv_val);
233 printf(" Password:\t%s\n", passwd->bv_val);
235 printf(" Salt:\t\t");
237 for(i=0; i<salt.bv_len; i++){
238 printf("%02x", salt_value[i]);
241 printf(" Iteration:\t%d\n", iteration);
244 for(i=0; i<dk.bv_len; i++){
245 printf("%02x", dk_value[i]);
250 rc = pbkdf2_format(scheme, iteration, &salt, &dk, msg);
252 #ifdef SLAPD_PBKDF2_DEBUG
253 printf(" Output:\t%s\n", msg->bv_val);
259 static int pbkdf2_check(
260 const struct berval *scheme,
261 const struct berval *passwd,
262 const struct berval *cred,
268 /* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
269 unsigned char salt_value[PBKDF2_SALT_SIZE + 1];
270 char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
271 /* dk_value require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
272 unsigned char dk_value[PBKDF2_MAX_DK_SIZE + 1];
273 char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1];
274 unsigned char input_dk_value[PBKDF2_MAX_DK_SIZE];
279 struct hmac_sha1_ctx sha1_ctx;
280 struct hmac_sha256_ctx sha256_ctx;
281 struct hmac_sha512_ctx sha512_ctx;
282 void * current_ctx = NULL;
283 pbkdf2_hmac_update current_hmac_update = NULL;
284 pbkdf2_hmac_digest current_hmac_digest = NULL;
287 #ifdef SLAPD_PBKDF2_DEBUG
288 printf("Checking for %s\n", scheme->bv_val);
289 printf(" Stored Value:\t%s\n", passwd->bv_val);
290 printf(" Input Cred:\t%s\n", cred->bv_val);
294 if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
295 dk_len = PBKDF2_SHA1_DK_SIZE;
297 }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
298 dk_len = PBKDF2_SHA1_DK_SIZE;
300 }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
301 dk_len = PBKDF2_SHA256_DK_SIZE;
303 }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
304 dk_len = PBKDF2_SHA512_DK_SIZE;
307 return LUTIL_PASSWD_ERR;
310 if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
311 dk_len = PBKDF2_SHA1_DK_SIZE;
312 current_ctx = &sha1_ctx;
313 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
314 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
315 hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
316 }else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
317 dk_len = PBKDF2_SHA1_DK_SIZE;
318 current_ctx = &sha1_ctx;
319 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
320 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
321 hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
322 }else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
323 dk_len = PBKDF2_SHA256_DK_SIZE;
324 current_ctx = &sha256_ctx;
325 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update;
326 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest;
327 hmac_sha256_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
328 }else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
329 dk_len = PBKDF2_SHA512_DK_SIZE;
330 current_ctx = &sha512_ctx;
331 current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update;
332 current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest;
333 hmac_sha512_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
335 return LUTIL_PASSWD_ERR;
339 iteration = atoi(passwd->bv_val);
341 return LUTIL_PASSWD_ERR;
345 ptr = strchr(passwd->bv_val, '$');
347 return LUTIL_PASSWD_ERR;
349 ptr++; /* skip '$' */
350 rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64));
352 return LUTIL_PASSWD_ERR;
355 ptr = strchr(ptr, '$');
357 return LUTIL_PASSWD_ERR;
359 ptr++; /* skip '$' */
360 rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64));
362 return LUTIL_PASSWD_ERR;
365 /* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
366 rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1);
368 return LUTIL_PASSWD_ERR;
371 /* consistency check */
372 if(rc != PBKDF2_SALT_SIZE){
373 return LUTIL_PASSWD_ERR;
376 /* The targetsize require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
377 rc = lutil_b64_pton(dk_b64, dk_value, sizeof(dk_value));
379 return LUTIL_PASSWD_ERR;
382 /* consistency check */
384 return LUTIL_PASSWD_ERR;
388 if(!PKCS5_PBKDF2_HMAC(cred->bv_val, cred->bv_len,
389 salt_value, PBKDF2_SALT_SIZE,
390 iteration, md, dk_len, input_dk_value)){
391 return LUTIL_PASSWD_ERR;
394 PBKDF2(current_ctx, current_hmac_update, current_hmac_digest,
396 PBKDF2_SALT_SIZE, salt_value,
397 dk_len, input_dk_value);
400 rc = memcmp(dk_value, input_dk_value, dk_len);
401 #ifdef SLAPD_PBKDF2_DEBUG
402 printf(" Iteration:\t%d\n", iteration);
403 printf(" Base64 Salt:\t%s\n", salt_b64);
404 printf(" Base64 DK:\t%s\n", dk_b64);
406 printf(" Stored Salt:\t");
407 for(i=0; i<PBKDF2_SALT_SIZE; i++){
408 printf("%02x", salt_value[i]);
412 printf(" Stored DK:\t");
413 for(i=0; i<dk_len; i++){
414 printf("%02x", dk_value[i]);
418 printf(" Input DK:\t");
419 for(i=0; i<dk_len; i++){
420 printf("%02x", input_dk_value[i]);
423 printf(" Result:\t%d\n", rc);
425 return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK;
428 int init_module(int argc, char *argv[]) {
430 rc = lutil_passwd_add((struct berval *)&pbkdf2_scheme,
431 pbkdf2_check, pbkdf2_encrypt);
433 rc = lutil_passwd_add((struct berval *)&pbkdf2_sha1_scheme,
434 pbkdf2_check, pbkdf2_encrypt);
437 rc = lutil_passwd_add((struct berval *)&pbkdf2_sha256_scheme,
438 pbkdf2_check, pbkdf2_encrypt);
441 rc = lutil_passwd_add((struct berval *)&pbkdf2_sha512_scheme,
442 pbkdf2_check, pbkdf2_encrypt);
448 * indent-tabs-mode: t