• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5123321399

30 May 2023 04:06PM UTC coverage: 92.213% (+0.004%) from 92.209%
5123321399

Pull #3558

github

web-flow
Merge dd72f7389 into 057bcbc35
Pull Request #3558: Add braces around all if/else statements

75602 of 81986 relevant lines covered (92.21%)

11859779.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.71
/src/lib/pbkdf/pgp_s2k/pgp_s2k.cpp
1
/*
2
* OpenPGP S2K
3
* (C) 1999-2007,2017 Jack Lloyd
4
* (C) 2018 Ribose Inc
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include <botan/pgp_s2k.h>
10

11
#include <botan/exceptn.h>
12
#include <botan/internal/fmt.h>
13
#include <botan/internal/timer.h>
14
#include <algorithm>
15

16
namespace Botan {
17

18
namespace {
19

20
void pgp_s2k(HashFunction& hash,
29✔
21
             uint8_t output_buf[],
22
             size_t output_len,
23
             const char* password,
24
             const size_t password_size,
25
             const uint8_t salt[],
26
             size_t salt_len,
27
             size_t iterations) {
28
   if(iterations > 1 && salt_len == 0) {
29✔
29
      throw Invalid_Argument("OpenPGP S2K requires a salt in iterated mode");
×
30
   }
31

32
   secure_vector<uint8_t> input_buf(salt_len + password_size);
29✔
33
   if(salt_len > 0) {
29✔
34
      copy_mem(&input_buf[0], salt, salt_len);
25✔
35
   }
36
   if(password_size > 0) {
29✔
37
      copy_mem(&input_buf[salt_len], cast_char_ptr_to_uint8(password), password_size);
27✔
38
   }
39

40
   secure_vector<uint8_t> hash_buf(hash.output_length());
29✔
41

42
   size_t pass = 0;
29✔
43
   size_t generated = 0;
29✔
44

45
   while(generated != output_len) {
88✔
46
      const size_t output_this_pass = std::min(hash_buf.size(), output_len - generated);
59✔
47

48
      // Preload some number of zero bytes (empty first iteration)
49
      std::vector<uint8_t> zero_padding(pass);
59✔
50
      hash.update(zero_padding);
59✔
51

52
      // The input is always fully processed even if iterations is very small
53
      if(input_buf.empty() == false) {
59✔
54
         size_t left = std::max(iterations, input_buf.size());
57✔
55
         while(left > 0) {
8,958,481✔
56
            const size_t input_to_take = std::min(left, input_buf.size());
8,958,424✔
57
            hash.update(input_buf.data(), input_to_take);
8,958,424✔
58
            left -= input_to_take;
8,958,424✔
59
         }
60
      }
61

62
      hash.final(hash_buf.data());
59✔
63
      copy_mem(output_buf + generated, hash_buf.data(), output_this_pass);
59✔
64
      generated += output_this_pass;
59✔
65
      ++pass;
59✔
66
   }
59✔
67
}
56✔
68

69
}  // namespace
70

71
size_t OpenPGP_S2K::pbkdf(uint8_t output_buf[],
13✔
72
                          size_t output_len,
73
                          std::string_view password,
74
                          const uint8_t salt[],
75
                          size_t salt_len,
76
                          size_t iterations,
77
                          std::chrono::milliseconds msec) const {
78
   std::unique_ptr<PasswordHash> pwdhash;
13✔
79

80
   if(iterations == 0) {
13✔
81
      RFC4880_S2K_Family s2k_params(m_hash->new_object());
×
82
      iterations = s2k_params.tune(output_len, msec, 0, std::chrono::milliseconds(10))->iterations();
×
83
   }
×
84

85
   pgp_s2k(*m_hash, output_buf, output_len, password.data(), password.size(), salt, salt_len, iterations);
13✔
86

87
   return iterations;
13✔
88
}
13✔
89

90
std::string RFC4880_S2K_Family::name() const { return fmt("OpenPGP-S2K({})", m_hash->name()); }
2✔
91

92
std::unique_ptr<PasswordHash> RFC4880_S2K_Family::tune(size_t output_len,
1✔
93
                                                       std::chrono::milliseconds msec,
94
                                                       size_t /*max_memory_usage_mb*/,
95
                                                       std::chrono::milliseconds tune_time) const {
96
   const size_t buf_size = 1024;
1✔
97
   std::vector<uint8_t> buffer(buf_size);
1✔
98

99
   Timer timer("RFC4880_S2K", buf_size);
1✔
100
   timer.run_until_elapsed(tune_time, [&]() { m_hash->update(buffer); });
119✔
101

102
   const double hash_bytes_per_second = timer.bytes_per_second();
1✔
103
   const uint64_t desired_nsec = msec.count() * 1000000;
1✔
104

105
   const size_t hash_size = m_hash->output_length();
1✔
106
   const size_t blocks_required = (output_len <= hash_size ? 1 : (output_len + hash_size - 1) / hash_size);
1✔
107

108
   const double bytes_to_be_hashed = (hash_bytes_per_second * (desired_nsec / 1000000000.0)) / blocks_required;
1✔
109
   const size_t iterations = RFC4880_round_iterations(static_cast<size_t>(bytes_to_be_hashed));
1✔
110

111
   return std::make_unique<RFC4880_S2K>(m_hash->new_object(), iterations);
1✔
112
}
2✔
113

114
std::unique_ptr<PasswordHash> RFC4880_S2K_Family::from_params(size_t iter, size_t /*i2*/, size_t /*i3*/) const {
14✔
115
   return std::make_unique<RFC4880_S2K>(m_hash->new_object(), iter);
14✔
116
}
117

118
std::unique_ptr<PasswordHash> RFC4880_S2K_Family::default_params() const {
1✔
119
   return std::make_unique<RFC4880_S2K>(m_hash->new_object(), 50331648);
1✔
120
}
121

122
std::unique_ptr<PasswordHash> RFC4880_S2K_Family::from_iterations(size_t iter) const {
×
123
   return std::make_unique<RFC4880_S2K>(m_hash->new_object(), iter);
×
124
}
125

126
RFC4880_S2K::RFC4880_S2K(std::unique_ptr<HashFunction> hash, size_t iterations) :
16✔
127
      m_hash(std::move(hash)), m_iterations(iterations) {}
16✔
128

129
std::string RFC4880_S2K::to_string() const { return fmt("OpenPGP-S2K({},{})", m_hash->name(), m_iterations); }
×
130

131
void RFC4880_S2K::derive_key(uint8_t out[],
16✔
132
                             size_t out_len,
133
                             const char* password,
134
                             const size_t password_len,
135
                             const uint8_t salt[],
136
                             size_t salt_len) const {
137
   pgp_s2k(*m_hash, out, out_len, password, password_len, salt, salt_len, m_iterations);
16✔
138
}
16✔
139

140
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc