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

randombit / botan / 5230455705

10 Jun 2023 02:30PM UTC coverage: 91.715% (-0.03%) from 91.746%
5230455705

push

github

randombit
Merge GH #3584 Change clang-format AllowShortFunctionsOnASingleLine config from All to Inline

77182 of 84154 relevant lines covered (91.72%)

11975295.43 hits per line

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

80.39
/src/lib/misc/fpe_fe1/fpe_fe1.cpp
1
/*
2
* Format Preserving Encryption (FE1 scheme)
3
* (C) 2009,2018 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/fpe_fe1.h>
9

10
#include <botan/mac.h>
11
#include <botan/numthry.h>
12
#include <botan/reducer.h>
13
#include <botan/internal/divide.h>
14
#include <botan/internal/fmt.h>
15
#include <botan/internal/loadstor.h>
16

17
namespace Botan {
18

19
namespace {
20

21
// Normally FPE is for SSNs, CC#s, etc, nothing too big
22
const size_t MAX_N_BYTES = 128 / 8;
23

24
/*
25
* Factor n into a and b which are as close together as possible.
26
* Assumes n is composed mostly of small factors which is the case for
27
* typical uses of FPE (typically, n is a power of 10)
28
*/
29
void factor(BigInt n, BigInt& a, BigInt& b) {
15✔
30
   a = BigInt::one();
15✔
31
   b = BigInt::one();
15✔
32

33
   size_t n_low_zero = low_zero_bits(n);
15✔
34

35
   a <<= (n_low_zero / 2);
15✔
36
   b <<= n_low_zero - (n_low_zero / 2);
15✔
37
   n >>= n_low_zero;
15✔
38

39
   for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i) {
98,130✔
40
      while(n % PRIMES[i] == 0) {
98,256✔
41
         a *= PRIMES[i];
141✔
42
         if(a > b) {
141✔
43
            std::swap(a, b);
141✔
44
         }
45
         n /= BigInt::from_word(PRIMES[i]);
282✔
46
      }
47
   }
48

49
   if(a > b) {
15✔
50
      std::swap(a, b);
×
51
   }
52
   a *= n;
15✔
53

54
   if(a <= 1 || b <= 1) {
30✔
55
      throw Internal_Error("Could not factor n for use in FPE");
×
56
   }
57
}
15✔
58

59
}  // namespace
60

61
FPE_FE1::FPE_FE1(const BigInt& n, size_t rounds, bool compat_mode, std::string_view mac_algo) : m_rounds(rounds) {
15✔
62
   if(m_rounds < 3) {
15✔
63
      throw Invalid_Argument("FPE_FE1 rounds too small");
×
64
   }
65

66
   m_mac = MessageAuthenticationCode::create_or_throw(mac_algo);
15✔
67

68
   m_n_bytes = BigInt::encode(n);
15✔
69

70
   if(m_n_bytes.size() > MAX_N_BYTES) {
15✔
71
      throw Invalid_Argument("N is too large for FPE encryption");
×
72
   }
73

74
   factor(n, m_a, m_b);
15✔
75

76
   if(compat_mode) {
15✔
77
      if(m_a < m_b) {
12✔
78
         std::swap(m_a, m_b);
12✔
79
      }
80
   } else {
81
      if(m_a > m_b) {
3✔
82
         std::swap(m_a, m_b);
×
83
      }
84
   }
85

86
   mod_a = std::make_unique<Modular_Reducer>(m_a);
15✔
87
}
15✔
88

89
FPE_FE1::~FPE_FE1() = default;
62✔
90

91
void FPE_FE1::clear() {
×
92
   m_mac->clear();
×
93
}
×
94

95
std::string FPE_FE1::name() const {
×
96
   return fmt("FPE_FE1({},{})", m_mac->name(), m_rounds);
×
97
}
98

99
Key_Length_Specification FPE_FE1::key_spec() const {
15✔
100
   return m_mac->key_spec();
15✔
101
}
102

103
bool FPE_FE1::has_keying_material() const {
×
104
   return m_mac->has_keying_material();
×
105
}
106

107
void FPE_FE1::key_schedule(const uint8_t key[], size_t length) {
15✔
108
   m_mac->set_key(key, length);
15✔
109
}
15✔
110

