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