2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2009-2013 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>
26 #include <openssl/evp.h>
28 #define PBKDF2_SALT_SIZE 16
29 #define PBKDF2_DK_SIZE 20
30 #define PBKDF2_ITERATION 60000
32 const struct berval pbkdf2scheme = BER_BVC("{PBKDF2}");
35 * Converting base64 string to adapted base64 string.
36 * Adapted base64 encode is identical to general base64 encode except
37 * that it uses '.' instead of '+', and omits trailing padding '=' and
39 * see http://pythonhosted.org/passlib/lib/passlib.utils.html
40 * This is destructive function.
42 static int b64_to_ab64(char *str)
58 * Converting adapted base64 string to base64 string.
59 * dstsize will require src length + 2, due to output string have
60 * potential to append "=" or "==".
61 * return -1 if few output buffer.
63 static int ab64_to_b64(char *src, char *dst, size_t dstsize){
66 for(i=0; p[i] && p[i] != '$'; i++){
88 static int pbkdf2_format(
89 const struct berval *sc,
91 const struct berval *salt,
92 const struct berval *dk,
97 char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
98 char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_DK_SIZE) + 1];
100 rc = lutil_b64_ntop((unsigned char *)salt->bv_val, salt->bv_len,
101 salt_b64, sizeof(salt_b64));
103 return LUTIL_PASSWD_ERR;
105 b64_to_ab64(salt_b64);
106 rc = lutil_b64_ntop((unsigned char *)dk->bv_val, dk->bv_len,
107 dk_b64, sizeof(dk_b64));
109 return LUTIL_PASSWD_ERR;
112 msg->bv_len = asprintf(&msg->bv_val, "%s%d$%s$%s",
113 sc->bv_val, iteration,
116 return LUTIL_PASSWD_ERR;
119 #ifdef SLAPD_PBKDF2_DEBUG
120 printf(" Output:\t%s\n", msg->bv_val);
122 return LUTIL_PASSWD_OK;
125 static int pbkdf2_encrypt(
126 const struct berval *scheme,
127 const struct berval *passwd,
131 unsigned char salt_value[PBKDF2_SALT_SIZE];
133 unsigned char dk_value[PBKDF2_DK_SIZE];
135 int iteration = PBKDF2_ITERATION;
137 dk.bv_val = (char *)dk_value;
138 dk.bv_len = PBKDF2_DK_SIZE;
139 salt.bv_val = (char *)salt_value;
140 salt.bv_len = sizeof(salt_value);
142 if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){
143 return LUTIL_PASSWD_ERR;
146 if(!PKCS5_PBKDF2_HMAC_SHA1(passwd->bv_val, passwd->bv_len,
147 (unsigned char *)salt.bv_val, salt.bv_len,
148 iteration, PBKDF2_DK_SIZE, dk_value)){
149 return LUTIL_PASSWD_ERR;
152 #ifdef SLAPD_PBKDF2_DEBUG
153 printf("DEBUG pbkdf2_encrypt()\n");
154 printf(" Password:\t%s\n", passwd->bv_val);
156 printf(" Salt:\t\t");
158 for(i=0; i<salt.bv_len; i++){
159 printf("%02x", salt_value[i]);
162 printf(" Iteration:\t%d\n", iteration);
165 for(i=0; i<PBKDF2_DK_SIZE; i++){
166 printf("%02x", dk_value[i]);
171 return pbkdf2_format(scheme, iteration, &salt, &dk, msg);
174 static int pbkdf2_check(
175 const struct berval *scheme,
176 const struct berval *passwd,
177 const struct berval *cred,
183 /* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
184 unsigned char salt_value[PBKDF2_SALT_SIZE + 1];
185 char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
186 /* dk_value require PBKDF2_DK_SIZE + 1 in lutil_b64_pton. */
187 unsigned char dk_value[PBKDF2_DK_SIZE + 1];
188 char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_DK_SIZE) + 1];
189 unsigned char input_dk_value[PBKDF2_DK_SIZE];
191 #ifdef SLAPD_PBKDF2_DEBUG
192 printf("DEBUG pbkdf2_check()\n");
193 printf(" Stored Value:\t%s\n", passwd->bv_val);
194 printf(" Input Cred:\t%s\n", cred->bv_val);
197 iteration = atoi(passwd->bv_val);
199 return LUTIL_PASSWD_ERR;
203 ptr = strchr(passwd->bv_val, '$');
205 return LUTIL_PASSWD_ERR;
207 ptr++; /* skip '$' */
208 rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64));
210 return LUTIL_PASSWD_ERR;
213 ptr = strchr(ptr, '$');
215 return LUTIL_PASSWD_ERR;
217 ptr++; /* skip '$' */
218 rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64));
220 return LUTIL_PASSWD_ERR;
223 /* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
224 rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1);
226 return LUTIL_PASSWD_ERR;
229 /* consistency check */
230 if(rc != PBKDF2_SALT_SIZE){
231 return LUTIL_PASSWD_ERR;
234 /* The targetsize require PBKDF2_DK_SIZE + 1 in lutil_b64_pton. */
235 rc = lutil_b64_pton(dk_b64, dk_value, PBKDF2_DK_SIZE + 1);
237 return LUTIL_PASSWD_ERR;
240 /* consistency check */
241 if(rc != PBKDF2_DK_SIZE){
242 return LUTIL_PASSWD_ERR;
245 if(!PKCS5_PBKDF2_HMAC_SHA1(cred->bv_val, cred->bv_len,
246 salt_value, PBKDF2_SALT_SIZE,
247 iteration, PBKDF2_DK_SIZE, input_dk_value)){
248 return LUTIL_PASSWD_ERR;
251 rc = memcmp(dk_value, input_dk_value, PBKDF2_DK_SIZE);
252 #ifdef SLAPD_PBKDF2_DEBUG
253 printf(" Iteration:\t%d\n", iteration);
254 printf(" Base64 Salt:\t%s\n", salt_b64);
255 printf(" Base64 DK:\t%s\n", dk_b64);
257 printf(" Stored Salt:\t");
258 for(i=0; i<PBKDF2_SALT_SIZE; i++){
259 printf("%02x", salt_value[i]);
263 printf(" Stored DK:\t");
264 for(i=0; i<PBKDF2_DK_SIZE; i++){
265 printf("%02x", dk_value[i]);
269 printf(" Input DK:\t");
270 for(i=0; i<PBKDF2_DK_SIZE; i++){
271 printf("%02x", input_dk_value[i]);
274 printf(" Result:\t%d\n", rc);
276 return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK;
279 int init_module(int argc, char *argv[]) {
281 rc = lutil_passwd_add((struct berval *)&pbkdf2scheme,
282 pbkdf2_check, pbkdf2_encrypt);
285 /* TODO: add {PBKDF2-SHA256} and {PBKDF2-SHA512} schemes. */
291 * indent-tabs-mode: t