111
BigInt FPE_FE1::F(const BigInt& R,
86✔
112
                  size_t round,
113
                  const secure_vector<uint8_t>& tweak_mac,
114
                  secure_vector<uint8_t>& tmp) const {
115
   tmp = BigInt::encode_locked(R);
86✔
116

117
   m_mac->update(tweak_mac);
86✔
118
   m_mac->update_be(static_cast<uint32_t>(round));
86✔
119

120
   m_mac->update_be(static_cast<uint32_t>(tmp.size()));
86✔
121
   m_mac->update(tmp.data(), tmp.size());
86✔
122

123
   tmp = m_mac->final();
86✔
124
   return BigInt(tmp.data(), tmp.size());
86✔
125
}
126

127
secure_vector<uint8_t> FPE_FE1::compute_tweak_mac(const uint8_t tweak[], size_t tweak_len) const {
22✔
128
   m_mac->update_be(static_cast<uint32_t>(m_n_bytes.size()));
22✔
129
   m_mac->update(m_n_bytes.data(), m_n_bytes.size());
22✔
130

131
   m_mac->update_be(static_cast<uint32_t>(tweak_len));
22✔
132
   if(tweak_len > 0) {
22✔
133
      m_mac->update(tweak, tweak_len);
16✔
134
   }
135

136
   return m_mac->final();
22✔
137
}
138

139
BigInt FPE_FE1::encrypt(const BigInt& input, const uint8_t tweak[], size_t tweak_len) const {
11✔
140
   const secure_vector<uint8_t> tweak_mac = compute_tweak_mac(tweak, tweak_len);
11✔
141

142
   BigInt X = input;
11✔
143

144
   secure_vector<uint8_t> tmp;
11✔
145

146
   BigInt L, R, Fi;
11✔
147
   for(size_t i = 0; i != m_rounds; ++i) {
54✔
148
      ct_divide(X, m_b, L, R);
43✔
149
      Fi = F(R, i, tweak_mac, tmp);
43✔
150
      X = m_a * R + mod_a->reduce(L + Fi);
215✔
151
   }
152

153
   return X;
11✔
154
}
55✔
155

156
BigInt FPE_FE1::decrypt(const BigInt& input, const uint8_t tweak[], size_t tweak_len) const {
11✔
157
   const secure_vector<uint8_t> tweak_mac = compute_tweak_mac(tweak, tweak_len);
11✔
158

159
   BigInt X = input;
11✔
160
   secure_vector<uint8_t> tmp;
11✔
161

162
   BigInt W, R, Fi;
11✔
163
   for(size_t i = 0; i != m_rounds; ++i) {
54✔
164
      ct_divide(X, m_a, R, W);
43✔
165

166
      Fi = F(R, m_rounds - i - 1, tweak_mac, tmp);
43✔
167
      X = m_b * mod_a->reduce(W - Fi) + R;
215✔
168
   }
169

170
   return X;
11✔
171
}
55✔
172

173
BigInt FPE_FE1::encrypt(const BigInt& x, uint64_t tweak) const {
×
174
   uint8_t tweak8[8];
×
175
   store_be(tweak, tweak8);
×
176
   return encrypt(x, tweak8, sizeof(tweak8));
×
177
}
178

179
BigInt FPE_FE1::decrypt(const BigInt& x, uint64_t tweak) const {
×
180
   uint8_t tweak8[8];
×
181
   store_be(tweak, tweak8);
×
182
   return decrypt(x, tweak8, sizeof(tweak8));
×
183
}
184

185
namespace FPE {
186

187
BigInt fe1_encrypt(const BigInt& n, const BigInt& X, const SymmetricKey& key, const std::vector<uint8_t>& tweak) {
6✔
188
   FPE_FE1 fpe(n, 3, true, "HMAC(SHA-256)");
6✔
189
   fpe.set_key(key);
6✔
190
   return fpe.encrypt(X, tweak.data(), tweak.size());
12✔
191
}
6✔
192

193
BigInt fe1_decrypt(const BigInt& n, const BigInt& X, const SymmetricKey& key, const std::vector<uint8_t>& tweak) {
6✔
194
   FPE_FE1 fpe(n, 3, true, "HMAC(SHA-256)");
6✔
195
   fpe.set_key(key);
6✔
196
   return fpe.decrypt(X, tweak.data(), tweak.size());
12✔
197
}
6✔
198

199
}  // namespace FPE
200

201
}  // 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

© 2026 Coveralls, Inc