diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/examples/fpe.cpp | 128 |
1 files changed, 120 insertions, 8 deletions
diff --git a/doc/examples/fpe.cpp b/doc/examples/fpe.cpp index 9384a0d2d..cc9ee8093 100644 --- a/doc/examples/fpe.cpp +++ b/doc/examples/fpe.cpp @@ -1,22 +1,134 @@ +/* +* Encrypt credit cards numbers with valid checksums into other credit +* card numbers with valid checksums using format preserving encryption. +*/ + #include <botan/fpe.h> +#include <botan/sha160.h> #include <botan/init.h> using namespace Botan; #include <iostream> +#include <stdexcept> + +byte luhn_checksum(u64bit cc_number) + { + byte sum = 0; + + bool alt = false; + while(cc_number) + { + byte 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(u64bit cc_number) + { + return (luhn_checksum(cc_number) == 0); + } + +u64bit cc_rank(u64bit cc_number) + { + // Remove Luhn checksum + return cc_number / 10; + } + +u64bit cc_derank(u64bit cc_number) + { + for(u32bit i = 0; i != 10; ++i) + if(luhn_check(cc_number * 10 + i)) + return (cc_number * 10 + i); + return 0; + } + +/* +* Use the SHA-1 hash of the account name or ID as a tweak +*/ +SecureVector<byte> sha1(const std::string& acct_name) + { + SHA_160 hash; + hash.update(acct_name); + return hash.final(); + } -int main() +u64bit encrypt_cc_number(u64bit cc_number, + const SymmetricKey& key, + const std::string& acct_name) + { + BigInt n = 1000000000000000; + + u64bit cc_ranked = cc_rank(cc_number); + + BigInt c = fpe_encrypt(n, cc_ranked, key, sha1(acct_name)); + + if(c.bits() > 50) + throw std::runtime_error("FPE produced a number too large"); + + u64bit enc_cc = 0; + for(u32bit i = 0; i != 7; ++i) + enc_cc = (enc_cc << 8) | c.byte_at(6-i); + return cc_derank(enc_cc); + } + +u64bit decrypt_cc_number(u64bit enc_cc, + const SymmetricKey& key, + const std::string& acct_name) + { + BigInt n = 1000000000000000; + + u64bit cc_ranked = cc_rank(enc_cc); + + BigInt c = fpe_decrypt(n, cc_ranked, key, sha1(acct_name)); + + if(c.bits() > 50) + throw std::runtime_error("FPE produced a number too large"); + + u64bit dec_cc = 0; + for(u32bit i = 0; i != 7; ++i) + dec_cc = (dec_cc << 8) | c.byte_at(6-i); + return cc_derank(dec_cc); + } + +int main(int argc, char* argv[]) { LibraryInitializer init; - BigInt n = 100000000; - BigInt x = 49604394; + if(argc != 4) + { + std::cout << "Usage: " << argv[0] << " cc-number acct-name passwd\n"; + return 1; + } + + u64bit cc_number = atoll(argv[1]); + std::string acct_name = argv[2]; + std::string passwd = argv[3]; + + std::cout << cc_number << ' ' << luhn_check(cc_number) << '\n'; + + SymmetricKey key = sha1(passwd); + + u64bit enc_cc = encrypt_cc_number(cc_number, key, acct_name); + + std::cout << enc_cc << ' ' << luhn_check(enc_cc) << '\n'; - SymmetricKey key("AAAAAAAAAAAAAAAA"); - MemoryVector<byte> tweak(4); + u64bit dec_cc = decrypt_cc_number(enc_cc, key, acct_name); - BigInt c = fpe_encrypt(n, x, key, tweak); - BigInt p = fpe_decrypt(n, c, key, tweak); + std::cout << dec_cc << ' ' << luhn_check(dec_cc) << '\n'; - std::cout << c << ' ' << p << ' ' << x << '\n'; + if(dec_cc != cc_number) + std::cout << "Something went wrong :(\n"; } |