pkcs5_pbkdf2.c revision 1.1
1/*	$OpenBSD: pkcs5_pbkdf2.c,v 1.1 2012/09/06 19:41:59 tedu Exp $	*/
2
3/*-
4 * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/param.h>
21
22#include <string.h>
23#include <limits.h>
24#include <stdlib.h>
25#include <util.h>
26
27#include <sha1.h>
28
29
30/* #define PBKDF2_MAIN */
31
32/*
33 * HMAC-SHA-1 (from RFC 2202).
34 */
35static void
36hmac_sha1(const u_int8_t *text, size_t text_len, const u_int8_t *key,
37    size_t key_len, u_int8_t digest[SHA1_DIGEST_LENGTH])
38{
39	SHA1_CTX ctx;
40	u_int8_t k_pad[SHA1_BLOCK_LENGTH];
41	u_int8_t tk[SHA1_DIGEST_LENGTH];
42	int i;
43
44	if (key_len > SHA1_BLOCK_LENGTH) {
45		SHA1Init(&ctx);
46		SHA1Update(&ctx, key, key_len);
47		SHA1Final(tk, &ctx);
48
49		key = tk;
50		key_len = SHA1_DIGEST_LENGTH;
51	}
52
53	bzero(k_pad, sizeof k_pad);
54	bcopy(key, k_pad, key_len);
55	for (i = 0; i < SHA1_BLOCK_LENGTH; i++)
56		k_pad[i] ^= 0x36;
57
58	SHA1Init(&ctx);
59	SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH);
60	SHA1Update(&ctx, text, text_len);
61	SHA1Final(digest, &ctx);
62
63	bzero(k_pad, sizeof k_pad);
64	bcopy(key, k_pad, key_len);
65	for (i = 0; i < SHA1_BLOCK_LENGTH; i++)
66		k_pad[i] ^= 0x5c;
67
68	SHA1Init(&ctx);
69	SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH);
70	SHA1Update(&ctx, digest, SHA1_DIGEST_LENGTH);
71	SHA1Final(digest, &ctx);
72}
73
74/*
75 * Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
76 * Code based on IEEE Std 802.11-2007, Annex H.4.2.
77 */
78int
79pkcs5_pbkdf2(const char *pass, size_t pass_len, const char *salt, size_t salt_len,
80    u_int8_t *key, size_t key_len, u_int rounds)
81{
82	u_int8_t *asalt, obuf[SHA1_DIGEST_LENGTH];
83	u_int8_t d1[SHA1_DIGEST_LENGTH], d2[SHA1_DIGEST_LENGTH];
84	u_int i, j;
85	u_int count;
86	size_t r;
87
88	if (rounds < 1 || key_len == 0)
89		return -1;
90	if (salt_len == 0 || salt_len > SIZE_MAX - 4)
91		return -1;
92	if ((asalt = malloc(salt_len + 4)) == NULL)
93		return -1;
94
95	memcpy(asalt, salt, salt_len);
96
97	for (count = 1; key_len > 0; count++) {
98		asalt[salt_len + 0] = (count >> 24) & 0xff;
99		asalt[salt_len + 1] = (count >> 16) & 0xff;
100		asalt[salt_len + 2] = (count >> 8) & 0xff;
101		asalt[salt_len + 3] = count & 0xff;
102		hmac_sha1(asalt, salt_len + 4, pass, pass_len, d1);
103		memcpy(obuf, d1, sizeof(obuf));
104
105		for (i = 1; i < rounds; i++) {
106			hmac_sha1(d1, sizeof(d1), pass, pass_len, d2);
107			memcpy(d1, d2, sizeof(d1));
108			for (j = 0; j < sizeof(obuf); j++)
109				obuf[j] ^= d1[j];
110		}
111
112		r = MIN(key_len, SHA1_DIGEST_LENGTH);
113		memcpy(key, obuf, r);
114		key += r;
115		key_len -= r;
116	};
117	bzero(asalt, salt_len + 4);
118	free(asalt);
119	bzero(d1, sizeof(d1));
120	bzero(d2, sizeof(d2));
121	bzero(obuf, sizeof(obuf));
122
123	return 0;
124}
125
126#ifdef PBKDF2_MAIN
127struct test_vector {
128	u_int rounds;
129	const char *pass;
130	const char *salt;
131	const char expected[32];
132};
133
134/*
135 * Test vectors from RFC 3962
136 */
137struct test_vector test_vectors[] = {
138	{
139		1,
140		"password",
141		"ATHENA.MIT.EDUraeburn",
142		{
143			0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01,
144			0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15,
145			0x0a, 0xd1, 0xf7, 0xa0, 0x4b, 0xb9, 0xf3, 0xa3,
146			0x33, 0xec, 0xc0, 0xe2, 0xe1, 0xf7, 0x08, 0x37
147		},
148	}, {
149		2,
150		"password",
151		"ATHENA.MIT.EDUraeburn",
152		{
153			0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e,
154			0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d,
155			0xa0, 0x53, 0x78, 0xb9, 0x32, 0x44, 0xec, 0x8f,
156			0x48, 0xa9, 0x9e, 0x61, 0xad, 0x79, 0x9d, 0x86
157		},
158	}, {
159		1200,
160		"password",
161		"ATHENA.MIT.EDUraeburn",
162		{
163			0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e,
164			0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b,
165			0xa7, 0xe5, 0x2d, 0xdb, 0xc5, 0xe5, 0x14, 0x2f,
166			0x70, 0x8a, 0x31, 0xe2, 0xe6, 0x2b, 0x1e, 0x13
167		},
168	}, {
169		5,
170		"password",
171		"\0224VxxV4\022", /* 0x1234567878563412 */
172		{
173			0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6,
174			0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49,
175			0x3f, 0x98, 0xd2, 0x03, 0xe6, 0xbe, 0x49, 0xa6,
176			0xad, 0xf4, 0xfa, 0x57, 0x4b, 0x6e, 0x64, 0xee
177		},
178	}, {
179		1200,
180		"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
181		"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
182		"pass phrase equals block size",
183		{
184			0x13, 0x9c, 0x30, 0xc0, 0x96, 0x6b, 0xc3, 0x2b,
185			0xa5, 0x5f, 0xdb, 0xf2, 0x12, 0x53, 0x0a, 0xc9,
186			0xc5, 0xec, 0x59, 0xf1, 0xa4, 0x52, 0xf5, 0xcc,
187			0x9a, 0xd9, 0x40, 0xfe, 0xa0, 0x59, 0x8e, 0xd1
188		},
189	}, {
190		1200,
191		"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
192		"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
193		"pass phrase exceeds block size",
194		{
195			0x9c, 0xca, 0xd6, 0xd4, 0x68, 0x77, 0x0c, 0xd5,
196			0x1b, 0x10, 0xe6, 0xa6, 0x87, 0x21, 0xbe, 0x61,
197			0x1a, 0x8b, 0x4d, 0x28, 0x26, 0x01, 0xdb, 0x3b,
198			0x36, 0xbe, 0x92, 0x46, 0x91, 0x5e, 0xc8, 0x2a
199		},
200	}, {
201		50,
202		"\360\235\204\236", /* g-clef (0xf09d849e) */
203		"EXAMPLE.COMpianist",
204		{
205			0x6b, 0x9c, 0xf2, 0x6d, 0x45, 0x45, 0x5a, 0x43,
206			0xa5, 0xb8, 0xbb, 0x27, 0x6a, 0x40, 0x3b, 0x39,
207			0xe7, 0xfe, 0x37, 0xa0, 0xc4, 0x1e, 0x02, 0xc2,
208			0x81, 0xff, 0x30, 0x69, 0xe1, 0xe9, 0x4f, 0x52
209		},
210	}
211};
212#define NVECS (sizeof(test_vectors) / sizeof(*test_vectors))
213
214#include <stdio.h>
215#include <err.h>
216
217static void
218printhex(const char *s, const u_int8_t *buf, size_t len)
219{
220	size_t i;
221
222	printf("%s: ", s);
223	for (i = 0; i < len; i++)
224		printf("%02x", buf[i]);
225	printf("\n");
226	fflush(stdout);
227}
228
229int
230main(int argc, char **argv)
231{
232	u_int i, j;
233	u_char result[32];
234	struct test_vector *vec;
235
236	for (i = 0; i < NVECS; i++) {
237		vec = &test_vectors[i];
238		printf("vector %u\n", i);
239		for (j = 1; j < sizeof(result); j += 3) {
240			if (pkcs5_pbkdf2(vec->pass, strlen(vec->pass),
241			    vec->salt, strlen(vec->salt),
242			    result, j, vec->rounds) != 0)
243			errx(1, "pbkdf2 failed");
244			if (memcmp(result, vec->expected, j) != 0) {
245				printhex(" got", result, j);
246				printhex("want", vec->expected, j);
247				return 1;
248			}
249		}
250	}
251	return 0;
252}
253#endif /* PBKDF2_MAIN */
254