1 | /* pkcs5.c Partial Password-Based Cryptography (PKCS#5) implementation |
2 | * Copyright (C) 2002 Free Software Foundation, Inc. |
3 | * |
4 | * This file is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This file is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this file; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
17 | * |
18 | */ |
19 | |
20 | #include "gcrypt.h" |
21 | |
22 | /* |
23 | * 5.2 PBKDF2 |
24 | * |
25 | * PBKDF2 applies a pseudorandom function (see Appendix B.1 for an |
26 | * example) to derive keys. The length of the derived key is essentially |
27 | * unbounded. (However, the maximum effective search space for the |
28 | * derived key may be limited by the structure of the underlying |
29 | * pseudorandom function. See Appendix B.1 for further discussion.) |
30 | * PBKDF2 is recommended for new applications. |
31 | * |
32 | * PBKDF2 (P, S, c, dkLen) |
33 | * |
34 | * Options: PRF underlying pseudorandom function (hLen |
35 | * denotes the length in octets of the |
36 | * pseudorandom function output) |
37 | * |
38 | * Input: P password, an octet string |
39 | * S salt, an octet string |
40 | * c iteration count, a positive integer |
41 | * dkLen intended length in octets of the derived |
42 | * key, a positive integer, at most |
43 | * (2^32 - 1) * hLen |
44 | * |
45 | * Output: DK derived key, a dkLen-octet string |
46 | */ |
47 | |
48 | static gcry_error_t gcry_pbkdf2(int PRF, |
49 | const char *P, |
50 | size_t Plen, |
51 | const char *S, |
52 | size_t Slen, |
53 | unsigned int c, |
54 | unsigned int dkLen, |
55 | char *DK) |
56 | { |
57 | gcry_md_hd_t prf; |
58 | gcry_error_t rc; |
59 | char *U; |
60 | unsigned int u; |
61 | unsigned int hLen; |
62 | unsigned int l; |
63 | unsigned int r; |
64 | unsigned char *p; |
65 | unsigned int i; |
66 | unsigned int k; |
67 | |
68 | hLen = gcry_md_get_algo_dlen(algo: PRF); |
69 | if (hLen == 0) |
70 | return GPG_ERR_UNSUPPORTED_ALGORITHM; |
71 | |
72 | if (c == 0) |
73 | return GPG_ERR_INV_ARG; |
74 | |
75 | if (dkLen == 0) |
76 | return GPG_ERR_TOO_SHORT; |
77 | |
78 | /* |
79 | * |
80 | * Steps: |
81 | * |
82 | * 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and |
83 | * stop. |
84 | */ |
85 | |
86 | if (dkLen > 4294967295U) |
87 | return GPG_ERR_TOO_LARGE; |
88 | |
89 | /* |
90 | * 2. Let l be the number of hLen-octet blocks in the derived key, |
91 | * rounding up, and let r be the number of octets in the last |
92 | * block: |
93 | * |
94 | * l = CEIL (dkLen / hLen) , |
95 | * r = dkLen - (l - 1) * hLen . |
96 | * |
97 | * Here, CEIL (x) is the "ceiling" function, i.e. the smallest |
98 | * integer greater than, or equal to, x. |
99 | */ |
100 | |
101 | l = dkLen / hLen; |
102 | if (dkLen % hLen) |
103 | l++; |
104 | r = dkLen - (l - 1) * hLen; |
105 | |
106 | /* |
107 | * 3. For each block of the derived key apply the function F defined |
108 | * below to the password P, the salt S, the iteration count c, and |
109 | * the block index to compute the block: |
110 | * |
111 | * T_1 = F (P, S, c, 1) , |
112 | * T_2 = F (P, S, c, 2) , |
113 | * ... |
114 | * T_l = F (P, S, c, l) , |
115 | * |
116 | * where the function F is defined as the exclusive-or sum of the |
117 | * first c iterates of the underlying pseudorandom function PRF |
118 | * applied to the password P and the concatenation of the salt S |
119 | * and the block index i: |
120 | * |
121 | * F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c |
122 | * |
123 | * where |
124 | * |
125 | * U_1 = PRF (P, S || INT (i)) , |
126 | * U_2 = PRF (P, U_1) , |
127 | * ... |
128 | * U_c = PRF (P, U_{c-1}) . |
129 | * |
130 | * Here, INT (i) is a four-octet encoding of the integer i, most |
131 | * significant octet first. |
132 | * |
133 | * 4. Concatenate the blocks and extract the first dkLen octets to |
134 | * produce a derived key DK: |
135 | * |
136 | * DK = T_1 || T_2 || ... || T_l<0..r-1> |
137 | * |
138 | * 5. Output the derived key DK. |
139 | * |
140 | * Note. The construction of the function F follows a "belt-and- |
141 | * suspenders" approach. The iterates U_i are computed recursively to |
142 | * remove a degree of parallelism from an opponent; they are exclusive- |
143 | * ored together to reduce concerns about the recursion degenerating |
144 | * into a small set of values. |
145 | * |
146 | */ |
147 | rc = gcry_md_open(h: &prf, algo: PRF, flags: GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE); |
148 | if (rc != GPG_ERR_NO_ERROR) |
149 | return rc; |
150 | |
151 | U = (char *)gcry_malloc(n: hLen); |
152 | if (!U) { |
153 | rc = GPG_ERR_ENOMEM; |
154 | goto done; |
155 | } |
156 | |
157 | for (i = 1; i <= l; i++) { |
158 | memset(s: DK + (i - 1) * hLen, c: 0, n: i == l ? r : hLen); |
159 | |
160 | for (u = 1; u <= c; u++) { |
161 | gcry_md_reset(hd: prf); |
162 | |
163 | rc = gcry_md_setkey(hd: prf, key: P, keylen: Plen); |
164 | if (rc != GPG_ERR_NO_ERROR) { |
165 | goto done; |
166 | } |
167 | if (u == 1) { |
168 | char tmp[4]; |
169 | gcry_md_write(hd: prf, buffer: S, length: Slen); |
170 | tmp[0] = (i & 0xff000000) >> 24; |
171 | tmp[1] = (i & 0x00ff0000) >> 16; |
172 | tmp[2] = (i & 0x0000ff00) >> 8; |
173 | tmp[3] = (i & 0x000000ff) >> 0; |
174 | gcry_md_write(hd: prf, buffer: tmp, length: 4); |
175 | } else |
176 | gcry_md_write(hd: prf, buffer: U, length: hLen); |
177 | |
178 | p = gcry_md_read(hd: prf, algo: PRF); |
179 | if (p == nullptr) { |
180 | rc = GPG_ERR_CONFIGURATION; |
181 | goto done; |
182 | } |
183 | |
184 | memcpy(dest: U, src: p, n: hLen); |
185 | for (k = 0; k < (i == l ? r : hLen); k++) |
186 | DK[(i - 1) * hLen + k] ^= U[k]; |
187 | } |
188 | } |
189 | |
190 | rc = GPG_ERR_NO_ERROR; |
191 | done: |
192 | gcry_md_close(hd: prf); |
193 | gcry_free(a: U); |
194 | return rc; |
195 | } |
196 | |