ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/hkdf.C
Revision: 1.1
Committed: Tue Jul 16 16:44:36 2013 UTC (10 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Log Message:
3.x

File Contents

# Content
1 /*
2 hkdf.C -- RFC 5869 HKDF implementation
3 Copyright (C) 2013 Marc Lehmann <gvpe@schmorp.de>
4
5 This file is part of GVPE.
6
7 GVPE is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, see <http://www.gnu.org/licenses/>.
19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this Program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a modified
24 version of that library), containing parts covered by the terms of the
25 OpenSSL or SSLeay licenses, the licensors of this Program grant you
26 additional permission to convey the resulting work. Corresponding
27 Source for a non-source form of such a combination shall include the
28 source code for the parts of OpenSSL used as well as that of the
29 covered work.
30 */
31
32 #include "config.h"
33
34 #include <cstring>
35
36 #include <openssl/rand.h>
37 #include <openssl/hmac.h>
38
39 #include "util.h"
40 #include "hkdf.h"
41
42 hkdf::hkdf (const void *salt, int len, const EVP_MD *hash)
43 {
44 HMAC_CTX_init (&ctx);
45
46 if (!salt)
47 {
48 memset (prk, 0, sizeof prk);
49 salt = prk;
50 len = EVP_MD_size (hash);
51 }
52
53 require (HMAC_Init_ex (&ctx, salt, len, hash, 0));
54 }
55
56 hkdf::~hkdf ()
57 {
58 HMAC_CTX_cleanup (&ctx);
59 }
60
61 void
62 hkdf::extract (const void *ikm, int len)
63 {
64 require (HMAC_Update (&ctx, (u8 *)ikm, len));
65 }
66
67 void
68 hkdf::extract_done ()
69 {
70 require (HMAC_Final (&ctx, prk, 0));
71 }
72
73 void
74 hkdf::expand (void *okm, int len, const void *info, int infolen)
75 {
76 u8 tn[sizeof prk];
77 u8 iter = 0;
78 int md_size = HMAC_size (&ctx);
79
80 while (len)
81 {
82 require (HMAC_Init_ex (&ctx, prk, md_size, 0, 0));
83
84 if (iter)
85 require (HMAC_Update (&ctx, tn, md_size));
86
87 require (HMAC_Update (&ctx, (u8 *)info, infolen));
88
89
90 ++iter;
91 require (iter);
92
93 require (HMAC_Update (&ctx, &iter, 1));
94
95 require (HMAC_Final (&ctx, tn, 0));
96
97 int ol = len > md_size ? md_size : len;
98
99 memcpy (okm, tn, ol);
100
101 okm = (void *)(ol + (char *)okm);
102 len -= ol;
103 }
104 }
105
106 // try to verify all test vectors from the RFC
107 // since I implemented the hkdf myself, and I am no crypto expert,
108 // we run verification on every startup.
109 void
110 hkdf::verify ()
111 {
112 struct unhex
113 {
114 u8 *p;
115 int l;
116
117 u8 s[256];
118
119 unhex (const char *hs)
120 {
121 l = 0;
122 p = 0;
123
124 if (!hs)
125 return;
126
127 p = s;
128
129 while (*hs)
130 {
131 int d1 = *hs >= '0' && *hs <= '9' ? *hs - '0' : *hs - 'a' + 10; ++hs;
132 int d2 = *hs >= '0' && *hs <= '9' ? *hs - '0' : *hs - 'a' + 10; ++hs;
133
134 *p++ = d1 * 16 + d2;
135 ++l;
136 }
137
138 p = s;
139 }
140 };
141
142 const struct hkdf_test
143 {
144 int hash;
145 const char *IKM, *salt, *info;
146 const char *PRK, *OKM;
147 } tests[] = {
148 { // 0
149 256,
150 "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
151 "000102030405060708090a0b0c",
152 "f0f1f2f3f4f5f6f7f8f9",
153 "077709362c2e32df0ddc3f0dc47bba63"
154 "90b6c73bb50f9c3122ec844ad7c2b3e5",
155 "3cb25f25faacd57a90434f64d0362f2a"
156 "2d2d0a90cf1a5a4c5db02d56ecc4c5bf"
157 "34007208d5b887185865"
158 }, { // 1
159 256,
160 "000102030405060708090a0b0c0d0e0f"
161 "101112131415161718191a1b1c1d1e1f"
162 "202122232425262728292a2b2c2d2e2f"
163 "303132333435363738393a3b3c3d3e3f"
164 "404142434445464748494a4b4c4d4e4f",
165 "606162636465666768696a6b6c6d6e6f"
166 "707172737475767778797a7b7c7d7e7f"
167 "808182838485868788898a8b8c8d8e8f"
168 "909192939495969798999a9b9c9d9e9f"
169 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
170 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
171 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
172 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
173 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
174 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
175 "06a6b88c5853361a06104c9ceb35b45c"
176 "ef760014904671014a193f40c15fc244",
177 "b11e398dc80327a1c8e7f78c596a4934"
178 "4f012eda2d4efad8a050cc4c19afa97c"
179 "59045a99cac7827271cb41c65e590e09"
180 "da3275600c2f09b8367793a9aca3db71"
181 "cc30c58179ec3e87c14c01d5c1f3434f"
182 "1d87"
183 }, { // 2
184 256,
185 "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
186 "",
187 "",
188 "19ef24a32c717b167f33a91d6f648bdf"
189 "96596776afdb6377ac434c1c293ccb04",
190 "8da4e775a563c18f715f802a063c5a31"
191 "b8a11f5c5ee1879ec3454e5f3c738d2d"
192 "9d201395faa4b61a96c8"
193 }, { // 3
194 1,
195 "0b0b0b0b0b0b0b0b0b0b0b",
196 "000102030405060708090a0b0c",
197 "f0f1f2f3f4f5f6f7f8f9",
198 "9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243",
199 "085a01ea1b10f36933068b56efa5ad81"
200 "a4f14b822f5b091568a9cdd4f155fda2"
201 "c22e422478d305f3f896"
202 }, { // 4
203 1,
204 "000102030405060708090a0b0c0d0e0f"
205 "101112131415161718191a1b1c1d1e1f"
206 "202122232425262728292a2b2c2d2e2f"
207 "303132333435363738393a3b3c3d3e3f"
208 "404142434445464748494a4b4c4d4e4f",
209 "606162636465666768696a6b6c6d6e6f"
210 "707172737475767778797a7b7c7d7e7f"
211 "808182838485868788898a8b8c8d8e8f"
212 "909192939495969798999a9b9c9d9e9f"
213 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
214 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
215 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
216 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
217 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
218 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
219 "8adae09a2a307059478d309b26c4115a224cfaf6",
220 "0bd770a74d1160f7c9f12cd5912a06eb"
221 "ff6adcae899d92191fe4305673ba2ffe"
222 "8fa3f1a4e5ad79f3f334b3b202b2173c"
223 "486ea37ce3d397ed034c7f9dfeb15c5e"
224 "927336d0441f4c4300e2cff0d0900b52"
225 "d3b4"
226 }, { // 5
227 1,
228 "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
229 "",
230 "",
231 "da8c8a73c7fa77288ec6f5e7c297786aa0d32d01",
232 "0ac1af7002b3d761d1e55298da9d0506"
233 "b9ae52057220a306e07b6b87e8df21d0"
234 "ea00033de03984d34918"
235 }, { // 6
236 1,
237 "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
238 0,
239 "",
240 "2adccada18779e7c2077ad2eb19d3f3e731385dd",
241 "2c91117204d745f3500d636a62f64f0a"
242 "b3bae548aa53d423b0d1f27ebba6f5e5"
243 "673a081d70cce7acfc48"
244 }
245 };
246
247 for (int i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
248 {
249 const hkdf_test &test = tests[i];
250
251 unhex salt (test.salt);
252 unhex ikm (test.IKM);
253 unhex info (test.info);
254 unhex prk_correct (test.PRK);
255 unhex okm_correct (test.OKM);
256
257 char okm[256];
258
259 hkdf h (salt.p, salt.l, test.hash == 1 ? EVP_sha1 () : EVP_sha256 ());
260 h.extract (ikm.p, ikm.l);
261 h.extract_done ();
262 h.expand (okm, okm_correct.l, info.p, info.l);
263
264 require (!memcmp (h.prk, prk_correct.p, prk_correct.l));
265 require (!memcmp (okm , okm_correct.p, okm_correct.l));
266 }
267 }
268