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
main(void)152 int main(void) {
153 CRYPTO_library_init();
154 ERR_load_crypto_strings();
155
156 if (!TestEmptyPassword()) {
157 fprintf(stderr, "TestEmptyPassword failed\n");
158 return 1;
159 }
160
161 if (!TestEmptySalt()) {
162 fprintf(stderr, "TestEmptySalt failed\n");
163 return 1;
164 }
165
166 if (!TestRFC6070Vectors()) {
167 fprintf(stderr, "TestRFC6070Vectors failed\n");
168 return 1;
169 }
170
171 if (!TestSHA2()) {
172 fprintf(stderr, "TestSHA2 failed\n");
173 return 1;
174 }
175
176 printf("PASS\n");
177 ERR_free_strings();
178 return 0;
179 }
180