aboutsummaryrefslogtreecommitdiffstats
path: root/src/cli/cc_enc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/cc_enc.cpp')
-rw-r--r--src/cli/cc_enc.cpp161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/cli/cc_enc.cpp b/src/cli/cc_enc.cpp
new file mode 100644
index 000000000..25c9b960b
--- /dev/null
+++ b/src/cli/cc_enc.cpp
@@ -0,0 +1,161 @@
+/*
+* (C) 2014,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "cli.h"
+#include <botan/hex.h>
+
+#if defined(BOTAN_HAS_FPE_FE1) && defined(BOTAN_HAS_PBKDF)
+
+#include <botan/fpe_fe1.h>
+#include <botan/pbkdf.h>
+
+namespace Botan_CLI {
+
+namespace {
+
+uint8_t luhn_checksum(uint64_t cc_number)
+ {
+ uint8_t sum = 0;
+
+ bool alt = false;
+ while(cc_number)
+ {
+ uint8_t digit = cc_number % 10;
+ if(alt)
+ {
+ digit *= 2;
+ if(digit > 9)
+ digit -= 9;
+ }
+
+ sum += digit;
+
+ cc_number /= 10;
+ alt = !alt;
+ }
+
+ return (sum % 10);
+ }
+
+bool luhn_check(uint64_t cc_number)
+ {
+ return (luhn_checksum(cc_number) == 0);
+ }
+
+uint64_t cc_rank(uint64_t cc_number)
+ {
+ // Remove Luhn checksum
+ return cc_number / 10;
+ }
+
+uint64_t cc_derank(uint64_t cc_number)
+ {
+ for(size_t i = 0; i != 10; ++i)
+ {
+ if(luhn_check(cc_number * 10 + i))
+ {
+ return (cc_number * 10 + i);
+ }
+ }
+
+ return 0;
+ }
+
+uint64_t encrypt_cc_number(uint64_t cc_number,
+ const Botan::secure_vector<uint8_t>& key,
+ const std::vector<uint8_t>& tweak)
+ {
+ const Botan::BigInt n = 1000000000000000;
+
+ const uint64_t cc_ranked = cc_rank(cc_number);
+
+ const Botan::BigInt c = Botan::FPE::fe1_encrypt(n, cc_ranked, key, tweak);
+
+ if(c.bits() > 50)
+ throw std::runtime_error("FPE produced a number too large");
+
+ uint64_t enc_cc = 0;
+ for(size_t i = 0; i != 7; ++i)
+ enc_cc = (enc_cc << 8) | c.byte_at(6-i);
+ return cc_derank(enc_cc);
+ }
+
+uint64_t decrypt_cc_number(uint64_t enc_cc,
+ const Botan::secure_vector<uint8_t>& key,
+ const std::vector<uint8_t>& tweak)
+ {
+ const Botan::BigInt n = 1000000000000000;
+
+ const uint64_t cc_ranked = cc_rank(enc_cc);
+
+ const Botan::BigInt c = Botan::FPE::fe1_decrypt(n, cc_ranked, key, tweak);
+
+ if(c.bits() > 50)
+ throw CLI_Error("FPE produced a number too large");
+
+ uint64_t dec_cc = 0;
+ for(size_t i = 0; i != 7; ++i)
+ dec_cc = (dec_cc << 8) | c.byte_at(6-i);
+ return cc_derank(dec_cc);
+ }
+
+}
+
+class CC_Encrypt : public Command
+ {
+ public:
+ CC_Encrypt() : Command("cc_encrypt CC passphrase --tweak=") {}
+
+ void go()
+ {
+ const uint64_t cc_number = std::stoull(get_arg("CC"));
+ const std::vector<uint8_t> tweak = Botan::hex_decode(get_arg("tweak"));
+ const std::string pass = get_arg("passphrase");
+
+ std::unique_ptr<Botan::PBKDF> pbkdf(Botan::PBKDF::create("PBKDF2(SHA-256)"));
+ if(!pbkdf)
+ throw CLI_Error_Unsupported("PBKDF", "PBKDF2(SHA-256)");
+
+ Botan::secure_vector<uint8_t> key =
+ pbkdf->pbkdf_iterations(32, pass,
+ tweak.data(), tweak.size(),
+ 100000);
+
+ output() << encrypt_cc_number(cc_number, key, tweak) << "\n";
+ }
+ };
+
+BOTAN_REGISTER_COMMAND(CC_Encrypt);
+
+class CC_Decrypt : public Command
+ {
+ public:
+ CC_Decrypt() : Command("cc_decrypt CC passphrase --tweak=") {}
+
+ void go() override
+ {
+ const uint64_t cc_number = std::stoull(get_arg("CC"));
+ const std::vector<uint8_t> tweak = Botan::hex_decode(get_arg("tweak"));
+ const std::string pass = get_arg("passphrase");
+
+ std::unique_ptr<Botan::PBKDF> pbkdf(Botan::PBKDF::create("PBKDF2(SHA-256)"));
+ if(!pbkdf)
+ throw CLI_Error_Unsupported("PBKDF", "PBKDF2(SHA-256)");
+
+ Botan::secure_vector<uint8_t> key =
+ pbkdf->pbkdf_iterations(32, pass,
+ tweak.data(), tweak.size(),
+ 100000);
+
+ output() << decrypt_cc_number(cc_number, key, tweak) << "\n";
+ }
+ };
+
+BOTAN_REGISTER_COMMAND(CC_Decrypt);
+
+}
+
+#endif // FPE && PBKDF