1 /* $NetBSD: pkcs5_pbkdf2.c,v 1.13 2008/04/21 15:23:35 christos Exp $ */
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Roland C. Dowdeswell.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * This code is an implementation of PKCS #5 PBKDF2 which is described
36 * ``PKCS #5 v2.0: Password-Based Cryptography Standard'', RSA Laboratories,
39 * and can be found at the following URL:
41 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/
43 * It was also republished as RFC 2898.
47 #include <sys/cdefs.h>
49 __RCSID("$NetBSD: pkcs5_pbkdf2.c,v 1.13 2008/04/21 15:23:35 christos Exp $");
52 #include <sys/resource.h>
53 #include <sys/endian.h>
61 #include <openssl/hmac.h>
63 #include "pkcs5_pbkdf2.h"
66 static void prf_iterate(u_int8_t
*, const u_int8_t
*, size_t,
67 const u_int8_t
*, size_t, size_t, size_t);
68 static int pkcs5_pbkdf2_time(size_t, size_t);
70 #define PRF_BLOCKLEN 20
73 prf_iterate(u_int8_t
*r
, const u_int8_t
*P
, size_t Plen
,
74 const u_int8_t
*S
, size_t Slen
, size_t c
, size_t ind
)
81 u_int8_t tmp
[EVP_MAX_MD_SIZE
];
83 data
= emalloc(Slen
+ 4);
84 (void)memcpy(data
, S
, Slen
);
85 be32enc(data
+ Slen
, ind
);
88 for (i
=0; i
< c
; i
++) {
89 (void)HMAC(EVP_sha1(), P
, Plen
, data
, datalen
, tmp
, &tmplen
);
91 assert(tmplen
== PRF_BLOCKLEN
);
94 (void)memcpy(r
, tmp
, PRF_BLOCKLEN
);
97 memxor(r
, tmp
, PRF_BLOCKLEN
);
98 (void)memcpy(data
, tmp
, PRF_BLOCKLEN
);
99 datalen
= PRF_BLOCKLEN
;
105 * pkcs5_pbkdf2 takes all of its lengths in bytes.
109 pkcs5_pbkdf2(u_int8_t
**r
, size_t dkLen
, const u_int8_t
*P
, size_t Plen
,
110 const u_int8_t
*S
, size_t Slen
, size_t c
, int compat
)
124 l
= (dkLen
+ PRF_BLOCKLEN
- 1) / PRF_BLOCKLEN
;
126 /* allocate the output */
127 *r
= emalloc(l
* PRF_BLOCKLEN
);
130 for (i
= 0; i
< l
; i
++)
131 prf_iterate(*r
+ (PRF_BLOCKLEN
* i
), P
, Plen
, S
, Slen
, c
,
135 * by the structure of the code, we do not need to concatenate
136 * the blocks, they're already concatenated. We do not extract
137 * the first dkLen octets, since we [naturally] assume that the
138 * calling function will use only the octets that it needs and
139 * the free(3) will free all of the allocated memory.
145 * We use predefined lengths for the password and salt to ensure that
146 * no analysis can be done on the output of the calibration based on
147 * those parameters. We do not do the same for dkLen because:
148 * 1. dkLen is known to the attacker if they know the iteration
150 * 2. using the wrong dkLen will skew the calibration by an
151 * integral factor n = (dkLen / 160).
154 #define CAL_PASSLEN 64
155 #define CAL_SALTLEN 64
156 #define CAL_TIME 30000 /* Minimum number of microseconds that
157 * are considered significant.
161 * We return the user time in microseconds that c iterations
162 * of the algorithm take.
166 pkcs5_pbkdf2_time(size_t dkLen
, size_t c
)
172 u_int8_t P
[CAL_PASSLEN
];
173 u_int8_t S
[CAL_SALTLEN
];
175 (void)getrusage(RUSAGE_SELF
, &start
);
176 /* XXX compat flag at end to be removed when _OLD keygen method is */
177 ret
= pkcs5_pbkdf2(&r
, dkLen
, P
, sizeof(P
), S
, sizeof(S
), c
, 0);
180 (void)getrusage(RUSAGE_SELF
, &end
);
183 return (end
.ru_utime
.tv_sec
- start
.ru_utime
.tv_sec
) * 1000000
184 + (end
.ru_utime
.tv_usec
- start
.ru_utime
.tv_usec
);
188 pkcs5_pbkdf2_calibrate(size_t dkLen
, int microseconds
)
194 for (i
= 0; i
< 5; i
++) {
196 * First we get a meaningfully long time by doubling the
197 * iteration count until it takes longer than CAL_TIME. This
198 * should take approximately 2 * CAL_TIME.
200 for (c
= 1;; c
*= 2) {
201 t
= pkcs5_pbkdf2_time(dkLen
, c
);
206 /* Now that we know that, we scale it. */
207 ret
= (size_t) ((u_int64_t
) c
* microseconds
/ t
);
210 * Since it is quite important to not get this wrong,
211 * we test the result.
214 t
= pkcs5_pbkdf2_time(dkLen
, ret
);
216 /* if we are over 5% off, return an error */
217 if (abs(microseconds
- t
) > (microseconds
/ 20))