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/bio.h>
19 #include <openssl/crypto.h>
20 #include <openssl/digest.h>
21 #include <openssl/err.h>
22 #include <openssl/evp.h>
23 
24 
25 // Prints out the data buffer as a sequence of hex bytes.
PrintDataHex(const void * data,size_t len)26 static void PrintDataHex(const void *data, size_t len) {
27   for (size_t i = 0; i < len; ++i) {
28     fprintf(stderr, "%02x", (int)((const uint8_t *)data)[i]);
29   }
30 }
31 
32 // Helper for testing that PBKDF2 derives the expected key from the given
33 // 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)34 static bool TestPBKDF2(const void *password, size_t password_len,
35                        const void *salt, size_t salt_len, unsigned iterations,
36                        const EVP_MD *digest, size_t key_len,
37                        const uint8_t *expected_key) {
38   uint8_t key[64];
39 
40   if (key_len > sizeof(key)) {
41     fprintf(stderr, "Output buffer is not large enough.\n");
42     return false;
43   }
44 
45   if (!PKCS5_PBKDF2_HMAC((const char *)password, password_len,
46                          (const uint8_t *)salt, salt_len, iterations, digest,
47                          key_len, key)) {
48     fprintf(stderr, "Call to PKCS5_PBKDF2_HMAC failed\n");
49     ERR_print_errors_fp(stderr);
50     return false;
51   }
52 
53   if (memcmp(key, expected_key, key_len) != 0) {
54     fprintf(stderr, "Resulting key material does not match expectation\n");
55     fprintf(stderr, "Expected:\n    ");
56     PrintDataHex(expected_key, key_len);
57     fprintf(stderr, "\nActual:\n    ");
58     PrintDataHex(key, key_len);
59     fprintf(stderr, "\n");
60     return false;
61   }
62 
63   return true;
64 }
65 
66 // Tests deriving a key using an empty password (specified both as NULL and as
67 // non-NULL). Note that NULL has special meaning to HMAC initialization.
TestEmptyPassword()68 static bool TestEmptyPassword() {
69   const uint8_t kKey[] = {0xa3, 0x3d, 0xdd, 0xc3, 0x04, 0x78, 0x18,
70                           0x55, 0x15, 0x31, 0x1f, 0x87, 0x52, 0x89,
71                           0x5d, 0x36, 0xea, 0x43, 0x63, 0xa2};
72 
73   if (!TestPBKDF2(NULL, 0, "salt", 4, 1, EVP_sha1(), sizeof(kKey), kKey) ||
74       !TestPBKDF2("", 0, "salt", 4, 1, EVP_sha1(), sizeof(kKey), kKey)) {
75     return false;
76   }
77 
78   return true;
79 }
80 
81 // Tests deriving a key using an empty salt. Note that the expectation was
82 // generated using OpenSSL itself, and hence is not verified.
TestEmptySalt()83 static bool TestEmptySalt() {
84   const uint8_t kKey[] = {0x8b, 0xc2, 0xf9, 0x16, 0x7a, 0x81, 0xcd, 0xcf,
85                           0xad, 0x12, 0x35, 0xcd, 0x90, 0x47, 0xf1, 0x13,
86                           0x62, 0x71, 0xc1, 0xf9, 0x78, 0xfc, 0xfc, 0xb3,
87                           0x5e, 0x22, 0xdb, 0xea, 0xfa, 0x46, 0x34, 0xf6};
88 
89   if (!TestPBKDF2("password", 8, NULL, 0, 2, EVP_sha256(), sizeof(kKey),
90                   kKey) ||
91       !TestPBKDF2("password", 8, "", 0, 2, EVP_sha256(), sizeof(kKey), kKey)) {
92     return false;
93   }
94 
95   return true;
96 }
97 
98 // Exercises test vectors taken from https://tools.ietf.org/html/rfc6070.
99 // Note that each of these test vectors uses SHA-1 as the digest.
TestRFC6070Vectors()100 static bool TestRFC6070Vectors() {
101   const uint8_t kKey1[] = {0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e,
102                            0x71, 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60,
103                            0x12, 0x06, 0x2f, 0xe0, 0x37, 0xa6};
104   const uint8_t kKey2[] = {0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f,
105                            0x8c, 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d,
106                            0x41, 0xf0, 0xd8, 0xde, 0x89, 0x57};
107   const uint8_t kKey3[] = {0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
108                            0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3};
109 
110   if (!TestPBKDF2("password", 8, "salt", 4, 1, EVP_sha1(), sizeof(kKey1),
111                   kKey1) ||
112       !TestPBKDF2("password", 8, "salt", 4, 2, EVP_sha1(), sizeof(kKey2),
113                   kKey2) ||
114       !TestPBKDF2("pass\0word", 9, "sa\0lt", 5, 4096, EVP_sha1(),
115                   sizeof(kKey3), kKey3)) {
116     return false;
117   }
118 
119   return true;
120 }
121 
122 // Tests key derivation using SHA-2 digests.
TestSHA2()123 static bool TestSHA2() {
124   // This test was taken from:
125   // http://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors.
126   const uint8_t kKey1[] = {0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3,
127                            0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0, 0x6d, 0xd0,
128                            0x2a, 0x30, 0x3f, 0x8e, 0xf3, 0xc2, 0x51, 0xdf,
129                            0xd6, 0xe2, 0xd8, 0x5a, 0x95, 0x47, 0x4c, 0x43};
130 
131   // This test was taken from:
132   // http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors.
133   const uint8_t kKey2[] = {
134       0x8c, 0x05, 0x11, 0xf4, 0xc6, 0xe5, 0x97, 0xc6, 0xac, 0x63, 0x15,
135       0xd8, 0xf0, 0x36, 0x2e, 0x22, 0x5f, 0x3c, 0x50, 0x14, 0x95, 0xba,
136       0x23, 0xb8, 0x68, 0xc0, 0x05, 0x17, 0x4d, 0xc4, 0xee, 0x71, 0x11,
137       0x5b, 0x59, 0xf9, 0xe6, 0x0c, 0xd9, 0x53, 0x2f, 0xa3, 0x3e, 0x0f,
138       0x75, 0xae, 0xfe, 0x30, 0x22, 0x5c, 0x58, 0x3a, 0x18, 0x6c, 0xd8,
139       0x2b, 0xd4, 0xda, 0xea, 0x97, 0x24, 0xa3, 0xd3, 0xb8};
140 
141   if (!TestPBKDF2("password", 8, "salt", 4, 2, EVP_sha256(), sizeof(kKey1),
142                   kKey1) ||
143       !TestPBKDF2("passwordPASSWORDpassword", 24,
144                   "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, 4096,
145                   EVP_sha512(), sizeof(kKey2), kKey2)) {
146     return false;
147   }
148 
149   return true;
150 }
151 
152 // Tests key derivation using iterations=0.
153 //
154 // RFC 2898 defines the iteration count (c) as a "positive integer". So doing a
155 // key derivation with iterations=0 is ill-defined and should result in a
156 // failure.
TestZeroIterations()157 static bool TestZeroIterations() {
158   static const char kPassword[] = "password";
159   const size_t password_len = strlen(kPassword);
160   static const uint8_t kSalt[] = {1, 2, 3, 4};
161   const size_t salt_len = sizeof(kSalt);
162   const EVP_MD *digest = EVP_sha1();
163 
164   uint8_t key[10] = {0};
165   const size_t key_len = sizeof(key);
166 
167   // Verify that calling with iterations=1 works.
168   if (!PKCS5_PBKDF2_HMAC(kPassword, password_len, kSalt, salt_len,
169                          1 /* iterations */, digest, key_len, key)) {
170     fprintf(stderr, "PBKDF2 failed with iterations=1\n");
171     return false;
172   }
173 
174   // Flip the first key byte (so can later test if it got set).
175   const uint8_t expected_first_byte = key[0];
176   key[0] = ~key[0];
177 
178   // However calling it with iterations=0 fails.
179   if (PKCS5_PBKDF2_HMAC(kPassword, password_len, kSalt, salt_len,
180                         0 /* iterations */, digest, key_len, key)) {
181     fprintf(stderr, "PBKDF2 returned zero with iterations=0\n");
182     return false;
183   }
184 
185   // For backwards compatibility, the iterations == 0 case still fills in
186   // the out key.
187   return key[0] == expected_first_byte;
188 }
189 
main(void)190 int main(void) {
191   CRYPTO_library_init();
192   ERR_load_crypto_strings();
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