1 /*
2 ---------------------------------------------------------------------------
3 Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
4
5 LICENSE TERMS
6
7 The free distribution and use of this software in both source and binary
8 form is allowed (with or without changes) provided that:
9
10 1. distributions of this source code include the above copyright
11 notice, this list of conditions and the following disclaimer;
12
13 2. distributions in binary form include the above copyright
14 notice, this list of conditions and the following disclaimer
15 in the documentation and/or other associated materials;
16
17 3. the copyright holder's name is not used to endorse products
18 built using this software without specific written permission.
19
20 ALTERNATIVELY, provided that this notice is retained in full, this product
21 may be distributed under the terms of the GNU General Public License (GPL),
22 in which case the provisions of the GPL apply INSTEAD OF those given above.
23
24 DISCLAIMER
25
26 This software is provided 'as is' with no explicit or implied warranties
27 in respect of its properties, including, but not limited to, correctness
28 and/or fitness for purpose.
29 ---------------------------------------------------------------------------
30 Issue Date: 26/08/2003
31
32 This is an implementation of RFC2898, which specifies key derivation from
33 a password and a salt value.
34 */
35
36 #include <memory.h>
37 #include "hmac.h"
38
39 #if defined(__cplusplus)
40 extern "C"
41 {
42 #endif
43
derive_key(const unsigned char pwd[],unsigned int pwd_len,const unsigned char salt[],unsigned int salt_len,unsigned int iter,unsigned char key[],unsigned int key_len)44 void derive_key(const unsigned char pwd[], /* the PASSWORD */
45 unsigned int pwd_len, /* and its length */
46 const unsigned char salt[], /* the SALT and its */
47 unsigned int salt_len, /* length */
48 unsigned int iter, /* the number of iterations */
49 unsigned char key[], /* space for the output key */
50 unsigned int key_len)/* and its required length */
51 {
52 unsigned int i, j, k, n_blk;
53 unsigned char uu[HASH_OUTPUT_SIZE], ux[HASH_OUTPUT_SIZE];
54 hmac_ctx c1[1], c2[1], c3[1];
55
56 /* set HMAC context (c1) for password */
57 hmac_sha_begin(c1);
58 hmac_sha_key(pwd, pwd_len, c1);
59
60 /* set HMAC context (c2) for password and salt */
61 memcpy(c2, c1, sizeof(hmac_ctx));
62 hmac_sha_data(salt, salt_len, c2);
63
64 /* find the number of SHA blocks in the key */
65 n_blk = 1 + (key_len - 1) / HASH_OUTPUT_SIZE;
66
67 for(i = 0; i < n_blk; ++i) /* for each block in key */
68 {
69 /* ux[] holds the running xor value */
70 memset(ux, 0, HASH_OUTPUT_SIZE);
71
72 /* set HMAC context (c3) for password and salt */
73 memcpy(c3, c2, sizeof(hmac_ctx));
74
75 /* enter additional data for 1st block into uu */
76 uu[0] = (unsigned char)((i + 1) >> 24);
77 uu[1] = (unsigned char)((i + 1) >> 16);
78 uu[2] = (unsigned char)((i + 1) >> 8);
79 uu[3] = (unsigned char)(i + 1);
80
81 /* this is the key mixing iteration */
82 for(j = 0, k = 4; j < iter; ++j)
83 {
84 /* add previous round data to HMAC */
85 hmac_sha_data(uu, k, c3);
86
87 /* obtain HMAC for uu[] */
88 hmac_sha_end(uu, HASH_OUTPUT_SIZE, c3);
89
90 /* xor into the running xor block */
91 for(k = 0; k < HASH_OUTPUT_SIZE; ++k)
92 ux[k] ^= uu[k];
93
94 /* set HMAC context (c3) for password */
95 memcpy(c3, c1, sizeof(hmac_ctx));
96 }
97
98 /* compile key blocks into the key output */
99 j = 0; k = i * HASH_OUTPUT_SIZE;
100 while(j < HASH_OUTPUT_SIZE && k < key_len)
101 key[k++] = ux[j++];
102 }
103 }
104
105 #ifdef TEST
106
107 #include <stdio.h>
108
109 struct
110 { unsigned int pwd_len;
111 unsigned int salt_len;
112 unsigned int it_count;
113 unsigned char *pwd;
114 unsigned char salt[32];
115 unsigned char key[32];
116 } tests[] =
117 {
118 { 8, 4, 5, (unsigned char*)"password",
119 {
120 0x12, 0x34, 0x56, 0x78
121 },
122 {
123 0x5c, 0x75, 0xce, 0xf0, 0x1a, 0x96, 0x0d, 0xf7,
124 0x4c, 0xb6, 0xb4, 0x9b, 0x9e, 0x38, 0xe6, 0xb5
125 }
126 },
127 { 8, 8, 5, (unsigned char*)"password",
128 {
129 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12
130 },
131 {
132 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6,
133 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49
134 }
135 },
136 { 8, 21, 1, (unsigned char*)"password",
137 {
138 "ATHENA.MIT.EDUraeburn"
139 },
140 {
141 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01,
142 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15
143 }
144 },
145 { 8, 21, 2, (unsigned char*)"password",
146 {
147 "ATHENA.MIT.EDUraeburn"
148 },
149 {
150 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e,
151 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d
152 }
153 },
154 { 8, 21, 1200, (unsigned char*)"password",
155 {
156 "ATHENA.MIT.EDUraeburn"
157 },
158 {
159 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e,
160 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b
161 }
162 }
163 };
164
main()165 int main()
166 { unsigned int i, j, key_len = 256;
167 unsigned char key[256];
168
169 printf("\nTest of RFC2898 Password Based Key Derivation");
170 for(i = 0; i < 5; ++i)
171 {
172 derive_key(tests[i].pwd, tests[i].pwd_len, tests[i].salt,
173 tests[i].salt_len, tests[i].it_count, key, key_len);
174
175 printf("\ntest %i: ", i + 1);
176 printf("key %s", memcmp(tests[i].key, key, 16) ? "is bad" : "is good");
177 for(j = 0; j < key_len && j < 64; j += 4)
178 {
179 if(j % 16 == 0)
180 printf("\n");
181 printf("0x%02x%02x%02x%02x ", key[j], key[j + 1], key[j + 2], key[j + 3]);
182 }
183 printf(j < key_len ? " ... \n" : "\n");
184 }
185 printf("\n");
186 return 0;
187 }
188
189 #if defined(__cplusplus)
190 }
191 #endif
192
193 #endif
194