From a6177d3af54437375c752b8046230b7fb98c8563 Mon Sep 17 00:00:00 2001 From: lloyd Date: Thu, 5 Nov 2009 07:52:35 +0000 Subject: Add format preserving encryption, design is FE1/FD1 from the paper Format-Preserving Encryption (http://eprint.iacr.org/2009/251). This doesn't implement the rank functions which are necessary for the actual format-preserving part, though that would be nice to add to the example. --- doc/examples/fpe.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 doc/examples/fpe.cpp (limited to 'doc/examples') diff --git a/doc/examples/fpe.cpp b/doc/examples/fpe.cpp new file mode 100644 index 000000000..9384a0d2d --- /dev/null +++ b/doc/examples/fpe.cpp @@ -0,0 +1,22 @@ +#include +#include + +using namespace Botan; + +#include + +int main() + { + LibraryInitializer init; + + BigInt n = 100000000; + BigInt x = 49604394; + + SymmetricKey key("AAAAAAAAAAAAAAAA"); + MemoryVector tweak(4); + + BigInt c = fpe_encrypt(n, x, key, tweak); + BigInt p = fpe_decrypt(n, c, key, tweak); + + std::cout << c << ' ' << p << ' ' << x << '\n'; + } -- cgit v1.2.3 From 4049ba134674d78c07c8b0453cb5e5f312469639 Mon Sep 17 00:00:00 2001 From: lloyd Date: Mon, 9 Nov 2009 13:22:52 +0000 Subject: In creating X.509 certificates and PKCS #10 requests, let (actually: require) the user to specify the hash function to use, instead of always using SHA-1. This was a sensible default a few years ago, when there wasn't a ~2^60 attack on SHA-1 and support for SHA-2 was pretty much nil, but using something else makes a lot more sense these days. --- checks/x509.cpp | 10 +++++++-- doc/examples/ca.cpp | 2 +- doc/examples/gen_certs.cpp | 6 +++--- doc/examples/pkcs10.cpp | 2 +- doc/examples/self_sig.cpp | 3 ++- doc/log.txt | 1 + src/cert/x509/x509_ca.cpp | 52 +++++++++++++++++++++++++++++++--------------- src/cert/x509/x509_ca.h | 44 ++++++++++++++++++++++++++++----------- src/cert/x509/x509self.cpp | 6 ++++-- src/cert/x509/x509self.h | 4 ++++ 10 files changed, 91 insertions(+), 39 deletions(-) (limited to 'doc/examples') diff --git a/checks/x509.cpp b/checks/x509.cpp index 6f191285c..69dd29492 100644 --- a/checks/x509.cpp +++ b/checks/x509.cpp @@ -129,6 +129,8 @@ void do_x509_tests(RandomNumberGenerator& rng) { std::cout << "Testing X.509 CA/CRL/cert/cert request: " << std::flush; + std::string hash_fn = "SHA-256"; + /* Create the CA's key and self-signed cert */ std::cout << '.' << std::flush; RSA_PrivateKey ca_key(rng, 1024); @@ -136,6 +138,7 @@ void do_x509_tests(RandomNumberGenerator& rng) std::cout << '.' << std::flush; X509_Certificate ca_cert = X509::create_self_signed_cert(ca_opts(), ca_key, + hash_fn, rng); std::cout << '.' << std::flush; @@ -146,12 +149,14 @@ void do_x509_tests(RandomNumberGenerator& rng) std::cout << '.' << std::flush; PKCS10_Request user1_req = X509::create_cert_req(req_opts1(), user1_key, + "SHA-1", rng); /* Create user #2's key and cert request */ std::cout << '.' << std::flush; #if defined(BOTAN_HAS_ECDSA) - ECDSA_PrivateKey user2_key(rng, get_EC_Dom_Pars_by_oid("1.3.132.0.8")); + EC_Domain_Params ecc_domain = get_EC_Dom_Pars_by_oid("1.2.840.10045.3.1.7"); + ECDSA_PrivateKey user2_key(rng, ecc_domain); #else RSA_PrivateKey user2_key(rng, 1024); #endif @@ -159,11 +164,12 @@ void do_x509_tests(RandomNumberGenerator& rng) std::cout << '.' << std::flush; PKCS10_Request user2_req = X509::create_cert_req(req_opts2(), user2_key, + hash_fn, rng); /* Create the CA object */ std::cout << '.' << std::flush; - X509_CA ca(ca_cert, ca_key); + X509_CA ca(ca_cert, ca_key, hash_fn); std::cout << '.' << std::flush; /* Sign the requests to create the certs */ diff --git a/doc/examples/ca.cpp b/doc/examples/ca.cpp index 41dd409d5..9195be418 100644 --- a/doc/examples/ca.cpp +++ b/doc/examples/ca.cpp @@ -47,7 +47,7 @@ int main(int argc, char* argv[]) PKCS8::load_key(arg_ca_key, rng, arg_passphrase) ); - X509_CA ca(ca_cert, *privkey); + X509_CA ca(ca_cert, *privkey, "SHA-256"); // got a request PKCS10_Request req(arg_req_file); diff --git a/doc/examples/gen_certs.cpp b/doc/examples/gen_certs.cpp index f635e1ccf..90cb80038 100644 --- a/doc/examples/gen_certs.cpp +++ b/doc/examples/gen_certs.cpp @@ -34,7 +34,7 @@ X509_Certificate make_ca_cert(RandomNumberGenerator& rng, opts.end = later; opts.CA_key(); - return X509::create_self_signed_cert(opts, priv_key, rng); + return X509::create_self_signed_cert(opts, priv_key, "SHA-256", rng); } PKCS10_Request make_server_cert_req(const Private_Key& key, @@ -47,7 +47,7 @@ PKCS10_Request make_server_cert_req(const Private_Key& key, opts.add_ex_constraint("PKIX.ServerAuth"); - return X509::create_cert_req(opts, key, rng); + return X509::create_cert_req(opts, key, "SHA-1", rng); } void save_pair(const std::string& name, @@ -92,7 +92,7 @@ int main() save_pair("ca", ca_password, ca_cert, ca_key, rng); - X509_CA ca(ca_cert, ca_key); + X509_CA ca(ca_cert, ca_key, "SHA-256"); RSA_PrivateKey httpd_key(rng, 1536); X509_Certificate httpd_cert = ca.sign_request( diff --git a/doc/examples/pkcs10.cpp b/doc/examples/pkcs10.cpp index d719baf72..d9fa9accb 100644 --- a/doc/examples/pkcs10.cpp +++ b/doc/examples/pkcs10.cpp @@ -59,7 +59,7 @@ int main(int argc, char* argv[]) opts.xmpp = "someid@xmpp.org"; - PKCS10_Request req = X509::create_cert_req(opts, priv_key, rng); + PKCS10_Request req = X509::create_cert_req(opts, priv_key, "SHA-1", rng); std::ofstream req_file("req.pem"); req_file << req.PEM_encode(); diff --git a/doc/examples/self_sig.cpp b/doc/examples/self_sig.cpp index 0bf17e3bc..93161f7d2 100644 --- a/doc/examples/self_sig.cpp +++ b/doc/examples/self_sig.cpp @@ -64,7 +64,8 @@ int main(int argc, char* argv[]) if(do_CA) opts.CA_key(); - X509_Certificate cert = X509::create_self_signed_cert(opts, key, rng); + X509_Certificate cert = + X509::create_self_signed_cert(opts, key, "SHA-256", rng); std::ofstream cert_file("cert.pem"); cert_file << cert.PEM_encode(); diff --git a/doc/log.txt b/doc/log.txt index 75fde9a5f..f1c58be71 100644 --- a/doc/log.txt +++ b/doc/log.txt @@ -1,5 +1,6 @@ * 1.9.3-dev, ????-??-?? + - Allow use of any hash function in X.509 certificate creation - Set macros for available SIMD instructions in build.h * 1.9.2, 2009-11-03 diff --git a/src/cert/x509/x509_ca.cpp b/src/cert/x509/x509_ca.cpp index f0eb9c3e5..48ec0bd1c 100644 --- a/src/cert/x509/x509_ca.cpp +++ b/src/cert/x509/x509_ca.cpp @@ -9,9 +9,10 @@ #include #include #include -#include #include #include +#include +#include #include #include #include @@ -20,22 +21,33 @@ #include #include +#include + namespace Botan { /* * Load the certificate and private key */ X509_CA::X509_CA(const X509_Certificate& c, - const Private_Key& key) : cert(c) + const Private_Key& key, + const std::string& hash_fn) : cert(c) { - const Private_Key* key_pointer = &key; - if(!dynamic_cast(key_pointer)) + // Use pointer dynamic_cast to avoid exception if cast fails + if(!dynamic_cast(&key)) throw Invalid_Argument("X509_CA: " + key.algo_name() + " cannot sign"); if(!cert.is_CA_cert()) throw Invalid_Argument("X509_CA: This certificate is not for a CA"); - signer = choose_sig_format(key, ca_sig_algo); + signer = choose_sig_format(key, hash_fn, ca_sig_algo); + } + +/* +* X509_CA Destructor +*/ +X509_CA::~X509_CA() + { + delete signer; } /* @@ -70,7 +82,8 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, extensions.add( new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); - return make_cert(signer, rng, ca_sig_algo, req.raw_public_key(), + return make_cert(signer, rng, ca_sig_algo, + req.raw_public_key(), not_before, not_after, cert.subject_dn(), req.subject_dn(), extensions); @@ -230,18 +243,11 @@ X509_Certificate X509_CA::ca_certificate() const return cert; } -/* -* X509_CA Destructor -*/ -X509_CA::~X509_CA() - { - delete signer; - } - /* * Choose a signing format for the key */ PK_Signer* choose_sig_format(const Private_Key& key, + const std::string& hash_fn, AlgorithmIdentifier& sig_algo) { std::string padding; @@ -249,24 +255,36 @@ PK_Signer* choose_sig_format(const Private_Key& key, const std::string algo_name = key.algo_name(); + const HashFunction* proto_hash = retrieve_hash(hash_fn); + if(!proto_hash) + throw Algorithm_Not_Found(hash_fn); + + if(key.max_input_bits() < proto_hash->OUTPUT_LENGTH*8) + { + printf("%d %d\n", key.max_input_bits(), proto_hash->OUTPUT_LENGTH*8); + throw Invalid_Argument("Key is too small for chosen hash function"); + } + if(algo_name == "RSA") { - padding = "EMSA3(SHA-160)"; + padding = "EMSA3"; format = IEEE_1363; } else if(algo_name == "DSA") { - padding = "EMSA1(SHA-160)"; + padding = "EMSA1"; format = DER_SEQUENCE; } else if(algo_name == "ECDSA") { - padding = "EMSA1_BSI(SHA-160)"; + padding = "EMSA1_BSI"; format = IEEE_1363; } else throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name); + padding = padding + '(' + proto_hash->name() + ')'; + sig_algo.oid = OIDS::lookup(algo_name + "/" + padding); std::auto_ptr encoding(key.x509_encoder()); diff --git a/src/cert/x509/x509_ca.h b/src/cert/x509/x509_ca.h index ef2a8d134..6eb4bbbef 100644 --- a/src/cert/x509/x509_ca.h +++ b/src/cert/x509/x509_ca.h @@ -50,7 +50,8 @@ class BOTAN_DLL X509_CA * as the offset from the current time * @return the new CRL */ - X509_CRL new_crl(RandomNumberGenerator& rng, u32bit = 0) const; + X509_CRL new_crl(RandomNumberGenerator& rng, + u32bit next_update = 0) const; /** * Create a new CRL by with additional entries. @@ -65,27 +66,45 @@ class BOTAN_DLL X509_CA RandomNumberGenerator& rng, u32bit next_update = 0) const; - static X509_Certificate make_cert(PK_Signer*, - RandomNumberGenerator&, - const AlgorithmIdentifier&, - const MemoryRegion&, - const X509_Time&, const X509_Time&, - const X509_DN&, const X509_DN&, - const Extensions&); + /** + * Interface for creating new certificates + * @param signer a signing object + * @param rng a random number generator + * @param sig_algo the signature algorithm identifier + * @param not_before the start time of the certificate + * @param not_after the end time of the certificate + * @param issuer_dn the DN of the issuer + * @param subject_dn the DN of the subject + * @param extensions an optional list of certificate extensions + * @returns newly minted certificate + */ + static X509_Certificate make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const MemoryRegion& pub_key, + const X509_Time& not_before, + const X509_Time& not_after, + const X509_DN& issuer_dn, + const X509_DN& subject_dn, + const Extensions& extensions); /** * Create a new CA object. * @param ca_certificate the certificate of the CA * @param key the private key of the CA */ - X509_CA(const X509_Certificate& ca_certificate, const Private_Key& key); + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::string& hash_fn); + ~X509_CA(); private: X509_CA(const X509_CA&) {} X509_CA& operator=(const X509_CA&) { return (*this); } - X509_CRL make_crl(const std::vector&, - u32bit, u32bit, RandomNumberGenerator&) const; + X509_CRL make_crl(const std::vector& entries, + u32bit crl_number, u32bit next_update, + RandomNumberGenerator& rng) const; AlgorithmIdentifier ca_sig_algo; X509_Certificate cert; @@ -96,13 +115,14 @@ class BOTAN_DLL X509_CA * Choose the default signature format for a certain public key signature * scheme. * @param key will be the key to choose a padding scheme for +* @param hash_fn is the desired hash function * @param alg_id will be set to the chosen scheme * @return A PK_Signer object for generating signatures */ BOTAN_DLL PK_Signer* choose_sig_format(const Private_Key& key, + const std::string& hash_fn, AlgorithmIdentifier& alg_id); - } #endif diff --git a/src/cert/x509/x509self.cpp b/src/cert/x509/x509self.cpp index 8afb22a7e..f915c6ff5 100644 --- a/src/cert/x509/x509self.cpp +++ b/src/cert/x509/x509self.cpp @@ -65,6 +65,7 @@ namespace X509 { */ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, const Private_Key& key, + const std::string& hash_fn, RandomNumberGenerator& rng) { AlgorithmIdentifier sig_algo; @@ -72,7 +73,7 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, AlternativeName subject_alt; MemoryVector pub_key = shared_setup(opts, key); - std::auto_ptr signer(choose_sig_format(key, sig_algo)); + std::auto_ptr signer(choose_sig_format(key, hash_fn, sig_algo)); load_info(opts, subject_dn, subject_alt); Key_Constraints constraints; @@ -103,6 +104,7 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, */ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, const Private_Key& key, + const std::string& hash_fn, RandomNumberGenerator& rng) { AlgorithmIdentifier sig_algo; @@ -110,7 +112,7 @@ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, AlternativeName subject_alt; MemoryVector pub_key = shared_setup(opts, key); - std::auto_ptr signer(choose_sig_format(key, sig_algo)); + std::auto_ptr signer(choose_sig_format(key, hash_fn, sig_algo)); load_info(opts, subject_dn, subject_alt); const u32bit PKCS10_VERSION = 0; diff --git a/src/cert/x509/x509self.h b/src/cert/x509/x509self.h index bd3e29179..741350067 100644 --- a/src/cert/x509/x509self.h +++ b/src/cert/x509/x509self.h @@ -172,12 +172,14 @@ namespace X509 { * @param opts the options defining the certificate to create * @param key the private key used for signing, i.e. the key * associated with this self-signed certificate +* @param hash_fn the hash function to use * @param rng the rng to use * @return the newly created self-signed certificate */ BOTAN_DLL X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, const Private_Key& key, + const std::string& hash_fn, RandomNumberGenerator& rng); /** @@ -185,10 +187,12 @@ create_self_signed_cert(const X509_Cert_Options& opts, * @param opts the options defining the request to create * @param key the key used to sign this request * @param rng the rng to use +* @param hash_fn the hash function to use * @return the newly created PKCS#10 request */ BOTAN_DLL PKCS10_Request create_cert_req(const X509_Cert_Options& opts, const Private_Key& key, + const std::string& hash_fn, RandomNumberGenerator& rng); } -- cgit v1.2.3 From 651c74a712a52095206a9a7dea547c6b56b036d8 Mon Sep 17 00:00:00 2001 From: lloyd Date: Tue, 10 Nov 2009 05:40:36 +0000 Subject: Make the AES implementation using Intel's AES instruction extension official; testing with Intel's emulator shows all green. --- doc/examples/cpuid.cpp | 1 + doc/log.txt | 1 + src/block/aes_intel/aes_intel.cpp | 10 +++++----- src/block/aes_intel/aes_intel.h | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) (limited to 'doc/examples') diff --git a/doc/examples/cpuid.cpp b/doc/examples/cpuid.cpp index 1bdee787c..30ac4d676 100644 --- a/doc/examples/cpuid.cpp +++ b/doc/examples/cpuid.cpp @@ -12,6 +12,7 @@ int main() printf("SSSE3 %d\n", CPUID::has_ssse3()); printf("SSE41 %d\n", CPUID::has_sse41()); printf("SSE42 %d\n", CPUID::has_sse42()); + printf("AES-NI %d\n", CPUID::has_intel_aes()); printf("AltiVec %d\n", CPUID::has_altivec()); } diff --git a/doc/log.txt b/doc/log.txt index f1c58be71..cd97089e1 100644 --- a/doc/log.txt +++ b/doc/log.txt @@ -2,6 +2,7 @@ * 1.9.3-dev, ????-??-?? - Allow use of any hash function in X.509 certificate creation - Set macros for available SIMD instructions in build.h + - Add AES-128 using Intel AES instruction intrinsics * 1.9.2, 2009-11-03 - Add SIMD version of XTEA diff --git a/src/block/aes_intel/aes_intel.cpp b/src/block/aes_intel/aes_intel.cpp index 057728e72..fb71a5d89 100644 --- a/src/block/aes_intel/aes_intel.cpp +++ b/src/block/aes_intel/aes_intel.cpp @@ -1,6 +1,6 @@ /** -* AES -* (C) 1999-2009 Jack Lloyd +* AES using Intel's AES-NI instructions +* (C) 2009 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -24,7 +24,7 @@ __m128i aes_128_key_expansion(__m128i key, __m128i key_with_rcon) } /** -* AES Encryption +* AES-128 Encryption */ void AES_128_Intel::encrypt_n(const byte in[], byte out[], u32bit blocks) const { @@ -70,7 +70,7 @@ void AES_128_Intel::encrypt_n(const byte in[], byte out[], u32bit blocks) const } /** -* AES Decryption +* AES-128 Decryption */ void AES_128_Intel::decrypt_n(const byte in[], byte out[], u32bit blocks) const { @@ -116,7 +116,7 @@ void AES_128_Intel::decrypt_n(const byte in[], byte out[], u32bit blocks) const } /** -* AES Key Schedule +* AES-128 Key Schedule */ void AES_128_Intel::key_schedule(const byte key[], u32bit length) { diff --git a/src/block/aes_intel/aes_intel.h b/src/block/aes_intel/aes_intel.h index 90270939c..052b37bb2 100644 --- a/src/block/aes_intel/aes_intel.h +++ b/src/block/aes_intel/aes_intel.h @@ -1,6 +1,6 @@ /** -* AES using Intel's AES instructions -* (C) 1999-2009 Jack Lloyd +* AES using Intel's AES-NI instructions +* (C) 2009 Jack Lloyd * * Distributed under the terms of the Botan license */ -- cgit v1.2.3 From 743014387833eb52e71fc9d4381e2a546e80f158 Mon Sep 17 00:00:00 2001 From: lloyd Date: Tue, 10 Nov 2009 07:39:52 +0000 Subject: Rename CPUID::has_intel_aes to has_aes_intel, and add CPUID::has_aes_via, which is currently just a stub returning false. --- doc/examples/cpuid.cpp | 5 ++++- src/engine/aes_isa_eng/aes_isa_engine.cpp | 4 ++-- src/utils/cpuid.h | 13 +++++++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) (limited to 'doc/examples') diff --git a/doc/examples/cpuid.cpp b/doc/examples/cpuid.cpp index 30ac4d676..bc33ef907 100644 --- a/doc/examples/cpuid.cpp +++ b/doc/examples/cpuid.cpp @@ -7,12 +7,15 @@ using namespace Botan; int main() { printf("Cache line size: %d\n", CPUID::cache_line_size()); + printf("RDTSC: %d\n", CPUID::has_rdtsc()); printf("SSE2 %d\n", CPUID::has_sse2()); printf("SSSE3 %d\n", CPUID::has_ssse3()); printf("SSE41 %d\n", CPUID::has_sse41()); printf("SSE42 %d\n", CPUID::has_sse42()); - printf("AES-NI %d\n", CPUID::has_intel_aes()); + printf("AES-NI %d\n", CPUID::has_aes_intel()); + + printf("AES-VIA %d\n", CPUID::has_aes_via()); printf("AltiVec %d\n", CPUID::has_altivec()); } diff --git a/src/engine/aes_isa_eng/aes_isa_engine.cpp b/src/engine/aes_isa_eng/aes_isa_engine.cpp index fd36feb2f..bbbdd288e 100644 --- a/src/engine/aes_isa_eng/aes_isa_engine.cpp +++ b/src/engine/aes_isa_eng/aes_isa_engine.cpp @@ -23,7 +23,7 @@ AES_ISA_Engine::find_block_cipher(const SCAN_Name& request, Algorithm_Factory&) const { #if defined(BOTAN_HAS_AES_INTEL) - if(CPUID::has_intel_aes()) + if(CPUID::has_aes_intel()) { if(request.algo_name() == "AES-128") return new AES_128_Intel; @@ -37,7 +37,7 @@ AES_ISA_Engine::find_block_cipher(const SCAN_Name& request, #endif #if defined(BOTAN_HAS_AES_VIA) - if(CPUID::has_via_aes()) + if(CPUID::has_aes_via()) { if(request.algo_name() == "AES-128") return new AES_128_VIA; diff --git a/src/utils/cpuid.h b/src/utils/cpuid.h index 8b8021754..455721af9 100644 --- a/src/utils/cpuid.h +++ b/src/utils/cpuid.h @@ -60,11 +60,20 @@ class CPUID { return ((x86_processor_flags() >> CPUID_SSE42_BIT) & 1); } /** - * Check if the processor supports Intel AES instructions + * Check if the processor supports Intel's AES instructions */ - static bool has_intel_aes() + static bool has_aes_intel() { return ((x86_processor_flags() >> CPUID_INTEL_AES_BIT) & 1); } + /** + * Check if the processor supports VIA's AES instructions + * (not implemented) + */ + static bool has_aes_via() { return false; } + + /** + * Check if the processor supports AltiVec/VMX + */ static bool has_altivec(); private: static u64bit x86_processor_flags(); -- cgit v1.2.3 From 32b16ba09ed2aff221c88662a30bb2449d4e139f Mon Sep 17 00:00:00 2001 From: lloyd Date: Tue, 10 Nov 2009 07:44:20 +0000 Subject: Clean up cpuid test prog --- doc/examples/cpuid.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'doc/examples') diff --git a/doc/examples/cpuid.cpp b/doc/examples/cpuid.cpp index bc33ef907..76438783f 100644 --- a/doc/examples/cpuid.cpp +++ b/doc/examples/cpuid.cpp @@ -1,21 +1,28 @@ -#include - +#include #include using namespace Botan; +void print_if_feature(const std::string& feature_name, bool exists) + { + if(exists) + std::cout << feature_name << '\n'; + else + std::cout << '[' << feature_name << ']' << '\n'; + } + int main() { - printf("Cache line size: %d\n", CPUID::cache_line_size()); + std::cout << "Cache line size = " << CPUID::cache_line_size() << "\n"; - printf("RDTSC: %d\n", CPUID::has_rdtsc()); - printf("SSE2 %d\n", CPUID::has_sse2()); - printf("SSSE3 %d\n", CPUID::has_ssse3()); - printf("SSE41 %d\n", CPUID::has_sse41()); - printf("SSE42 %d\n", CPUID::has_sse42()); - printf("AES-NI %d\n", CPUID::has_aes_intel()); + print_if_feature("RDTSC", CPUID::has_rdtsc()); + print_if_feature("SSE2", CPUID::has_sse2()); + print_if_feature("SSSE3", CPUID::has_ssse3()); + print_if_feature("SSE4.1", CPUID::has_sse41()); + print_if_feature("SSE4.2", CPUID::has_sse42()); - printf("AES-VIA %d\n", CPUID::has_aes_via()); + print_if_feature("AES-NI", CPUID::has_aes_intel()); + print_if_feature("AES-VIA", CPUID::has_aes_via()); - printf("AltiVec %d\n", CPUID::has_altivec()); + print_if_feature("AltiVec", CPUID::has_altivec()); } -- cgit v1.2.3 From 47032ae7a9070b1dfb3efdd6b491a3f8be958f69 Mon Sep 17 00:00:00 2001 From: lloyd Date: Fri, 13 Nov 2009 15:07:51 +0000 Subject: Extend FPE example to encrypt credit card numbers with valid Luhn checksums onto other CCNs with valid checksums. --- doc/examples/fpe.cpp | 128 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 120 insertions(+), 8 deletions(-) (limited to 'doc/examples') 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 +#include #include using namespace Botan; #include +#include + +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 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 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"; } -- cgit v1.2.3