blob: a329e8d52bd418566eba7079ee8286ca2d22d149 [file] [log] [blame]
Alexandre Lision907ed2e2014-02-04 10:33:09 -05001#include <stdint.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5
6#include <crypto/hmac256.h>
7
8/*
9HKDF-Expand(PRK, info, L)
10
11Description in RFC 5869
12
13 HKDF-Expand(PRK, info, L) -> OKM
14
15 Options:
16 Hash a hash function; HashLen denotes the length of the
17 hash function output in octets
18 Inputs:
19 PRK a pseudorandom key of at least HashLen octets
20 (usually, the output from the extract step)
21 info optional context and application specific information
22 (can be a zero-length string)
23 L length of output keying material in octets
24 (<= 255*HashLen)
25
26 Output:
27 OKM output keying material (of L octets)
28
29 The output OKM is calculated as follows:
30
31 N = ceil(L/HashLen)
32 T = T(1) | T(2) | T(3) | ... | T(N)
33 OKM = first L octets of T
34
35 where:
36 T(0) = empty string (zero length)
37 T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
38 T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
39 T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
40 ...
41
42 (where the constant concatenated to the end of each T(n) is a
43 single octet.)
44
45
46 A.1. Test Case 1
47
48 Basic test case with SHA-256
49
50 Hash = SHA-256
51 IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
52 salt = 0x000102030405060708090a0b0c (13 octets)
53 info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets)
54 L = 42
55
56 PRK = 0x077709362c2e32df0ddc3f0dc47bba63
57 90b6c73bb50f9c3122ec844ad7c2b3e5 (32 octets)
58 OKM = 0x3cb25f25faacd57a90434f64d0362f2a
59 2d2d0a90cf1a5a4c5db02d56ecc4c5bf
60 34007208d5b887185865 (42 octets)
61
62A.2. Test Case 2
63
64 Test with SHA-256 and longer inputs/outputs
65
66 Hash = SHA-256
67 IKM = 0x000102030405060708090a0b0c0d0e0f
68 101112131415161718191a1b1c1d1e1f
69 202122232425262728292a2b2c2d2e2f
70 303132333435363738393a3b3c3d3e3f
71 404142434445464748494a4b4c4d4e4f (80 octets)
72 salt = 0x606162636465666768696a6b6c6d6e6f
73 707172737475767778797a7b7c7d7e7f
74 808182838485868788898a8b8c8d8e8f
75 909192939495969798999a9b9c9d9e9f
76 a0a1a2a3a4a5a6a7a8a9aaabacadaeaf (80 octets)
77 info = 0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
78 c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
79 d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
80 e0e1e2e3e4e5e6e7e8e9eaebecedeeef
81 f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff (80 octets)
82 L = 82
83
84 PRK = 0x06a6b88c5853361a06104c9ceb35b45c
85 ef760014904671014a193f40c15fc244 (32 octets)
86 OKM = 0xb11e398dc80327a1c8e7f78c596a4934
87 4f012eda2d4efad8a050cc4c19afa97c
88 59045a99cac7827271cb41c65e590e09
89 da3275600c2f09b8367793a9aca3db71
90 cc30c58179ec3e87c14c01d5c1f3434f
91 1d87 (82 octets)
92
93A.3. Test Case 3
94
95 Test with SHA-256 and zero-length salt/info
96
97 Hash = SHA-256
98 IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
99 salt = (0 octets)
100 info = (0 octets)
101 L = 42
102
103 PRK = 0x19ef24a32c717b167f33a91d6f648bdf
104 96596776afdb6377ac434c1c293ccb04 (32 octets)
105 OKM = 0x8da4e775a563c18f715f802a063c5a31
106 b8a11f5c5ee1879ec3454e5f3c738d2d
107 9d201395faa4b61a96c8 (42 octets)
108
109*/
110
111static void hexdump(const char* title, const unsigned char *s, int l)
112{
113 int n=0;
114
115 if (s == NULL) return;
116
117 fprintf(stderr, "%s",title);
118 for( ; n < l ; ++n) {
119 if((n%16) == 0)
120 fprintf(stderr, "\n%04x",n);
121 fprintf(stderr, " %02x",s[n]);
122 }
123 fprintf(stderr, "\n");
124}
125
126
127static uint8_t info_A1[] = {
128 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9};
129
130static int32_t L_A1 = 42;
131
132static uint8_t PRK_A1[] = {
133 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
134 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5};
135
136static uint8_t OKM_A1[] = {
137 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
138 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
139 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65}; // (42 octets)
140
141
142static int32_t L_A3 = 42;
143
144static uint8_t PRK_A3[] = {
145 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf,
146 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04}; // (32 octets)
147
148static uint8_t OKM_A3[] = {
149 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31,
150 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d,
151 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8}; // (42 octets)
152
153
154
155void* createSha256HmacContext(uint8_t* key, int32_t keyLength);
156void freeSha256HmacContext(void* ctx);
157void hmacSha256Ctx(void* ctx, const uint8_t* data[], uint32_t dataLength[], uint8_t* mac, int32_t* macLength );
158
159
160static int expand(uint8_t* prk, uint32_t prkLen, uint8_t* info, int32_t infoLen, int32_t L, uint32_t hashLen, uint8_t* outbuffer)
161{
162 int32_t n;
163 uint8_t *T;
164 void* hmacCtx;
165
166 const uint8_t* data[4]; // Data pointers for HMAC data, max. 3 plus terminating NULL
167 uint32_t dataLen[4];
168 int32_t dataIdx = 0;
169
170 uint8_t counter;
171 int32_t macLength;
172
173 if (prkLen < hashLen)
174 return -1;
175
176 n = (L + (hashLen-1)) / hashLen;
177
178 // T points to buffer that holds concatenated T(1) || T(2) || ... T(N))
179 T = reinterpret_cast<uint8_t*>(malloc(n * hashLen));
180
181 // Prepare the HMAC
182 hmacCtx = createSha256HmacContext(prk, prkLen);
183
184 // Prepare first HMAC. T(0) has zero length, thus we ignore it in first run.
185 // After first run use its output (T(1)) as first data in next HMAC run.
186 for (int i = 1; i <= n; i++) {
187 if (infoLen > 0 && info != NULL) {
188 data[dataIdx] = info;
189 dataLen[dataIdx++] = infoLen;
190 }
191 counter = i & 0xff;
192 data[dataIdx] = &counter;
193 dataLen[dataIdx++] = 1;
194
195 data[dataIdx] = NULL;
196 dataLen[dataIdx++] = 0;
197
198 hmacSha256Ctx(hmacCtx, data, dataLen, T + ((i-1) * hashLen), &macLength);
199
200 dataIdx = 0;
201 data[dataIdx] = T + ((i-1) * hashLen);
202 dataLen[dataIdx++] = hashLen;
203 }
204 freeSha256HmacContext(hmacCtx);
205 memcpy(outbuffer, T, L);
206 free(T);
207 return 0;
208}
209
210int main(int argc, char *argv[])
211{
212 uint8_t buffer[500];
213 expand(PRK_A1, sizeof(PRK_A1), info_A1, sizeof(info_A1), L_A1, SHA256_DIGEST_LENGTH, buffer);
214 if (memcmp(buffer, OKM_A1, L_A1) != 0) {
215 fprintf(stderr, "ERROR: Test result A1 mismatch");
216 hexdump("Computed result of expand A1", buffer, L_A1);
217 hexdump("Expected result of expand A1", OKM_A1, L_A1);
218 return 1;
219 }
220
221 expand(PRK_A3, sizeof(PRK_A3), NULL, 0, L_A3, SHA256_DIGEST_LENGTH, buffer);
222 if (memcmp(buffer, OKM_A3, L_A3) != 0) {
223 fprintf(stderr, "ERROR: Test result A3 mismatch");
224 hexdump("Computed result of expand A3", buffer, L_A3);
225 hexdump("Expected result of expand A3", OKM_A3, L_A3);
226 return 1;
227 }
228
229 printf("Done\n");
230 return 0;
231}