• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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