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