pk11_pbkdf2_unittest.cc (7470B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <memory> 8 #include "nss.h" 9 #include "pk11pub.h" 10 11 #include "gtest/gtest.h" 12 #include "nss_scoped_ptrs.h" 13 14 namespace nss_test { 15 16 static unsigned char* ToUcharPtr(std::string& str) { 17 return const_cast<unsigned char*>( 18 reinterpret_cast<const unsigned char*>(str.c_str())); 19 } 20 21 class Pkcs11Pbkdf2Test : public ::testing::Test { 22 public: 23 void Derive(std::vector<uint8_t>& derived, SECOidTag hash_alg) { 24 // Shared between test vectors. 25 const unsigned int kIterations = 4096; 26 std::string pass("passwordPASSWORDpassword"); 27 std::string salt("saltSALTsaltSALTsaltSALTsaltSALTsalt"); 28 29 // Derivation must succeed with the right values. 30 EXPECT_TRUE(DeriveBytes(pass, salt, derived, hash_alg, kIterations)); 31 32 // Derivation must fail when the password is bogus. 33 std::string bogus_pass("PasswordPASSWORDpassword"); 34 EXPECT_FALSE(DeriveBytes(bogus_pass, salt, derived, hash_alg, kIterations)); 35 36 // Derivation must fail when the salt is bogus. 37 std::string bogus_salt("SaltSALTsaltSALTsaltSALTsaltSALTsalt"); 38 EXPECT_FALSE(DeriveBytes(pass, bogus_salt, derived, hash_alg, kIterations)); 39 40 // Derivation must fail when using the wrong hash function. 41 SECOidTag next_hash_alg = static_cast<SECOidTag>(hash_alg + 1); 42 EXPECT_FALSE(DeriveBytes(pass, salt, derived, next_hash_alg, kIterations)); 43 44 // Derivation must fail when using the wrong number of kIterations. 45 EXPECT_FALSE(DeriveBytes(pass, salt, derived, hash_alg, kIterations + 1)); 46 } 47 48 void KeySizes(SECOidTag hash_alg) { 49 // These tests will only validate the controls around the key sizes. 50 // The resulting key is tested above, with valid key sizes. 51 const unsigned int kIterations = 10; 52 std::string pass("passwordPASSWORDpassword"); 53 std::string salt("saltSALTsaltSALTsaltSALTsaltSALTsalt"); 54 std::string salt_empty(""); 55 56 // Derivation must fail when using key sizes bigger than MAX_KEY_LEN. 57 const int big_key_size = 768; 58 EXPECT_FALSE(KeySizeParam(pass, salt, big_key_size, hash_alg, kIterations)); 59 60 // Zero is acceptable as key size and will be managed internally. 61 const int zero_key_size = 0; 62 EXPECT_TRUE(KeySizeParam(pass, salt, zero_key_size, hash_alg, kIterations)); 63 64 // Zero is acceptable as salt size and will be managed internally. 65 EXPECT_TRUE( 66 KeySizeParam(pass, salt_empty, zero_key_size, hash_alg, kIterations)); 67 68 // -1 will be set to 0 internally and this means that the key size will be 69 // obtained from the template. If the template doesn't have this defined, 70 // it must fail. 71 const int minus_key_size = -1; 72 EXPECT_FALSE( 73 KeySizeParam(pass, salt, minus_key_size, hash_alg, kIterations)); 74 75 // Lower than -1 is not allowed, as -1 means no keyLen defined. 76 const int negative_key_size = -10; 77 EXPECT_FALSE( 78 KeySizeParam(pass, salt, negative_key_size, hash_alg, kIterations)); 79 80 // Malformed inputs are handled without crashing 81 EXPECT_FALSE( 82 MalformedPass(pass, salt, big_key_size, hash_alg, kIterations)); 83 EXPECT_FALSE( 84 MalformedSalt(pass, salt, big_key_size, hash_alg, kIterations)); 85 } 86 87 private: 88 bool DeriveBytes(std::string& pass, std::string& salt, 89 std::vector<uint8_t>& derived, SECOidTag hash_alg, 90 unsigned int kIterations) { 91 SECItem pass_item = {siBuffer, ToUcharPtr(pass), 92 static_cast<unsigned int>(pass.length())}; 93 SECItem salt_item = {siBuffer, ToUcharPtr(salt), 94 static_cast<unsigned int>(salt.length())}; 95 96 // Set up PBKDF2 params. 97 ScopedSECAlgorithmID alg_id( 98 PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, hash_alg, hash_alg, 99 derived.size(), kIterations, &salt_item)); 100 101 // Derive. 102 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 103 ScopedPK11SymKey sym_key( 104 PK11_PBEKeyGen(slot.get(), alg_id.get(), &pass_item, false, nullptr)); 105 106 SECStatus rv = PK11_ExtractKeyValue(sym_key.get()); 107 EXPECT_EQ(rv, SECSuccess); 108 109 SECItem* key_data = PK11_GetKeyData(sym_key.get()); 110 return !memcmp(&derived[0], key_data->data, key_data->len); 111 } 112 113 bool GenerateKey(SECItem pass_item, SECItem salt_item, const int key_size, 114 SECOidTag hash_alg, unsigned int kIterations) { 115 // Set up PBKDF2 params. 116 ScopedSECAlgorithmID alg_id( 117 PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, hash_alg, hash_alg, 118 key_size, kIterations, &salt_item)); 119 120 // Try to generate a key with the defined params. 121 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 122 ScopedPK11SymKey sym_key( 123 PK11_PBEKeyGen(slot.get(), alg_id.get(), &pass_item, false, nullptr)); 124 125 // Should be nullptr if fail. 126 return sym_key.get(); 127 } 128 129 bool KeySizeParam(std::string& pass, std::string& salt, const int key_size, 130 SECOidTag hash_alg, unsigned int kIterations) { 131 SECItem pass_item = {siBuffer, ToUcharPtr(pass), 132 static_cast<unsigned int>(pass.length())}; 133 SECItem salt_item = {siBuffer, ToUcharPtr(salt), 134 static_cast<unsigned int>(salt.length())}; 135 136 return GenerateKey(pass_item, salt_item, key_size, hash_alg, kIterations); 137 } 138 139 bool MalformedSalt(std::string& pass, std::string& salt, const int key_size, 140 SECOidTag hash_alg, unsigned int kIterations) { 141 SECItem pass_item = {siBuffer, ToUcharPtr(pass), 142 static_cast<unsigned int>(pass.length())}; 143 SECItem salt_item = {siBuffer, nullptr, 0}; 144 145 return GenerateKey(pass_item, salt_item, key_size, hash_alg, kIterations); 146 } 147 148 bool MalformedPass(std::string& pass, std::string& salt, const int key_size, 149 SECOidTag hash_alg, unsigned int kIterations) { 150 SECItem pass_item = {siBuffer, nullptr, 0}; 151 SECItem salt_item = {siBuffer, ToUcharPtr(salt), 152 static_cast<unsigned int>(salt.length())}; 153 154 return GenerateKey(pass_item, salt_item, key_size, hash_alg, kIterations); 155 } 156 }; 157 158 // RFC 6070 <http://tools.ietf.org/html/rfc6070> 159 TEST_F(Pkcs11Pbkdf2Test, DeriveKnown1) { 160 std::vector<uint8_t> derived = {0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 161 0x9b, 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 162 0xe4, 0x4a, 0x8b, 0x29, 0x1a, 0x96, 0x4c, 163 0xf2, 0xf0, 0x70, 0x38}; 164 165 Derive(derived, SEC_OID_HMAC_SHA1); 166 } 167 168 // https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors 169 TEST_F(Pkcs11Pbkdf2Test, DeriveKnown2) { 170 std::vector<uint8_t> derived = { 171 0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f, 0x32, 0xd8, 172 0x14, 0xb8, 0x11, 0x6e, 0x84, 0xcf, 0x2b, 0x17, 0x34, 0x7e, 173 0xbc, 0x18, 0x00, 0x18, 0x1c, 0x4e, 0x2a, 0x1f, 0xb8, 0xdd, 174 0x53, 0xe1, 0xc6, 0x35, 0x51, 0x8c, 0x7d, 0xac, 0x47, 0xe9}; 175 176 Derive(derived, SEC_OID_HMAC_SHA256); 177 } 178 179 TEST_F(Pkcs11Pbkdf2Test, KeyLenSizes) { 180 // The size controls are regardless of the algorithms. 181 KeySizes(SEC_OID_HMAC_SHA256); 182 } 183 184 } // namespace nss_test