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

randombit / botan / 26995937053

04 Jun 2026 09:38PM UTC coverage: 89.394% (-2.3%) from 91.672%
26995937053

push

github

web-flow
Merge pull request #5642 from randombit/jack/prefetch-in-ks

Improve prefetching for table based implementations

110588 of 123708 relevant lines covered (89.39%)

11056434.37 hits per line

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

94.12
/src/cli/cc_enc.cpp
1
/*
2
* (C) 2014,2015 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "cli.h"
8
#include <botan/hex.h>
9

10
#if defined(BOTAN_HAS_FPE_FE1) && defined(BOTAN_HAS_PBKDF)
11

12
   #include <botan/exceptn.h>
13
   #include <botan/fpe_fe1.h>
14
   #include <botan/pbkdf.h>
15
   #include <botan/symkey.h>
16
   #include <botan/internal/parsing.h>
17

18
namespace Botan_CLI {
19

20
namespace {
21

22
uint8_t luhn_checksum(uint64_t cc_number) {
52✔
23
   uint8_t sum = 0;
52✔
24

25
   bool alt = false;
52✔
26
   while(cc_number > 0) {
844✔
27
      uint8_t digit = cc_number % 10;
792✔
28
      if(alt) {
792✔
29
         digit *= 2;
383✔
30
         if(digit > 9) {
383✔
31
            digit -= 9;
130✔
32
         }
33
      }
34

35
      sum += digit;
792✔
36

37
      cc_number /= 10;
792✔
38
      alt = !alt;
792✔
39
   }
40

41
   return (sum % 10);
52✔
42
}
43

44
bool luhn_check(uint64_t cc_number) {
52✔
45
   return (luhn_checksum(cc_number) == 0);
52✔
46
}
47

48
uint64_t cc_rank(uint64_t cc_number) {
10✔
49
   // Remove Luhn checksum
50
   return cc_number / 10;
10✔
51
}
52

53
uint64_t cc_derank(uint64_t cc_number) {
10✔
54
   for(size_t i = 0; i != 10; ++i) {
52✔
55
      if(luhn_check(cc_number * 10 + i)) {
104✔
56
         return (cc_number * 10 + i);
10✔
57
      }
58
   }
59

60
   return 0;
61
}
62

63
uint64_t cc_modulus(size_t cc_digits) {
10✔
64
   uint64_t n = 1;
10✔
65
   for(size_t i = 1; i != cc_digits; ++i) {
154✔
66
      n *= 10;
144✔
67
   }
68
   return n;
10✔
69
}
70

71
uint64_t bigint_to_u64(const Botan::BigInt& n) {
10✔
72
   if(n.bits() > 64) {
10✔
73
      throw CLI_Error("FPE produced a number too large");
×
74
   }
75

76
   uint64_t result = 0;
77
   for(size_t i = 0; i != 8; ++i) {
90✔
78
      result = (result << 8) | n.byte_at(7 - i);
80✔
79
   }
80
   return result;
10✔
81
}
82

83
std::string format_cc_number(uint64_t cc_number, size_t cc_digits) {
10✔
84
   const std::string cc_str = std::to_string(cc_number);
10✔
85
   if(cc_str.size() > cc_digits) {
10✔
86
      throw CLI_Error("FPE produced a number too large");
×
87
   }
88
   return std::string(cc_digits - cc_str.size(), '0') + cc_str;
20✔
89
}
10✔
90

91
uint64_t encrypt_cc_number(uint64_t cc_number,
5✔
92
                           size_t cc_digits,
93
                           const Botan::SymmetricKey& key,
94
                           const std::vector<uint8_t>& tweak) {
95
   const Botan::BigInt n(cc_modulus(cc_digits));
10✔
96

97
   const Botan::BigInt c = Botan::FPE::fe1_encrypt(n, Botan::BigInt::from_u64(cc_rank(cc_number)), key, tweak);
5✔
98

99
   return cc_derank(bigint_to_u64(c));
10✔
100
}
5✔
101

102
uint64_t decrypt_cc_number(uint64_t enc_cc,
5✔
103
                           size_t cc_digits,
104
                           const Botan::SymmetricKey& key,
105
                           const std::vector<uint8_t>& tweak) {
106
   const Botan::BigInt n(cc_modulus(cc_digits));
10✔
107

108
   const Botan::BigInt c = Botan::FPE::fe1_decrypt(n, Botan::BigInt::from_u64(cc_rank(enc_cc)), key, tweak);
5✔
109

110
   return cc_derank(bigint_to_u64(c));
10✔
111
}
5✔
112

113
uint64_t parse_cc(std::string_view input) {
10✔
114
   if(input.size() >= 13 && input.size() <= 19) {
10✔
115
      if(auto cc = Botan::parse_u64(input)) {
10✔
116
         return *cc;
10✔
117
      }
118
   }
119

120
   throw CLI_Usage_Error("Invalid credit card input");
×
121
}
122

123
class CC_Encrypt final : public Command {
124
   public:
125
      CC_Encrypt() : Command("cc_encrypt CC passphrase --tweak=") {}
12✔
126

127
      std::string group() const override { return "misc"; }
1✔
128

129
      std::string description() const override {
1✔
130
         return "Encrypt the passed valid credit card number using FPE encryption";
1✔
131
      }
132

133
      void go() override {
5✔
134
         const std::string cc = get_arg("CC");
5✔
135
         const uint64_t cc_number = parse_cc(cc);
5✔
136
         const std::vector<uint8_t> tweak = Botan::hex_decode(get_arg("tweak"));
10✔
137
         const std::string pass = get_arg("passphrase");
5✔
138

139
         auto pbkdf = Botan::PBKDF::create("PBKDF2(SHA-256)");
5✔
140
         if(!pbkdf) {
5✔
141
            throw CLI_Error_Unsupported("PBKDF", "PBKDF2(SHA-256)");
×
142
         }
143

144
         auto key = Botan::SymmetricKey(pbkdf->pbkdf_iterations(32, pass, tweak.data(), tweak.size(), 100000));
5✔
145

146
         output() << format_cc_number(encrypt_cc_number(cc_number, cc.size(), key, tweak), cc.size()) << "\n";
15✔
147
      }
15✔
148
};
149

150
BOTAN_REGISTER_COMMAND("cc_encrypt", CC_Encrypt);
6✔
151

152
class CC_Decrypt final : public Command {
153
   public:
154
      CC_Decrypt() : Command("cc_decrypt CC passphrase --tweak=") {}
12✔
155

156
      std::string group() const override { return "misc"; }
1✔
157

158
      std::string description() const override {
1✔
159
         return "Decrypt the passed valid ciphertext credit card number using FPE decryption";
1✔
160
      }
161

162
      void go() override {
5✔
163
         const std::string cc = get_arg("CC");
10✔
164
         const uint64_t cc_number = parse_cc(cc);
5✔
165
         const std::vector<uint8_t> tweak = Botan::hex_decode(get_arg("tweak"));
10✔
166
         const std::string pass = get_arg("passphrase");
5✔
167

168
         auto pbkdf = Botan::PBKDF::create("PBKDF2(SHA-256)");
5✔
169
         if(!pbkdf) {
5✔
170
            throw CLI_Error_Unsupported("PBKDF", "PBKDF2(SHA-256)");
×
171
         }
172

173
         auto key = Botan::SymmetricKey(pbkdf->pbkdf_iterations(32, pass, tweak.data(), tweak.size(), 100000));
5✔
174

175
         output() << format_cc_number(decrypt_cc_number(cc_number, cc.size(), key, tweak), cc.size()) << "\n";
15✔
176
      }
15✔
177
};
178

179
BOTAN_REGISTER_COMMAND("cc_decrypt", CC_Decrypt);
6✔
180

181
}  // namespace
182

183
}  // namespace Botan_CLI
184

185
#endif  // FPE && PBKDF
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