xref: /netbsd/sbin/cgdconfig/pkcs5_pbkdf2.c (revision c4a72b64)
1 /* $NetBSD: pkcs5_pbkdf2.c,v 1.1 2002/10/04 18:37:20 elric Exp $ */
2 
3 /*-
4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Roland C. Dowdeswell.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * This code is an implementation of PKCS #5 PBKDF2 which is described
41  * in:
42  *
43  * ``PKCS #5 v2.0: Password-Based Cryptography Standard'', RSA Laboratories,
44  * March 25, 1999.
45  *
46  * and can be found at the following URL:
47  *
48  *	http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/
49  *
50  * It was also republished as RFC 2898.
51  */
52 
53 
54 #include <sys/cdefs.h>
55 #ifndef lint
56 __RCSID("$NetBSD: pkcs5_pbkdf2.c,v 1.1 2002/10/04 18:37:20 elric Exp $");
57 #endif
58 
59 #include <assert.h>
60 #include <malloc.h>
61 #include <stdlib.h>
62 #include <string.h>
63 
64 #include <openssl/hmac.h>
65 
66 #include "pkcs5_pbkdf2.h"
67 #include "utils.h"
68 
69 static void	int_encode(u_int8_t *, int);
70 static void	prf_iterate(u_int8_t *, const u_int8_t *, int,
71 			    const u_int8_t *, int, int, int);
72 
73 #define PRF_BLOCKLEN	20
74 
75 /*
76  * int_encode encodes i as a four octet integer, most significant
77  * octet first.  (from the end of Step 3).
78  */
79 
80 static void
81 int_encode(u_int8_t *res, int i)
82 {
83 
84 	*res++ = (i >> 24) & 0xff;
85 	*res++ = (i >> 16) & 0xff;
86 	*res++ = (i >>  8) & 0xff;
87 	*res   = (i      ) & 0xff;
88 }
89 
90 void
91 prf_iterate(u_int8_t *r, const u_int8_t *P, int Plen,
92 	    const u_int8_t *S, int Slen, int c, int ind)
93 {
94 	int		 first_time = 1;
95 	int		 i;
96 	int		 datalen;
97 	int		 tmplen;
98 	u_int8_t	*data;
99 	u_int8_t	 tmp[EVP_MAX_MD_SIZE];
100 
101 	data = malloc(Slen + 4);
102 	memcpy(data, S, Slen);
103 	int_encode(data + Slen, ind);
104 	datalen = Slen + 4;
105 
106 	for (i=0; i < c; i++) {
107 		HMAC(EVP_sha1(), P, Plen, data, datalen, tmp, &tmplen);
108 
109 		assert(tmplen == PRF_BLOCKLEN);
110 
111 		if (first_time) {
112 			memcpy(r, tmp, PRF_BLOCKLEN);
113 			first_time = 0;
114 		} else
115 			memxor(r, tmp, PRF_BLOCKLEN);
116 		memcpy(data, tmp, PRF_BLOCKLEN);
117 		datalen = PRF_BLOCKLEN;
118 	}
119 	free(data);
120 }
121 
122 /*
123  * pkcs5_pbkdf2 takes all of its lengths in bytes.
124  */
125 
126 int
127 pkcs5_pbkdf2(u_int8_t **r, int dkLen, const u_int8_t *P, int Plen,
128 	     const u_int8_t *S, int Slen, int c)
129 {
130 	int	i;
131 	int	l;
132 
133 	/* sanity */
134 	if (!r)
135 		return -1;
136 	if (dkLen <= 0)
137 		return -1;
138 	if (c < 1)
139 		return -1;
140 
141 	/* Step 2 */
142 	l = (dkLen + PRF_BLOCKLEN - 1) / PRF_BLOCKLEN;
143 
144 	/* allocate the output */
145 	*r = malloc(l * PRF_BLOCKLEN);
146 	if (!*r)
147 		return -1;
148 
149 	/* Step 3 */
150 	for (i=0; i < l; i++)
151 		prf_iterate(*r + (PRF_BLOCKLEN * i), P, Plen, S, Slen, c, i);
152 
153 	/* Step 4 and 5
154 	 *  by the structure of the code, we do not need to concatenate
155 	 *  the blocks, they're already concatenated.  We do not extract
156 	 *  the first dkLen octets, since we [naturally] assume that the
157 	 *  calling function will use only the octets that it needs and
158 	 *  the free(3) will free all of the allocated memory.
159 	 */
160 	return 0;
161 }
162