tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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