tor-browser

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

prng_kat_unittest.cc (5061B)


      1 // This Source Code Form is subject to the terms of the Mozilla Public
      2 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 // You can obtain one at http://mozilla.org/MPL/2.0/.
      4 
      5 #include "nspr.h"
      6 #include "nss.h"
      7 #include "ssl.h"
      8 
      9 #include <cstdlib>
     10 #include <fstream>
     11 
     12 #define GTEST_HAS_RTTI 0
     13 #include "gtest/gtest.h"
     14 #include "util.h"
     15 
     16 #include "blapi.h"
     17 
     18 extern std::string g_source_dir;
     19 
     20 namespace nss_test {
     21 
     22 struct PRNGTestValues {
     23  std::vector<uint8_t> entropy;
     24  std::vector<uint8_t> nonce;
     25  std::vector<uint8_t> personal;
     26  std::vector<uint8_t> expected_result;
     27  std::vector<uint8_t> additional_entropy;
     28  std::vector<uint8_t> additional_input_reseed;
     29  std::vector<std::vector<uint8_t>> additional_input;
     30 };
     31 
     32 bool contains(std::string& s, const char* to_find) {
     33  return s.find(to_find) != std::string::npos;
     34 }
     35 
     36 std::string trim(std::string str) {
     37  std::string whitespace = " \t\r\n";
     38  const auto strBegin = str.find_first_not_of(whitespace);
     39  if (strBegin == std::string::npos) {
     40    return "";
     41  }
     42  const auto strEnd = str.find_last_not_of(whitespace);
     43  const auto strRange = strEnd - strBegin + 1;
     44  return str.substr(strBegin, strRange);
     45 }
     46 
     47 std::vector<uint8_t> read_option_s(std::string& s) {
     48  size_t start = s.find("=") + 1;
     49  assert(start > 0);
     50  return hex_string_to_bytes(trim(s.substr(start, s.find("]", start))));
     51 }
     52 
     53 void print_bytes(std::vector<uint8_t> bytes, std::string name) {
     54  std::cout << name << ": ";
     55  for (auto b : bytes) {
     56    std::cout << std::setfill('0') << std::setw(2) << std::hex
     57              << static_cast<int>(b);
     58  }
     59  std::cout << std::endl;
     60 }
     61 
     62 static std::vector<PRNGTestValues> ReadFile(const std::string file_name) {
     63  std::vector<PRNGTestValues> test_vector;
     64  std::ifstream infile(file_name);
     65  EXPECT_FALSE(infile.fail()) << "kat file: " << file_name;
     66  std::string line;
     67 
     68  // Variables holding the input for each test.
     69  bool valid_option = false;
     70 
     71  // Read the file.
     72  std::streampos pos;
     73  while (std::getline(infile, line)) {
     74    // We only implement SHA256. Skip all other tests.
     75    if (contains(line, "[SHA-")) {
     76      valid_option = contains(line, "[SHA-256]");
     77    }
     78    if (!valid_option) {
     79      continue;
     80    }
     81 
     82    // We ignore the options and infer them from the test case.
     83 
     84    PRNGTestValues test;
     85    if (line.find("COUNT =")) {
     86      continue;
     87    }
     88 
     89    // Read test input.
     90    do {
     91      pos = infile.tellg();
     92      std::getline(infile, line);
     93      if (contains(line, "EntropyInput ")) {
     94        test.entropy = read_option_s(line);
     95        continue;
     96      }
     97      if (contains(line, "Nonce")) {
     98        test.nonce = read_option_s(line);
     99        continue;
    100      }
    101      if (contains(line, "PersonalizationString")) {
    102        test.personal = read_option_s(line);
    103        continue;
    104      }
    105      if (contains(line, "AdditionalInput ")) {
    106        test.additional_input.push_back(read_option_s(line));
    107        continue;
    108      }
    109      if (contains(line, "EntropyInputReseed")) {
    110        test.additional_entropy = read_option_s(line);
    111        continue;
    112      }
    113      if (contains(line, "AdditionalInputReseed")) {
    114        test.additional_input_reseed = read_option_s(line);
    115        continue;
    116      }
    117      if (contains(line, "ReturnedBits")) {
    118        test.expected_result = read_option_s(line);
    119        continue;
    120      }
    121    } while (!infile.eof() && line.find("COUNT =") && line.find("["));
    122 
    123    // Save test case.
    124    test_vector.push_back(test);
    125    test = {};
    126    infile.seekg(pos);
    127  }
    128  return test_vector;
    129 }
    130 
    131 class PRNGTest : public ::testing::Test {
    132 protected:
    133  void SetUp() override {
    134    test_vector_ = ReadFile(::g_source_dir + "/kat/Hash_DRBG.rsp");
    135    ASSERT_FALSE(test_vector_.empty());
    136  }
    137 
    138  void RunTest(PRNGTestValues& test) {
    139    ASSERT_EQ(2U, test.additional_input.size());
    140    SECStatus rv = PRNGTEST_Instantiate_Kat(
    141        test.entropy.data(), test.entropy.size(), test.nonce.data(),
    142        test.nonce.size(), test.personal.data(), test.personal.size());
    143    ASSERT_EQ(SECSuccess, rv);
    144    rv = PRNGTEST_Reseed(test.additional_entropy.data(),
    145                         test.additional_entropy.size(),
    146                         test.additional_input_reseed.data(),
    147                         test.additional_input_reseed.size());
    148    ASSERT_EQ(SECSuccess, rv);
    149 
    150    // Generate bytes.
    151    uint8_t bytes[128];
    152    PRNGTEST_Generate(bytes, 128, test.additional_input[0].data(),
    153                      test.additional_input[0].size());
    154    PRNGTEST_Generate(bytes, 128, test.additional_input[1].data(),
    155                      test.additional_input[1].size());
    156    std::vector<uint8_t> result(bytes, bytes + 128);
    157    if (result != test.expected_result) {
    158      print_bytes(result, "result  ");
    159      print_bytes(test.expected_result, "expected");
    160    }
    161    ASSERT_EQ(test.expected_result, result);
    162    rv = PRNGTEST_Uninstantiate();
    163    ASSERT_EQ(SECSuccess, rv);
    164  }
    165 
    166 protected:
    167  std::vector<PRNGTestValues> test_vector_;
    168 };
    169 
    170 TEST_F(PRNGTest, HashDRBG) {
    171  for (auto& v : test_vector_) {
    172    RunTest(v);
    173  }
    174 }
    175 
    176 }  // namespace nss_test