blob: 528470019c4ae3e4c2f9d4256e5661ffb6f87aa8 [file] [log] [blame]
Adam Langleye9ada862015-05-11 17:20:37 -07001/* 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
Adam Langleye9ada862015-05-11 17:20:37 -070018#include <openssl/crypto.h>
19#include <openssl/digest.h>
20#include <openssl/err.h>
21#include <openssl/evp.h>
22
Robert Sloan69939df2017-01-09 10:53:07 -080023#include "../internal.h"
24
Adam Langleye9ada862015-05-11 17:20:37 -070025
26// Prints out the data buffer as a sequence of hex bytes.
27static 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.
35static 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
Robert Sloan69939df2017-01-09 10:53:07 -080054 if (OPENSSL_memcmp(key, expected_key, key_len) != 0) {
Adam Langleye9ada862015-05-11 17:20:37 -070055 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.
69static 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.
84static 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.
101static 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.
124static 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
Kenny Roote99801b2015-11-06 15:31:15 -0800153// 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.
158static 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
Adam Langleye9ada862015-05-11 17:20:37 -0700191int main(void) {
192 CRYPTO_library_init();
Adam Langleye9ada862015-05-11 17:20:37 -0700193
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
Kenny Roote99801b2015-11-06 15:31:15 -0800214 if (!TestZeroIterations()) {
215 fprintf(stderr, "TestZeroIterations failed\n");
216 return 1;
217 }
218
Adam Langleye9ada862015-05-11 17:20:37 -0700219 printf("PASS\n");
220 ERR_free_strings();
221 return 0;
222}