1 /* Copyright (c) 2015, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include <openssl/crypto.h>
19 #include <openssl/digest.h>
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 
23 #include "../internal.h"
24 
25 
26 // Prints out the data buffer as a sequence of hex bytes.
PrintDataHex(const void * data,size_t len)27 static void PrintDataHex(const void *data, size_t len) {
28   for (size_t i = 0; i < len; ++i) {
29     fprintf(stderr, "%02x", (int)((const uint8_t *)data)[i]);
30   }
31 }
32 
33 // Helper for testing that PBKDF2 derives the expected key from the given
34 // inputs. Returns 1 on success, 0 otherwise.
TestPBKDF2(const void * password,size_t password_len,const void * salt,size_t salt_len,unsigned iterations,const EVP_MD * digest,size_t key_len,const uint8_t * expected_key)35 static bool TestPBKDF2(const void *password, size_t password_len,
36                        const void *salt, size_t salt_len, unsigned iterations,
37                        const EVP_MD *digest, size_t key_len,
38                        const uint8_t *expected_key) {
39   uint8_t key[64];
40 
41   if (key_len > sizeof(key)) {
42     fprintf(stderr, "Output buffer is not large enough.\n");
43     return false;
44   }
45 
46   if (!PKCS5_PBKDF2_HMAC((const char *)password, password_len,
47                          (const uint8_t *)salt, salt_len, iterations, digest,
48                          key_len, key)) {
49     fprintf(stderr, "Call to PKCS5_PBKDF2_HMAC failed\n");
50     ERR_print_errors_fp(stderr);
51     return false;
52   }
53 
54   if (OPENSSL_memcmp(key, expected_key, key_len) != 0) {
55     fprintf(stderr, "Resulting key material does not match expectation\n");
56     fprintf(stderr, "Expected:\n    ");
57     PrintDataHex(expected_key, key_len);
58     fprintf(stderr, "\nActual:\n    ");
59     PrintDataHex(key, key_len);
60     fprintf(stderr, "\n");
61     return false;
62   }
63 
64   return true;
65 }
66 
67 // Tests deriving a key using an empty password (specified both as NULL and as
68 // non-NULL). Note that NULL has special meaning to HMAC initialization.
TestEmptyPassword()69 static bool TestEmptyPassword() {
70   const uint8_t kKey[] = {0xa3, 0x3d, 0xdd, 0xc3, 0x04, 0x78, 0x18,
71                           0x55, 0x15, 0x31, 0x1f, 0x87, 0x52, 0x89,
72                           0x5d, 0x36, 0xea, 0x43, 0x63, 0xa2};
73 
74   if (!TestPBKDF2(NULL, 0, "salt", 4, 1, EVP_sha1(), sizeof(kKey), kKey) ||
75       !TestPBKDF2("", 0, "salt", 4, 1, EVP_sha1(), sizeof(kKey), kKey)) {
76     return false;
77   }
78 
79   return true;
80 }
81 
82 // Tests deriving a key using an empty salt. Note that the expectation was
83 // generated using OpenSSL itself, and hence is not verified.
TestEmptySalt()84 static bool TestEmptySalt() {
85   const uint8_t kKey[] = {0x8b, 0xc2, 0xf9, 0x16, 0x7a, 0x81, 0xcd, 0xcf,
86                           0xad, 0x12, 0x35, 0xcd, 0x90, 0x47, 0xf1, 0x13,
87                           0x62, 0x71, 0xc1, 0xf9, 0x78, 0xfc, 0xfc, 0xb3,
88                           0x5e, 0x22, 0xdb, 0xea, 0xfa, 0x46, 0x34, 0xf6};
89 
90   if (!TestPBKDF2("password", 8, NULL, 0, 2, EVP_sha256(), sizeof(kKey),
91                   kKey) ||
92       !TestPBKDF2("password", 8, "", 0, 2, EVP_sha256(), sizeof(kKey), kKey)) {
93     return false;
94   }
95 
96   return true;
97 }
98 
99 // Exercises test vectors taken from https://tools.ietf.org/html/rfc6070.
100 // Note that each of these test vectors uses SHA-1 as the digest.
TestRFC6070Vectors()101 static bool TestRFC6070Vectors() {
102   const uint8_t kKey1[] = {0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e,
103                            0x71, 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60,
104                            0x12, 0x06, 0x2f, 0xe0, 0x37, 0xa6};
105   const uint8_t kKey2[] = {0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f,
106                            0x8c, 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d,
107                            0x41, 0xf0, 0xd8, 0xde, 0x89, 0x57};
108   const uint8_t kKey3[] = {0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
109                            0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3};
110 
111   if (!TestPBKDF2("password", 8, "salt", 4, 1, EVP_sha1(), sizeof(kKey1),
112                   kKey1) ||
113       !TestPBKDF2("password", 8, "salt", 4, 2, EVP_sha1(), sizeof(kKey2),
114                   kKey2) ||
115       !TestPBKDF2("pass\0word", 9, "sa\0lt", 5, 4096, EVP_sha1(),
116                   sizeof(kKey3), kKey3)) {
117     return false;
118   }
119 
120   return true;
121 }
122 
123 // Tests key derivation using SHA-2 digests.
TestSHA2()124 static bool TestSHA2() {
125   // This test was taken from:
126   // http://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors.
127   const uint8_t kKey1[] = {0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3,
128                            0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0, 0x6d, 0xd0,
129                            0x2a, 0x30, 0x3f, 0x8e, 0xf3, 0xc2, 0x51, 0xdf,
130                            0xd6, 0xe2, 0xd8, 0x5a, 0x95, 0x47, 0x4c, 0x43};
131 
132   // This test was taken from:
133   // http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors.
134   const uint8_t kKey2[] = {
135       0x8c, 0x05, 0x11, 0xf4, 0xc6, 0xe5, 0x97, 0xc6, 0xac, 0x63, 0x15,
136       0xd8, 0xf0, 0x36, 0x2e, 0x22, 0x5f, 0x3c, 0x50, 0x14, 0x95, 0xba,
137       0x23, 0xb8, 0x68, 0xc0, 0x05, 0x17, 0x4d, 0xc4, 0xee, 0x71, 0x11,
138       0x5b, 0x59, 0xf9, 0xe6, 0x0c, 0xd9, 0x53, 0x2f, 0xa3, 0x3e, 0x0f,
139       0x75, 0xae, 0xfe, 0x30, 0x22, 0x5c, 0x58, 0x3a, 0x18, 0x6c, 0xd8,
140       0x2b, 0xd4, 0xda, 0xea, 0x97, 0x24, 0xa3, 0xd3, 0xb8};
141 
142   if (!TestPBKDF2("password", 8, "salt", 4, 2, EVP_sha256(), sizeof(kKey1),
143                   kKey1) ||
144       !TestPBKDF2("passwordPASSWORDpassword", 24,
145                   "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, 4096,
146                   EVP_sha512(), sizeof(kKey2), kKey2)) {
147     return false;
148   }
149 
150   return true;
151 }
152 
153 // Tests key derivation using iterations=0.
154 //
155 // RFC 2898 defines the iteration count (c) as a "positive integer". So doing a
156 // key derivation with iterations=0 is ill-defined and should result in a
157 // failure.
TestZeroIterations()158 static bool TestZeroIterations() {
159   static const char kPassword[] = "password";
160   const size_t password_len = strlen(kPassword);
161   static const uint8_t kSalt[] = {1, 2, 3, 4};
162   const size_t salt_len = sizeof(kSalt);
163   const EVP_MD *digest = EVP_sha1();
164 
165   uint8_t key[10] = {0};
166   const size_t key_len = sizeof(key);
167 
168   // Verify that calling with iterations=1 works.
169   if (!PKCS5_PBKDF2_HMAC(kPassword, password_len, kSalt, salt_len,
170                          1 /* iterations */, digest, key_len, key)) {
171     fprintf(stderr, "PBKDF2 failed with iterations=1\n");
172     return false;
173   }
174 
175   // Flip the first key byte (so can later test if it got set).
176   const uint8_t expected_first_byte = key[0];
177   key[0] = ~key[0];
178 
179   // However calling it with iterations=0 fails.
180   if (PKCS5_PBKDF2_HMAC(kPassword, password_len, kSalt, salt_len,
181                         0 /* iterations */, digest, key_len, key)) {
182     fprintf(stderr, "PBKDF2 returned zero with iterations=0\n");
183     return false;
184   }
185 
186   // For backwards compatibility, the iterations == 0 case still fills in
187   // the out key.
188   return key[0] == expected_first_byte;
189 }
190 
main(void)191 int main(void) {
192   CRYPTO_library_init();
193 
194   if (!TestEmptyPassword()) {
195     fprintf(stderr, "TestEmptyPassword failed\n");
196     return 1;
197   }
198 
199   if (!TestEmptySalt()) {
200     fprintf(stderr, "TestEmptySalt failed\n");
201     return 1;
202   }
203 
204   if (!TestRFC6070Vectors()) {
205     fprintf(stderr, "TestRFC6070Vectors failed\n");
206     return 1;
207   }
208 
209   if (!TestSHA2()) {
210     fprintf(stderr, "TestSHA2 failed\n");
211     return 1;
212   }
213 
214   if (!TestZeroIterations()) {
215     fprintf(stderr, "TestZeroIterations failed\n");
216     return 1;
217   }
218 
219   printf("PASS\n");
220   ERR_free_strings();
221   return 0;
222 }
223