1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/crypto/builtin/pbkdf2.c - Implementation of PBKDF2 from RFC 2898 */
3 /*
4 * Copyright 2002, 2008 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include <ctype.h>
28 #include "crypto_int.h"
29
30 #ifdef K5_BUILTIN_PBKDF2
31
32 /*
33 * RFC 2898 specifies PBKDF2 in terms of an underlying pseudo-random
34 * function with two arguments (password and salt||blockindex). Right
35 * now we only use PBKDF2 with the hmac-sha1 PRF, also specified in
36 * RFC 2898, which invokes HMAC with the password as the key and the
37 * second argument as the text. (HMAC accepts any key size up to the
38 * block size; the password is pre-hashed with unkeyed SHA1 if it is
39 * longer than the block size.)
40 *
41 * For efficiency, it is better to generate the key from the password
42 * once at the beginning, so we specify prf_fn in terms of a
43 * krb5_key first argument. That might not be convenient for a PRF
44 * which uses the password in some other way, so this might need to be
45 * adjusted in the future.
46 */
47
48 typedef krb5_error_code (*prf_fn)(krb5_key pass, krb5_data *salt,
49 krb5_data *out);
50
51 static int debug_hmac = 0;
52
printd(const char * descr,krb5_data * d)53 static void printd (const char *descr, krb5_data *d) {
54 unsigned int i, j;
55 const int r = 16;
56
57 printf("%s:", descr);
58
59 for (i = 0; i < d->length; i += r) {
60 printf("\n %04x: ", i);
61 for (j = i; j < i + r && j < d->length; j++)
62 printf(" %02x", 0xff & d->data[j]);
63 for (; j < i + r; j++)
64 printf(" ");
65 printf(" ");
66 for (j = i; j < i + r && j < d->length; j++) {
67 int c = 0xff & d->data[j];
68 printf("%c", isprint(c) ? c : '.');
69 }
70 }
71 printf("\n");
72 }
73
74 /*
75 * Implements the hmac-sha1 PRF. pass has been pre-hashed (if
76 * necessary) and converted to a key already; salt has had the block
77 * index appended to the original salt.
78 *
79 * NetBSD 8 declares an hmac() function in stdlib.h, so avoid that name.
80 */
81 static krb5_error_code
k5_hmac(const struct krb5_hash_provider * hash,krb5_keyblock * pass,krb5_data * salt,krb5_data * out)82 k5_hmac(const struct krb5_hash_provider *hash, krb5_keyblock *pass,
83 krb5_data *salt, krb5_data *out)
84 {
85 krb5_error_code err;
86 krb5_crypto_iov iov;
87
88 if (debug_hmac)
89 printd(" hmac input", salt);
90 iov.flags = KRB5_CRYPTO_TYPE_DATA;
91 iov.data = *salt;
92 err = krb5int_hmac_keyblock(hash, pass, &iov, 1, out);
93 if (err == 0 && debug_hmac)
94 printd(" hmac output", out);
95 return err;
96 }
97
98 static krb5_error_code
F(char * output,char * u_tmp1,char * u_tmp2,const struct krb5_hash_provider * hash,size_t hlen,krb5_keyblock * pass,const krb5_data * salt,unsigned long count,int i)99 F(char *output, char *u_tmp1, char *u_tmp2,
100 const struct krb5_hash_provider *hash, size_t hlen, krb5_keyblock *pass,
101 const krb5_data *salt, unsigned long count, int i)
102 {
103 unsigned char ibytes[4];
104 unsigned int j, k;
105 krb5_data sdata;
106 krb5_data out;
107 krb5_error_code err;
108
109 /* Compute U_1. */
110 store_32_be(i, ibytes);
111
112 memcpy(u_tmp2, salt->data, salt->length);
113 memcpy(u_tmp2 + salt->length, ibytes, 4);
114 sdata = make_data(u_tmp2, salt->length + 4);
115
116 out = make_data(u_tmp1, hlen);
117
118 err = k5_hmac(hash, pass, &sdata, &out);
119 if (err)
120 return err;
121
122 memcpy(output, u_tmp1, hlen);
123
124 /* Compute U_2, .. U_c. */
125 sdata.length = hlen;
126 for (j = 2; j <= count; j++) {
127 memcpy(u_tmp2, u_tmp1, hlen);
128 err = k5_hmac(hash, pass, &sdata, &out);
129 if (err)
130 return err;
131
132 /* And xor them together. */
133 for (k = 0; k < hlen; k++)
134 output[k] ^= u_tmp1[k];
135 }
136 return 0;
137 }
138
139 static krb5_error_code
pbkdf2(const struct krb5_hash_provider * hash,krb5_keyblock * pass,const krb5_data * salt,unsigned long count,const krb5_data * output)140 pbkdf2(const struct krb5_hash_provider *hash, krb5_keyblock *pass,
141 const krb5_data *salt, unsigned long count, const krb5_data *output)
142 {
143 size_t hlen = hash->hashsize;
144 int l, i;
145 char *utmp1, *utmp2;
146 char utmp3[128]; /* XXX length shouldn't be hardcoded! */
147
148 if (output->length == 0 || hlen == 0)
149 abort();
150 /* Step 1 & 2. */
151 if (output->length / hlen > 0xffffffff)
152 abort();
153 /* Step 2. */
154 l = (output->length + hlen - 1) / hlen;
155
156 utmp1 = /*output + dklen; */ malloc(hlen);
157 if (utmp1 == NULL)
158 return ENOMEM;
159 utmp2 = /*utmp1 + hlen; */ malloc(salt->length + 4 + hlen);
160 if (utmp2 == NULL) {
161 free(utmp1);
162 return ENOMEM;
163 }
164
165 /* Step 3. */
166 for (i = 1; i <= l; i++) {
167 krb5_error_code err;
168 char *out;
169
170 if (i == l)
171 out = utmp3;
172 else
173 out = output->data + (i-1) * hlen;
174 err = F(out, utmp1, utmp2, hash, hlen, pass, salt, count, i);
175 if (err) {
176 free(utmp1);
177 free(utmp2);
178 return err;
179 }
180 if (i == l)
181 memcpy(output->data + (i-1) * hlen, utmp3,
182 output->length - (i-1) * hlen);
183
184 }
185 free(utmp1);
186 free(utmp2);
187 return 0;
188 }
189
190 krb5_error_code
krb5int_pbkdf2_hmac(const struct krb5_hash_provider * hash,const krb5_data * out,unsigned long count,const krb5_data * pass,const krb5_data * salt)191 krb5int_pbkdf2_hmac(const struct krb5_hash_provider *hash,
192 const krb5_data *out, unsigned long count,
193 const krb5_data *pass, const krb5_data *salt)
194 {
195 krb5_keyblock keyblock;
196 char tmp[128];
197 krb5_data d;
198 krb5_crypto_iov iov;
199 krb5_error_code err;
200
201 assert(hash->hashsize <= sizeof(tmp));
202 if (pass->length > hash->blocksize) {
203 d = make_data(tmp, hash->hashsize);
204 iov.flags = KRB5_CRYPTO_TYPE_DATA;
205 iov.data = *pass;
206 err = hash->hash(&iov, 1, &d);
207 if (err)
208 return err;
209 keyblock.length = d.length;
210 keyblock.contents = (krb5_octet *) d.data;
211 } else {
212 keyblock.length = pass->length;
213 keyblock.contents = (krb5_octet *) pass->data;
214 }
215 keyblock.enctype = ENCTYPE_NULL;
216
217 err = pbkdf2(hash, &keyblock, salt, count, out);
218 return err;
219 }
220
221 #endif /* K5_BUILTIN_PBKDF2 */
222