2 ---------------------------------------------------------------------------
3 Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved.
5 The redistribution and use of this software (with or without changes)
6 is allowed without the payment of fees or royalties provided that:
8 source code distributions include the above copyright notice, this
9 list of conditions and the following disclaimer;
11 binary distributions include the above copyright notice, this list
12 of conditions and the following disclaimer in their documentation.
14 This software is provided 'as is' with no explicit or implied warranties
15 in respect of its operation, including, but not limited to, correctness
16 and fitness for purpose.
17 ---------------------------------------------------------------------------
18 Issue Date: 20/12/2007
20 This is an implementation of RFC2898, which specifies key derivation from
21 a password and a salt value.
27 #if defined(__cplusplus)
32 void derive_key(const unsigned char pwd[], /* the PASSWORD */
33 unsigned int pwd_len, /* and its length */
34 const unsigned char salt[], /* the SALT and its */
35 unsigned int salt_len, /* length */
36 unsigned int iter, /* the number of iterations */
37 unsigned char key[], /* space for the output key */
38 unsigned int key_len)/* and its required length */
40 unsigned int i, j, k, n_blk, h_size;
41 unsigned char uu[HMAC_MAX_OUTPUT_SIZE], ux[HMAC_MAX_OUTPUT_SIZE];
42 hmac_ctx c1[1], c2[1], c3[1];
44 /* set HMAC context (c1) for password */
45 h_size = hmac_sha_begin(HMAC_SHA1, c1);
46 hmac_sha_key(pwd, pwd_len, c1);
48 /* set HMAC context (c2) for password and salt */
49 memcpy(c2, c1, sizeof(hmac_ctx));
50 hmac_sha_data(salt, salt_len, c2);
52 /* find the number of SHA blocks in the key */
53 n_blk = 1 + (key_len - 1) / h_size;
55 for(i = 0; i < n_blk; ++i) /* for each block in key */
57 /* ux[] holds the running xor value */
58 memset(ux, 0, h_size);
60 /* set HMAC context (c3) for password and salt */
61 memcpy(c3, c2, sizeof(hmac_ctx));
63 /* enter additional data for 1st block into uu */
64 uu[0] = (unsigned char)((i + 1) >> 24);
65 uu[1] = (unsigned char)((i + 1) >> 16);
66 uu[2] = (unsigned char)((i + 1) >> 8);
67 uu[3] = (unsigned char)(i + 1);
69 /* this is the key mixing iteration */
70 for(j = 0, k = 4; j < iter; ++j)
72 /* add previous round data to HMAC */
73 hmac_sha_data(uu, k, c3);
75 /* obtain HMAC for uu[] */
76 hmac_sha_end(uu, h_size, c3);
78 /* xor into the running xor block */
79 for(k = 0; k < h_size; ++k)
82 /* set HMAC context (c3) for password */
83 memcpy(c3, c1, sizeof(hmac_ctx));
86 /* compile key blocks into the key output */
87 j = 0; k = i * h_size;
88 while(j < h_size && k < key_len)
98 { unsigned int pwd_len;
99 unsigned int salt_len;
100 unsigned int it_count;
102 unsigned char salt[32];
103 unsigned char key[32];
106 { 8, 4, 5, (unsigned char*)"password",
108 0x12, 0x34, 0x56, 0x78
111 0x5c, 0x75, 0xce, 0xf0, 0x1a, 0x96, 0x0d, 0xf7,
112 0x4c, 0xb6, 0xb4, 0x9b, 0x9e, 0x38, 0xe6, 0xb5
115 { 8, 8, 5, (unsigned char*)"password",
117 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12
120 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6,
121 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49
124 { 8, 21, 1, (unsigned char*)"password",
126 "ATHENA.MIT.EDUraeburn"
129 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01,
130 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15
133 { 8, 21, 2, (unsigned char*)"password",
135 "ATHENA.MIT.EDUraeburn"
138 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e,
139 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d
142 { 8, 21, 1200, (unsigned char*)"password",
144 "ATHENA.MIT.EDUraeburn"
147 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e,
148 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b
154 { unsigned int i, j, key_len = 256;
155 unsigned char key[256];
157 printf("\nTest of RFC2898 Password Based Key Derivation");
158 for(i = 0; i < 5; ++i)
160 derive_key(tests[i].pwd, tests[i].pwd_len, tests[i].salt,
161 tests[i].salt_len, tests[i].it_count, key, key_len);
163 printf("\ntest %i: ", i + 1);
164 printf("key %s", memcmp(tests[i].key, key, 16) ? "is bad" : "is good");
165 for(j = 0; j < key_len && j < 64; j += 4)
169 printf("0x%02x%02x%02x%02x ", key[j], key[j + 1], key[j + 2], key[j + 3]);
171 printf(j < key_len ? " ... \n" : "\n");
177 #if defined(__cplusplus)