diff options
author | lloyd <[email protected]> | 2011-04-04 03:43:52 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2011-04-04 03:43:52 +0000 |
commit | 3b9bfbd07c3723662832caf5b1efe04de28b656d (patch) | |
tree | ee2a9324f384efead6e5bb87ac8374e7e8734c90 /examples | |
parent | 04db054f1ae8de572ee9c0cfe227e76f84096bd6 (diff) |
Convert most of the documentation to reStructured Text, adding
a makefile to build it with Sphinx (http://sphinx.pocoo.org/).
Previously credits.txt listed public domain code sources; instead
directly credit the authors in the relevant files and delete that
file.
Drop the draft FIPS 140 security policy; I can't imagine FIPS 140
validation will ever happen, and if it does, I don't want
anything to do with it.
Also drop the internals doc, which was so out of date (and
incomplete) as to be worthless.
Move the tutorials and InSiTo pdfs into old/ for the time being,
until anything relevant from them can be filtered out and
converted into RST.
Diffstat (limited to 'examples')
66 files changed, 6651 insertions, 0 deletions
diff --git a/examples/GNUmakefile b/examples/GNUmakefile new file mode 100644 index 000000000..44fcfeea5 --- /dev/null +++ b/examples/GNUmakefile @@ -0,0 +1,21 @@ + +BOTAN_CONFIG = botan-config + +CXX = g++ +CFLAGS = -O2 -ansi -W -Wall -I../../build/include +LIBS = -L../.. -lbotan + +SRCS=$(wildcard *.cpp) + +PROGS=$(patsubst %.cpp,%,$(SRCS)) + +all: $(PROGS) + +clean: + @rm -f $(PROGS) + +%: %.cpp + $(CXX) $(CFLAGS) $? $(LIBS) -o $@ + +eax_test: eax_test.cpp + $(CXX) $(CFLAGS) $? $(LIBS) -lboost_regex -o $@ diff --git a/examples/asn1.cpp b/examples/asn1.cpp new file mode 100644 index 000000000..b0a6aa104 --- /dev/null +++ b/examples/asn1.cpp @@ -0,0 +1,312 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* + A simple ASN.1 parser, similiar to 'dumpasn1' or 'openssl asn1parse', though + without some of the bells and whistles of those. Primarily used for testing + the BER decoder. The output format is modeled loosely on 'asn1parse -i' + + The output is actually less precise than the other decoders named, because + the underlying BER_Decoder hides quite a bit from userspace, such as the use + of indefinite length encodings (and the EOC markers). At some point it will + also hide the constructed string types from the user, but right now you'll + seem them as-is. + + Written by Jack Lloyd, November 9-10, 2003 + - Nov 22: Updated to new BER_Object format (tag -> class_tag/type_tag) + - Nov 25: Much improved BIT STRING output + Can deal with non-constructed taggings + Can produce UTF-8 output +*/ + +// Set this if your terminal understands UTF-8; otherwise output is in Latin-1 +#define UTF8_TERMINAL 1 + +/* + What level the outermost layer of stuff is at. Probably 0 or 1; asn1parse + uses 0 as the outermost, while 1 makes more sense to me. 2+ doesn't make + much sense at all. +*/ +#define INITIAL_LEVEL 0 + +#include <botan/botan.h> +#include <botan/bigint.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/asn1_obj.h> +#include <botan/oids.h> +#include <botan/pem.h> +#include <botan/charset.h> +using namespace Botan; + +#include <stdio.h> +#include <ctype.h> + +void decode(BER_Decoder&, u32bit); +void emit(const std::string&, u32bit, u32bit, const std::string& = ""); +std::string type_name(ASN1_Tag); + +int main(int argc, char* argv[]) + { + if(argc != 2) + { + printf("Usage: %s <file>\n", argv[0]); + return 1; + } + + Botan::LibraryInitializer init; + + try { + DataSource_Stream in(argv[1]); + + if(!PEM_Code::matches(in)) + { + BER_Decoder decoder(in); + decode(decoder, INITIAL_LEVEL); + } + else + { + std::string label; // ignored + BER_Decoder decoder(PEM_Code::decode(in, label)); + decode(decoder, INITIAL_LEVEL); + } + + } + catch(std::exception& e) + { + printf("%s\n", e.what()); + return 1; + } + return 0; + } + +void decode(BER_Decoder& decoder, u32bit level) + { + BER_Object obj = decoder.get_next_object(); + + while(obj.type_tag != NO_OBJECT) + { + const ASN1_Tag type_tag = obj.type_tag; + const ASN1_Tag class_tag = obj.class_tag; + const u32bit length = obj.value.size(); + + /* hack to insert the tag+length back in front of the stuff now + that we've gotten the type info */ + DER_Encoder encoder; + encoder.add_object(type_tag, class_tag, obj.value, obj.value.size()); + SecureVector<byte> bits = encoder.get_contents(); + + BER_Decoder data(bits); + + if(class_tag & CONSTRUCTED) + { + BER_Decoder cons_info(obj.value); + if(type_tag == SEQUENCE) + { + emit("SEQUENCE", level, length); + decode(cons_info, level+1); + } + else if(type_tag == SET) + { + emit("SET", level, length); + decode(cons_info, level+1); + } + else + { + std::string name; + + if((class_tag & APPLICATION) || (class_tag & CONTEXT_SPECIFIC) || + (class_tag & PRIVATE)) + { + name = "cons [" + to_string(type_tag) + "]"; + + if(class_tag & APPLICATION) + name += " appl"; + if(class_tag & CONTEXT_SPECIFIC) + name += " context"; + if(class_tag & PRIVATE) + name += " private"; + } + else + name = type_name(type_tag) + " (cons)"; + + emit(name, level, length); + decode(cons_info, level+1); + } + } + else if(class_tag == APPLICATION || class_tag == CONTEXT_SPECIFIC || + class_tag == PRIVATE) + { + bool not_text = false; + + for(u32bit j = 0; j != bits.size(); j++) + if(!isgraph(bits[j]) && !isspace(bits[j])) + not_text = true; + + Pipe pipe(((not_text) ? new Hex_Encoder : 0)); + pipe.process_msg(bits); + emit("[" + to_string(type_tag) + "]", level, length, + pipe.read_all_as_string()); + } + else if(type_tag == OBJECT_ID) + { + OID oid; + data.decode(oid); + + std::string out = OIDS::lookup(oid); + if(out != oid.as_string()) + out += " [" + oid.as_string() + "]"; + + emit(type_name(type_tag), level, length, out); + } + else if(type_tag == INTEGER) + { + BigInt number; + data.decode(number); + + SecureVector<byte> rep; + + /* If it's small, it's probably a number, not a hash */ + if(number.bits() <= 16) + rep = BigInt::encode(number, BigInt::Decimal); + else + rep = BigInt::encode(number, BigInt::Hexadecimal); + + std::string str; + for(u32bit j = 0; j != rep.size(); j++) + str += (char)rep[j]; + + emit(type_name(type_tag), level, length, str); + } + else if(type_tag == BOOLEAN) + { + bool boolean; + data.decode(boolean); + emit(type_name(type_tag), + level, length, (boolean ? "true" : "false")); + } + else if(type_tag == NULL_TAG) + { + emit(type_name(type_tag), level, length); + } + else if(type_tag == OCTET_STRING) + { + SecureVector<byte> bits; + data.decode(bits, type_tag); + bool not_text = false; + + for(u32bit j = 0; j != bits.size(); j++) + if(!isgraph(bits[j]) && !isspace(bits[j])) + not_text = true; + + Pipe pipe(((not_text) ? new Hex_Encoder : 0)); + pipe.process_msg(bits); + emit(type_name(type_tag), level, length, pipe.read_all_as_string()); + } + else if(type_tag == BIT_STRING) + { + SecureVector<byte> bits; + data.decode(bits, type_tag); + + std::vector<bool> bit_set; + + for(u32bit j = 0; j != bits.size(); j++) + for(u32bit k = 0; k != 8; k++) + bit_set.push_back((bool)((bits[bits.size()-j-1] >> (7-k)) & 1)); + + std::string bit_str; + for(u32bit j = 0; j != bit_set.size(); j++) + { + bool the_bit = bit_set[bit_set.size()-j-1]; + + if(!the_bit && bit_str.size() == 0) + continue; + bit_str += (the_bit ? "1" : "0"); + } + + emit(type_name(type_tag), level, length, bit_str); + } + else if(type_tag == PRINTABLE_STRING || + type_tag == NUMERIC_STRING || + type_tag == IA5_STRING || + type_tag == T61_STRING || + type_tag == VISIBLE_STRING || + type_tag == UTF8_STRING || + type_tag == BMP_STRING) + { + ASN1_String str; + data.decode(str); + if(UTF8_TERMINAL) + emit(type_name(type_tag), level, length, + Charset::transcode(str.iso_8859(), + LATIN1_CHARSET, UTF8_CHARSET)); + else + emit(type_name(type_tag), level, length, str.iso_8859()); + } + else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME) + { + X509_Time time; + data.decode(time); + emit(type_name(type_tag), level, length, time.readable_string()); + } + else + fprintf(stderr, "Unknown tag: class=%02X, type=%02X\n", + class_tag, type_tag); + + obj = decoder.get_next_object(); + } + } + +void emit(const std::string& type, u32bit level, u32bit length, + const std::string& value) + { + const u32bit LIMIT = 128; + const u32bit BIN_LIMIT = 64; + + int written = 0; + written += printf(" d=%2d, l=%4d: ", level, length); + for(u32bit j = INITIAL_LEVEL; j != level; j++) + written += printf(" "); + written += printf("%s ", type.c_str()); + + bool should_skip = false; + if(value.length() > LIMIT) should_skip = true; + if((type == "OCTET STRING" || type == "BIT STRING") && + value.length() > BIN_LIMIT) + should_skip = true; + + if(value != "" && !should_skip) + { + if(written % 2 == 0) printf(" "); + while(written < 50) written += printf(" "); + printf(":%s\n", value.c_str()); + } + else + printf("\n"); + } + +std::string type_name(ASN1_Tag type) + { + if(type == PRINTABLE_STRING) return "PRINTABLE STRING"; + if(type == NUMERIC_STRING) return "NUMERIC STRING"; + if(type == IA5_STRING) return "IA5 STRING"; + if(type == T61_STRING) return "T61 STRING"; + if(type == UTF8_STRING) return "UTF8 STRING"; + if(type == VISIBLE_STRING) return "VISIBLE STRING"; + if(type == BMP_STRING) return "BMP STRING"; + + if(type == UTC_TIME) return "UTC TIME"; + if(type == GENERALIZED_TIME) return "GENERALIZED TIME"; + + if(type == OCTET_STRING) return "OCTET STRING"; + if(type == BIT_STRING) return "BIT STRING"; + + if(type == INTEGER) return "INTEGER"; + if(type == NULL_TAG) return "NULL"; + if(type == OBJECT_ID) return "OBJECT"; + if(type == BOOLEAN) return "BOOLEAN"; + return "(UNKNOWN)"; + } diff --git a/examples/base64.cpp b/examples/base64.cpp new file mode 100644 index 000000000..dbe8d19e3 --- /dev/null +++ b/examples/base64.cpp @@ -0,0 +1,80 @@ +/* +* Encode/decode base64 strings +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <fstream> +#include <iostream> +#include <string> +#include <vector> +#include <cstring> +#include <cstdlib> +#include <botan/botan.h> + +int main(int argc, char* argv[]) + { + if(argc < 2) + { + std::cout << "Usage: " << argv[0] << " [-w] [-c n] [-e|-d] files...\n" + " -e : Encode input to base64 strings (default) \n" + " -d : Decode base64 input\n" + " -w : Wrap lines\n" + " -c n: Wrap lines at column n, default 78\n"; + return 1; + } + + Botan::LibraryInitializer init; + + int column = 78; + bool wrap = false; + bool encoding = true; + std::vector<std::string> files; + + for(int j = 1; argv[j] != 0; j++) + { + std::string this_arg = argv[j]; + + if(this_arg == "-w") + wrap = true; + else if(this_arg == "-e"); + else if(this_arg == "-d") + encoding = false; + else if(this_arg == "-c") + { + if(argv[j+1]) + { column = atoi(argv[j+1]); j++; } + else + { + std::cout << "No argument for -c option" << std::endl; + return 1; + } + } + else files.push_back(argv[j]); + } + + for(unsigned int j = 0; j != files.size(); j++) + { + std::istream* stream; + if(files[j] == "-") stream = &std::cin; + else stream = new std::ifstream(files[j].c_str()); + + if(!*stream) + { + std::cout << "ERROR, couldn't open " << files[j] << std::endl; + continue; + } + + Botan::Pipe pipe((encoding) ? + ((Botan::Filter*)new Botan::Base64_Encoder(wrap, column)) : + ((Botan::Filter*)new Botan::Base64_Decoder)); + pipe.start_msg(); + *stream >> pipe; + pipe.end_msg(); + pipe.set_default_msg(j); + std::cout << pipe; + if(files[j] != "-") delete stream; + } + return 0; + } diff --git a/examples/bcrypt.cpp b/examples/bcrypt.cpp new file mode 100644 index 000000000..27a98cf33 --- /dev/null +++ b/examples/bcrypt.cpp @@ -0,0 +1,45 @@ +/* +* Bcrypt example +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/bcrypt.h> +#include <iostream> + +using namespace Botan; + +int main(int argc, char* argv[]) + { + if(argc != 2 && argc != 3) + { + std::cout << "Usage: " << argv[0] << " password\n" + << " " << argv[0] << " password passhash\n"; + return 1; + } + + LibraryInitializer init; + + if(argc == 2) + { + AutoSeeded_RNG rng; + + std::cout << generate_bcrypt(argv[1], rng, 12) << "\n"; + } + else if(argc == 3) + { + if(strlen(argv[2]) != 60) + { + std::cout << "Note: hash " << argv[2] + << " has wrong length and cannot be valid\n"; + } + + const bool ok = check_bcrypt(argv[1], argv[2]); + + std::cout << "Password is " << (ok ? "valid" : "NOT valid") << "\n"; + } + + return 0; + } diff --git a/examples/bench.cpp b/examples/bench.cpp new file mode 100644 index 000000000..20e6ec40b --- /dev/null +++ b/examples/bench.cpp @@ -0,0 +1,107 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/benchmark.h> +#include <botan/init.h> +#include <botan/auto_rng.h> +#include <botan/libstate.h> + +using namespace Botan; + +#include <iostream> + +namespace { + +const std::string algos[] = { + "AES-128", + "AES-192", + "AES-256", + "Blowfish", + "CAST-128", + "CAST-256", + "DES", + "DESX", + "TripleDES", + "GOST", + "IDEA", + "KASUMI", + "Lion(SHA-256,Turing,8192)", + "Luby-Rackoff(SHA-512)", + "MARS", + "MISTY1", + "Noekeon", + "RC2", + "RC5(12)", + "RC5(16)", + "RC6", + "SAFER-SK(10)", + "SEED", + "Serpent", + "Skipjack", + "Square", + "TEA", + "Twofish", + "XTEA", + "Adler32", + "CRC32", + "GOST-34.11", + "HAS-160", + "MD2", + "MD4", + "MD5", + "RIPEMD-128", + "RIPEMD-160", + "SHA-160", + "SHA-256", + "SHA-384", + "SHA-512", + "Skein-512", + "Tiger", + "Whirlpool", + "CMAC(AES-128)", + "HMAC(SHA-1)", + "X9.19-MAC", + "", +}; + +void benchmark_algo(const std::string& algo, + RandomNumberGenerator& rng) + { + u32bit milliseconds = 3000; + Algorithm_Factory& af = global_state().algorithm_factory(); + + std::map<std::string, double> speeds = + algorithm_benchmark(algo, af, rng, milliseconds, 16*1024); + + std::cout << algo << ":"; + + for(std::map<std::string, double>::const_iterator i = speeds.begin(); + i != speeds.end(); ++i) + { + std::cout << " " << i->second << " [" << i->first << "]"; + } + std::cout << "\n"; + } + +} + +int main(int argc, char* argv[]) + { + LibraryInitializer init; + + AutoSeeded_RNG rng; + + if(argc == 1) // no args, benchmark everything + { + for(u32bit i = 0; algos[i] != ""; ++i) + benchmark_algo(algos[i], rng); + } + else + { + for(int i = 1; argv[i]; ++i) + benchmark_algo(argv[i], rng); + } + } diff --git a/examples/benchmark.cpp b/examples/benchmark.cpp new file mode 100644 index 000000000..7ad1775e2 --- /dev/null +++ b/examples/benchmark.cpp @@ -0,0 +1,46 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/benchmark.h> + +#include <iostream> +#include <string> +#include <map> +#include <cstdlib> + +int main(int argc, char* argv[]) + { + if(argc <= 2) + { + std::cout << "Usage: " << argv[0] << " seconds <algo1> <algo2> ...\n"; + return 1; + } + + Botan::LibraryInitializer init; + + Botan::AutoSeeded_RNG rng; + + Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory(); + + double ms = 1000 * std::atof(argv[1]); + + for(size_t i = 2; argv[i]; ++i) + { + std::string algo = argv[i]; + + std::map<std::string, double> results = + algorithm_benchmark(algo, af, rng, ms, 16*1024); + + std::cout << algo << ":\n"; + for(std::map<std::string, double>::iterator r = results.begin(); + r != results.end(); ++r) + { + std::cout << " " << r->first << ": " << r->second << " MiB/s\n"; + } + std::cout << "\n"; + } + } diff --git a/examples/bzip.cpp b/examples/bzip.cpp new file mode 100644 index 000000000..6137bb6af --- /dev/null +++ b/examples/bzip.cpp @@ -0,0 +1,116 @@ +/* +* Bzip2 Compression/Decompression +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <string> +#include <cstring> +#include <vector> +#include <fstream> +#include <iostream> +#include <botan/botan.h> + +/* +* If Bzip2 isn't included, we know nothing works at compile time, but +* we wait to fail at runtime. Otherwise I would get 2-3 mails a month +* about how this was failing to compile (even with an informative +* #error message explaining the situation) because bzip2 wasn't +* included in the build. +*/ + +#if defined(BOTAN_HAS_COMPRESSOR_BZIP2) + #include <botan/bzip2.h> +#endif + +const std::string SUFFIX = ".bz2"; + +int main(int argc, char* argv[]) + { + if(argc < 2) + { + std::cout << "Usage: " << argv[0] + << " [-s] [-d] [-1...9] <filenames>" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + std::vector<std::string> files; + bool decompress = false, small = false; + int level = 9; + + for(int j = 1; argv[j] != 0; j++) + { + if(std::strcmp(argv[j], "-d") == 0) { decompress = true; continue; } + if(std::strcmp(argv[j], "-s") == 0) { small = true; continue; } + if(std::strcmp(argv[j], "-1") == 0) { level = 1; continue; } + if(std::strcmp(argv[j], "-2") == 0) { level = 2; continue; } + if(std::strcmp(argv[j], "-3") == 0) { level = 3; continue; } + if(std::strcmp(argv[j], "-4") == 0) { level = 4; continue; } + if(std::strcmp(argv[j], "-5") == 0) { level = 5; continue; } + if(std::strcmp(argv[j], "-6") == 0) { level = 6; continue; } + if(std::strcmp(argv[j], "-7") == 0) { level = 7; continue; } + if(std::strcmp(argv[j], "-8") == 0) { level = 8; continue; } + if(std::strcmp(argv[j], "-9") == 0) { level = 9; continue; } + files.push_back(argv[j]); + } + + try { + + Botan::Filter* bzip = 0; +#ifdef BOTAN_HAS_COMPRESSOR_BZIP2 + if(decompress) + bzip = new Botan::Bzip_Decompression(small); + else + bzip = new Botan::Bzip_Compression(level); +#endif + + if(!bzip) + { + std::cout << "Sorry, support for bzip2 not compiled into Botan\n"; + return 1; + } + + Botan::Pipe pipe(bzip); + + for(unsigned int j = 0; j != files.size(); j++) + { + std::string infile = files[j], outfile = files[j]; + if(!decompress) + outfile = outfile += SUFFIX; + else + outfile = outfile.replace(outfile.find(SUFFIX), + SUFFIX.length(), ""); + + std::ifstream in(infile.c_str(), std::ios::binary); + std::ofstream out(outfile.c_str(), std::ios::binary); + if(!in) + { + std::cout << "ERROR: could not read " << infile << std::endl; + continue; + } + if(!out) + { + std::cout << "ERROR: could not write " << outfile << std::endl; + continue; + } + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + pipe.set_default_msg(j); + out << pipe; + + in.close(); + out.close(); + } + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + return 1; + } + return 0; + } diff --git a/examples/ca.cpp b/examples/ca.cpp new file mode 100644 index 000000000..8dd3e981f --- /dev/null +++ b/examples/ca.cpp @@ -0,0 +1,76 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* + Implement the functionality of a simple CA: read in a CA certificate, + the associated private key, and a PKCS #10 certificate request. Sign the + request and print out the new certificate. + + File names are hardcoded for simplicity. + cacert.pem: The CA's certificate (perhaps created by self_sig) + caprivate.pem: The CA's private key + req.pem: The user's PKCS #10 certificate request +*/ + +#include <botan/botan.h> +#include <botan/x509_ca.h> +#include <botan/time.h> +using namespace Botan; + +#include <iostream> +#include <memory> + +int main(int argc, char* argv[]) + { + if(argc != 5) + { + std::cout << "Usage: " << argv[0] << " <passphrase> " + << "<ca cert> <ca key> <pkcs10>" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + try + { + const std::string arg_passphrase = argv[1]; + const std::string arg_ca_cert = argv[2]; + const std::string arg_ca_key = argv[3]; + const std::string arg_req_file = argv[4]; + + AutoSeeded_RNG rng; + + X509_Certificate ca_cert(arg_ca_cert); + + std::auto_ptr<PKCS8_PrivateKey> privkey( + PKCS8::load_key(arg_ca_key, rng, arg_passphrase) + ); + + X509_CA ca(ca_cert, *privkey, "SHA-256"); + + // got a request + PKCS10_Request req(arg_req_file); + + // you would insert checks here, and perhaps modify the request + // (this example should be extended to show how) + + // now sign the request + X509_Time start_time(system_time()); + X509_Time end_time(system_time() + 365 * 60 * 60 * 24); + + X509_Certificate new_cert = ca.sign_request(req, rng, + start_time, end_time); + + // send the new cert back to the requestor + std::cout << new_cert.PEM_encode(); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; + } diff --git a/examples/cert_verify.cpp b/examples/cert_verify.cpp new file mode 100644 index 000000000..04bcbecad --- /dev/null +++ b/examples/cert_verify.cpp @@ -0,0 +1,35 @@ +/* +* Simple example of a certificate validation +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/x509cert.h> +#include <botan/x509stor.h> + +#include <stdio.h> + +using namespace Botan; + +int main() + { + LibraryInitializer init; + + X509_Certificate ca_cert("ca_cert.pem"); + X509_Certificate subject_cert("http_cert.pem"); + + X509_Store cert_store; + + cert_store.add_cert(ca_cert, /*trusted=*/true); + + X509_Code code = cert_store.validate_cert(subject_cert); + + if(code == VERIFIED) + printf("Cert validated\n"); + else + printf("Cert did not validate, code = %d\n", code); + + return 0; + } diff --git a/examples/checksum.cpp b/examples/checksum.cpp new file mode 100644 index 000000000..dba7a7d70 --- /dev/null +++ b/examples/checksum.cpp @@ -0,0 +1,37 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/filters.h> + +#include <iostream> + +using namespace Botan; + +int main(int argc, char* argv[]) + { + if(argc != 2) + { + std::cout << "Usage: " << argv[0] << " filename\n"; + return 1; + } + + Botan::LibraryInitializer init; + + Pipe pipe(new Fork( + new Chain(new Hash_Filter("CRC24"), new Hex_Encoder), + new Chain(new Hash_Filter("CRC32"), new Hex_Encoder), + new Chain(new Hash_Filter("Adler32"), new Hex_Encoder) + )); + + DataSource_Stream in(argv[1]); + + pipe.process_msg(in); + + std::cout << pipe.read_all_as_string(0) << "\n"; + std::cout << pipe.read_all_as_string(1) << "\n"; + std::cout << pipe.read_all_as_string(2) << "\n"; + } diff --git a/examples/cms_dec.cpp b/examples/cms_dec.cpp new file mode 100644 index 000000000..84355fb4a --- /dev/null +++ b/examples/cms_dec.cpp @@ -0,0 +1,120 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/pkcs8.h> +#include <botan/cms_dec.h> +using namespace Botan; + +#include <iostream> +#include <memory> + +int main(int argc, char* argv[]) + { + if(argc != 2) + { + std::cout << "Usage: " << argv[0] << " <filename>\n"; + return 1; + } + + Botan::LibraryInitializer init; + + try { + AutoSeeded_RNG rng; + + X509_Certificate mycert("mycert.pem"); + PKCS8_PrivateKey* mykey = PKCS8::load_key("mykey.pem", rng, "cut"); + + X509_Certificate yourcert("yourcert.pem"); + X509_Certificate cacert("cacert.pem"); + X509_Certificate int_ca("int_ca.pem"); + + X509_Store store; + store.add_cert(mycert); + store.add_cert(yourcert); + store.add_cert(cacert, true); + store.add_cert(int_ca); + + DataSource_Stream message(argv[1]); + + CMS_Decoder decoder(message, store, mykey); + + while(decoder.layer_type() != CMS_Decoder::DATA) + { + CMS_Decoder::Status status = decoder.layer_status(); + CMS_Decoder::Content_Type content = decoder.layer_type(); + + if(status == CMS_Decoder::FAILURE) + { + std::cout << "Failure reading CMS data" << std::endl; + break; + } + + if(content == CMS_Decoder::DIGESTED) + { + std::cout << "Digested data, hash = " << decoder.layer_info() + << std::endl; + std::cout << "Hash is " + << ((status == CMS_Decoder::GOOD) ? "good" : "bad") + << std::endl; + } + + if(content == CMS_Decoder::SIGNED) + { + // how to handle multiple signers? they can all exist within a + // single level... + + std::cout << "Signed by " << decoder.layer_info() << std::endl; + //std::cout << "Sign time: " << decoder.xxx() << std::endl; + std::cout << "Signature is "; + if(status == CMS_Decoder::GOOD) + std::cout << "valid"; + else if(status == CMS_Decoder::BAD) + std::cout << "bad"; + else if(status == CMS_Decoder::NO_KEY) + std::cout << "(cannot check, no known cert)"; + std::cout << std::endl; + } + if(content == CMS_Decoder::ENVELOPED || + content == CMS_Decoder::COMPRESSED || + content == CMS_Decoder::AUTHENTICATED) + { + if(content == CMS_Decoder::ENVELOPED) + std::cout << "Enveloped"; + if(content == CMS_Decoder::COMPRESSED) + std::cout << "Compressed"; + if(content == CMS_Decoder::AUTHENTICATED) + std::cout << "MACed"; + + std::cout << ", algo = " << decoder.layer_info() << std::endl; + + if(content == CMS_Decoder::AUTHENTICATED) + { + std::cout << "MAC status is "; + if(status == CMS_Decoder::GOOD) + std::cout << "valid"; + else if(status == CMS_Decoder::BAD) + std::cout << "bad"; + else if(status == CMS_Decoder::NO_KEY) + std::cout << "(cannot check, no key)"; + std::cout << std::endl; + } + } + decoder.next_layer(); + } + + if(decoder.layer_type() == CMS_Decoder::DATA) + std::cout << "Message is \"" << decoder.get_data() + << '"' << std::endl; + else + std::cout << "No data anywhere?" << std::endl; + } + catch(std::exception& e) + { + std::cerr << e.what() << std::endl; + } + return 0; + } diff --git a/examples/cms_enc.cpp b/examples/cms_enc.cpp new file mode 100644 index 000000000..2cf813987 --- /dev/null +++ b/examples/cms_enc.cpp @@ -0,0 +1,59 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/cms_enc.h> +using namespace Botan; + +#include <iostream> +#include <fstream> +#include <memory> + +int main() + { + Botan::LibraryInitializer init; + + try { + + X509_Certificate mycert("mycert.pem"); + X509_Certificate mycert2("mycert2.pem"); + X509_Certificate yourcert("yourcert.pem"); + X509_Certificate cacert("cacert.pem"); + X509_Certificate int_ca("int_ca.pem"); + + AutoSeeded_RNG rng; + + X509_Store store; + store.add_cert(mycert); + store.add_cert(mycert2); + store.add_cert(yourcert); + store.add_cert(int_ca); + store.add_cert(cacert, true); + + const std::string msg = "prioncorp: we don't toy\n"; + + CMS_Encoder encoder(msg); + + encoder.compress("Zlib"); + encoder.digest(); + encoder.encrypt(rng, mycert); + + /* + PKCS8_PrivateKey* mykey = PKCS8::load_key("mykey.pem", rng, "cut"); + encoder.sign(store, *mykey); + */ + + SecureVector<byte> raw = encoder.get_contents(); + std::ofstream out("out.der"); + + out.write((const char*)raw.begin(), raw.size()); + } + catch(std::exception& e) + { + std::cerr << e.what() << std::endl; + } + return 0; + } diff --git a/examples/cpuid.cpp b/examples/cpuid.cpp new file mode 100644 index 000000000..6d4cc7593 --- /dev/null +++ b/examples/cpuid.cpp @@ -0,0 +1,46 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <iostream> +#include <string> +#include <botan/cpuid.h> + +using namespace Botan; + +namespace { + +void print_if_feature(const std::string& feature_name, bool exists) + { + std::cout << (exists ? '+' : '-') << " " << feature_name << "\n"; + } + +void print_header(const std::string& descr) + { + std::cout << "\n" << descr << "\n-----\n"; + } + +} + +int main() + { + CPUID::initialize(); + + std::cout << "Cache line size = " << CPUID::cache_line_size() << "\n"; + + print_header("SIMD instruction sets"); + 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()); + print_if_feature("AVX", CPUID::has_avx()); + print_if_feature("AltiVec", CPUID::has_altivec()); + + print_header("Other extensions"); + print_if_feature("RDTSC", CPUID::has_rdtsc()); + print_if_feature("PCMUL", CPUID::has_pcmuludq()); + print_if_feature("AES-NI", CPUID::has_aes_ni()); + print_if_feature("MOVBE", CPUID::has_movbe()); + } diff --git a/examples/cryptobox.cpp b/examples/cryptobox.cpp new file mode 100644 index 000000000..38d750d17 --- /dev/null +++ b/examples/cryptobox.cpp @@ -0,0 +1,53 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/cryptobox.h> +#include <fstream> +#include <iostream> +#include <vector> + +using namespace Botan; + +int main(int argc, char* argv[]) + { + LibraryInitializer init; + + AutoSeeded_RNG rng; + + if(argc != 3) + { + std::cout << "Usage: cryptobox pass filename\n"; + return 1; + } + + std::string pass = argv[1]; + std::string filename = argv[2]; + + std::ifstream input(filename.c_str(), std::ios::binary); + + std::vector<byte> file_contents; + while(input.good()) + { + byte filebuf[4096] = { 0 }; + input.read((char*)filebuf, sizeof(filebuf)); + size_t got = input.gcount(); + + file_contents.insert(file_contents.end(), filebuf, filebuf+got); + } + + std::string ciphertext = CryptoBox::encrypt(&file_contents[0], + file_contents.size(), + pass, rng); + + std::cout << ciphertext; + + /* + std::cout << CryptoBox::decrypt((const byte*)&ciphertext[0], + ciphertext.length(), + pass); + */ + } diff --git a/examples/decrypt.cpp b/examples/decrypt.cpp new file mode 100644 index 000000000..ea510c5e9 --- /dev/null +++ b/examples/decrypt.cpp @@ -0,0 +1,173 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Decrypt files encrypted with the 'encrypt' example application. + +I'm being lazy and writing the output to stdout rather than stripping +off the ".enc" suffix and writing it there. So all diagnostics go to +stderr so there is no confusion. +*/ + +#include <fstream> +#include <iostream> +#include <string> +#include <vector> +#include <cstring> +#include <memory> + +#include <botan/botan.h> + +#if defined(BOTAN_HAS_COMPRESSOR_ZLIB) + #include <botan/zlib.h> +#endif + +using namespace Botan; + +SecureVector<byte> b64_decode(const std::string&); + +int main(int argc, char* argv[]) + { + if(argc < 2) + { + std::cout << "Usage: " << argv[0] << " [-p passphrase] file\n" + << " -p : Use this passphrase to decrypt\n"; + return 1; + } + + Botan::LibraryInitializer init; + + std::string filename, passphrase; + + for(int j = 1; argv[j] != 0; j++) + { + if(std::strcmp(argv[j], "-p") == 0) + { + if(argv[j+1]) + { + passphrase = argv[j+1]; + j++; + } + else + { + std::cout << "No argument for -p option" << std::endl; + return 1; + } + } + else + { + if(filename != "") + { + std::cout << "You can only specify one file at a time\n"; + return 1; + } + filename = argv[j]; + } + } + + if(passphrase == "") + { + std::cout << "You have to specify a passphrase!" << std::endl; + return 1; + } + + std::ifstream in(filename.c_str()); + if(!in) + { + std::cout << "ERROR: couldn't open " << filename << std::endl; + return 1; + } + + std::string algo; + + try { + std::string header, salt_str, mac_str; + std::getline(in, header); + std::getline(in, algo); + std::getline(in, salt_str); + std::getline(in, mac_str); + + if(header != "-------- ENCRYPTED FILE --------") + { + std::cout << "ERROR: File is missing the usual header" << std::endl; + return 1; + } + + const BlockCipher* cipher_proto = global_state().algorithm_factory().prototype_block_cipher(algo); + + if(!cipher_proto) + { + std::cout << "Don't know about the block cipher \"" << algo << "\"\n"; + return 1; + } + + const u32bit key_len = cipher_proto->maximum_keylength(); + const u32bit iv_len = cipher_proto->block_size(); + + std::auto_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(SHA-1)")); + + const u32bit PBKDF2_ITERATIONS = 8192; + + SecureVector<byte> salt = b64_decode(salt_str); + + SymmetricKey bc_key = pbkdf->derive_key(key_len, "BLK" + passphrase, + &salt[0], salt.size(), + PBKDF2_ITERATIONS); + + InitializationVector iv = pbkdf->derive_key(iv_len, "IVL" + passphrase, + &salt[0], salt.size(), + PBKDF2_ITERATIONS); + + SymmetricKey mac_key = pbkdf->derive_key(16, "MAC" + passphrase, + &salt[0], salt.size(), + PBKDF2_ITERATIONS); + + Pipe pipe(new Base64_Decoder, + get_cipher(algo + "/CBC", bc_key, iv, DECRYPTION), +#ifdef BOTAN_HAS_COMPRESSOR_ZLIB + new Zlib_Decompression, +#endif + new Fork( + 0, + new Chain(new MAC_Filter("HMAC(SHA-1)", mac_key), + new Base64_Encoder) + ) + ); + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + + std::string our_mac = pipe.read_all_as_string(1); + if(our_mac != mac_str) + std::cout << "WARNING: MAC in message failed to verify\n"; + + std::cout << pipe.read_all_as_string(0); + } + catch(Algorithm_Not_Found) + { + std::cout << "Don't know about the block cipher \"" << algo << "\"\n"; + return 1; + } + catch(Decoding_Error) + { + std::cout << "Bad passphrase or corrupt file\n"; + return 1; + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + return 1; + } + return 0; + } + +SecureVector<byte> b64_decode(const std::string& in) + { + Pipe pipe(new Base64_Decoder); + pipe.process_msg(in); + return pipe.read_all(); + } diff --git a/examples/dh.cpp b/examples/dh.cpp new file mode 100644 index 000000000..652c7b136 --- /dev/null +++ b/examples/dh.cpp @@ -0,0 +1,73 @@ +/* +* (C) 2009-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/dh.h> +#include <botan/pubkey.h> +using namespace Botan; + +#include <iostream> +#include <memory> + +int main() + { + Botan::LibraryInitializer init; + + try + { + AutoSeeded_RNG rng; + + // Alice and Bob agree on a DH domain to use + DL_Group shared_domain("modp/ietf/1024"); + + // Alice creates a DH key and sends (the public part) to Bob + DH_PrivateKey private_a(rng, shared_domain); + + // Alice sends to Bob her public key: + MemoryVector<byte> public_a = private_a.public_value(); + + // Bob creates a key with a matching group + DH_PrivateKey private_b(rng, shared_domain); + + // Bob sends his public key to Alice + MemoryVector<byte> public_b = private_b.public_value(); + + PK_Key_Agreement ka1(private_a, "KDF2(SHA-1)"); + PK_Key_Agreement ka2(private_b, "KDF2(SHA-1)"); + + /* + * Preferably, include some salt or parameter that binds this key + * generation to the current session (for instance a session + * identifier, if guaranteed unique, would be a good choice). Or + * anything else that both sides can agree on that will never + * repeat. + */ + const std::string ka_salt = "alice and bob agree on a key"; + + SymmetricKey alice_key = ka1.derive_key(32, public_b, ka_salt); + SymmetricKey bob_key = ka2.derive_key(32, public_a, ka_salt); + + if(alice_key == bob_key) + { + std::cout << "The two keys matched, everything worked\n"; + std::cout << "The shared key was: " << alice_key.as_string() << "\n"; + } + else + { + std::cout << "The two keys didn't match! Hmmm...\n"; + std::cout << "Alice's key was: " << alice_key.as_string() << "\n"; + std::cout << "Bob's key was: " << bob_key.as_string() << "\n"; + } + + // Now use the shared key for encryption or MACing or whatever + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; + } diff --git a/examples/dsa_kgen.cpp b/examples/dsa_kgen.cpp new file mode 100644 index 000000000..fe3157370 --- /dev/null +++ b/examples/dsa_kgen.cpp @@ -0,0 +1,58 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +* +* Generate a 1024 bit DSA key and put it into a file. The public key +* format is that specified by X.509, while the private key format is +* PKCS #8. +*/ + +#include <iostream> +#include <fstream> +#include <string> +#include <botan/botan.h> +#include <botan/dsa.h> +#include <botan/rng.h> +using namespace Botan; + +#include <memory> + +int main(int argc, char* argv[]) + { + if(argc != 1 && argc != 2) + { + std::cout << "Usage: " << argv[0] << " [passphrase]" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + std::ofstream priv("dsapriv.pem"); + std::ofstream pub("dsapub.pem"); + if(!priv || !pub) + { + std::cout << "Couldn't write output files" << std::endl; + return 1; + } + + try + { + AutoSeeded_RNG rng; + + DL_Group group(rng, DL_Group::DSA_Kosherizer, 2048, 256); + + DSA_PrivateKey key(rng, group); + + pub << X509::PEM_encode(key); + if(argc == 1) + priv << PKCS8::PEM_encode(key); + else + priv << PKCS8::PEM_encode(key, rng, argv[1]); + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + } + return 0; + } diff --git a/examples/dsa_sign.cpp b/examples/dsa_sign.cpp new file mode 100644 index 000000000..5f02c0dc1 --- /dev/null +++ b/examples/dsa_sign.cpp @@ -0,0 +1,81 @@ +/* +* DSA signature generation example +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <iostream> +#include <iomanip> +#include <fstream> +#include <string> +#include <memory> + +#include <botan/botan.h> +#include <botan/pubkey.h> +#include <botan/dsa.h> +using namespace Botan; + +const std::string SUFFIX = ".sig"; + +int main(int argc, char* argv[]) + { + if(argc != 4) + { + std::cout << "Usage: " << argv[0] << " keyfile messagefile passphrase" + << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + try { + std::string passphrase(argv[3]); + + std::ifstream message(argv[2], std::ios::binary); + if(!message) + { + std::cout << "Couldn't read the message file." << std::endl; + return 1; + } + + std::string outfile = argv[2] + SUFFIX; + std::ofstream sigfile(outfile.c_str()); + if(!sigfile) + { + std::cout << "Couldn't write the signature to " + << outfile << std::endl; + return 1; + } + + AutoSeeded_RNG rng; + + std::auto_ptr<PKCS8_PrivateKey> key( + PKCS8::load_key(argv[1], rng, passphrase) + ); + + DSA_PrivateKey* dsakey = dynamic_cast<DSA_PrivateKey*>(key.get()); + + if(!dsakey) + { + std::cout << "The loaded key is not a DSA key!\n"; + return 1; + } + + PK_Signer signer(*dsakey, "EMSA1(SHA-1)"); + + DataSource_Stream in(message); + byte buf[4096] = { 0 }; + while(u32bit got = in.read(buf, sizeof(buf))) + signer.update(buf, got); + + Pipe pipe(new Base64_Encoder); + pipe.process_msg(signer.signature(rng)); + sigfile << pipe.read_all_as_string() << std::endl; + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + } + return 0; + } diff --git a/examples/dsa_ver.cpp b/examples/dsa_ver.cpp new file mode 100644 index 000000000..a666259c1 --- /dev/null +++ b/examples/dsa_ver.cpp @@ -0,0 +1,98 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Grab an DSA public key from the file given as an argument, grab a +signature from another file, and verify the message (which, suprise, +is also in a file). + +The signature format isn't particularly standard: take the IEEE 1363 +signature format, encoded into base64 with a trailing newline. +*/ + +#include <iostream> +#include <iomanip> +#include <fstream> +#include <cstdlib> +#include <string> +#include <memory> + +#include <botan/botan.h> +#include <botan/pubkey.h> +#include <botan/dsa.h> +using namespace Botan; + +namespace { + +SecureVector<byte> b64_decode(const std::string& in) + { + Pipe pipe(new Base64_Decoder); + pipe.process_msg(in); + return pipe.read_all(); + } + +} + +int main(int argc, char* argv[]) + { + if(argc != 4) + { + std::cout << "Usage: " << argv[0] + << " keyfile messagefile sigfile" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + std::ifstream message(argv[2], std::ios::binary); + if(!message) + { + std::cout << "Couldn't read the message file." << std::endl; + return 1; + } + + std::ifstream sigfile(argv[3]); + if(!sigfile) + { + std::cout << "Couldn't read the signature file." << std::endl; + return 1; + } + + try { + std::string sigstr; + getline(sigfile, sigstr); + + std::auto_ptr<X509_PublicKey> key(X509::load_key(argv[1])); + DSA_PublicKey* dsakey = dynamic_cast<DSA_PublicKey*>(key.get()); + if(!dsakey) + { + std::cout << "The loaded key is not a DSA key!\n"; + return 1; + } + + SecureVector<byte> sig = b64_decode(sigstr); + + PK_Verifier ver(*dsakey, "EMSA1(SHA-1)"); + + DataSource_Stream in(message); + byte buf[4096] = { 0 }; + while(u32bit got = in.read(buf, sizeof(buf))) + ver.update(buf, got); + + bool ok = ver.check_signature(sig); + + if(ok) + std::cout << "Signature verified\n"; + else + std::cout << "Signature did NOT verify\n"; + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + return 1; + } + return 0; + } diff --git a/examples/eax_test.cpp b/examples/eax_test.cpp new file mode 100644 index 000000000..32311800d --- /dev/null +++ b/examples/eax_test.cpp @@ -0,0 +1,251 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <fstream> +#include <iostream> +#include <sstream> +#include <boost/regex.hpp> + +#include <botan/botan.h> +#include <botan/eax.h> + +using namespace Botan; + +namespace { + +unsigned from_string(const std::string& s) + { + std::istringstream stream(s); + unsigned n; + stream >> n; + return n; + } + +std::string seq(unsigned n) + { + std::string s; + + for(unsigned i = 0; i != n; ++i) + { + unsigned char b = (i & 0xFF); + + const char bin2hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + s += bin2hex[(b >> 4)]; + s += bin2hex[(b & 0x0f)]; + } + + return s; + } + +void eax_test(const std::string& algo, + const std::string& key_str, + const std::string& nonce_str, + const std::string& header_str, + const std::string& tag_str, + const std::string& plaintext_str, + const std::string& ciphertext) + { + /* + printf("EAX(algo=%s key=%s nonce=%s header=%s tag=%s pt=%s ct=%s)\n", + algo.c_str(), key_str.c_str(), nonce_str.c_str(), header_str.c_str(), tag_str.c_str(), + plaintext_str.c_str(), ciphertext.c_str()); + */ + + SymmetricKey key(key_str); + InitializationVector iv(nonce_str); + + EAX_Encryption* enc; + + Pipe pipe(new Hex_Decoder, + enc = new EAX_Encryption(get_block_cipher(algo)), + new Hex_Encoder); + + enc->set_key(key); + enc->set_iv(iv); + + OctetString header(header_str); + + enc->set_header(header.begin(), header.length()); + + pipe.start_msg(); + pipe.write(plaintext_str); + pipe.end_msg(); + + std::string out = pipe.read_all_as_string(); + + if(out != ciphertext + tag_str) + { + printf("BAD enc %s '%s' != '%s%s'\n", algo.c_str(), + out.c_str(), ciphertext.c_str(), tag_str.c_str()); + } + else + printf("OK enc %s\n", algo.c_str()); + + try + { + EAX_Decryption* dec; + Pipe pipe2(new Hex_Decoder, + dec = new EAX_Decryption(get_block_cipher(algo)), + new Hex_Encoder); + + dec->set_key(key); + dec->set_iv(iv); + + dec->set_header(header.begin(), header.length()); + + pipe2.start_msg(); + pipe2.write(ciphertext); + pipe2.write(tag_str); + pipe2.end_msg(); + + std::string out2 = pipe2.read_all_as_string(); + + if(out2 != plaintext_str) + { + printf("BAD decrypt %s '%s'\n", algo.c_str(), out2.c_str()); + } + else + printf("OK decrypt %s\n", algo.c_str()); + } + catch(std::exception& e) + { + printf("%s\n", e.what()); + } + + } + +std::pair<std::string, int> translate_algo(const std::string& in) + { + if(in == "aes (16 byte key)") + return std::make_pair("AES-128", 16); + + if(in == "blowfish (8 byte key)") + return std::make_pair("Blowfish", 8); + + if(in == "rc2 (8 byte key)") + return std::make_pair("RC2", 8); + + if(in == "rc5 (8 byte key)") + return std::make_pair("RC5", 8); + + if(in == "rc6 (16 byte key)") + return std::make_pair("RC6", 16); + + if(in == "safer-sk128 (16 byte key)") + return std::make_pair("SAFER-SK(10)", 16); + + if(in == "twofish (16 byte key)") + return std::make_pair("Twofish", 16); + + if(in == "des (8 byte key)") + return std::make_pair("DES", 8); + + if(in == "3des (24 byte key)") + return std::make_pair("TripleDES", 24); + + // These 3 are disabled due to differences in base algorithm. + +#if 0 + // XTEA: LTC uses little endian, Botan (and Crypto++) use big-endian + // I swapped to LE in XTEA and the vectors did match + if(in == "xtea (16 byte key)") + return std::make_pair("XTEA", 16); + + // Skipjack: LTC uses big-endian, Botan (and Crypto++) use + // little-endian I am not sure if that was the full difference + // though, was unable to replicate LTC's EAX vectors with Skipjack + if(in == "skipjack (10 byte key)") + return std::make_pair("Skipjack", 10); + + // Noekeon: unknown cause, though LTC's lone test vector does not + // match Botan + + if(in == "noekeon (16 byte key)") + return std::make_pair("Noekeon", 16); + +#endif + + return std::make_pair("", 0); + } + +std::string rep(const std::string& s_in, unsigned n) + { + std::string s_out; + + for(unsigned i = 0; i != n; ++i) + s_out += s_in[i % s_in.size()]; + + return s_out; + } + +void run_tests(std::istream& in) + { + std::string algo; + std::string key; + + while(in.good()) + { + std::string line; + + std::getline(in, line); + + if(line == "") + continue; + + if(line.size() > 5 && line.substr(0, 4) == "EAX-") + { + std::pair<std::string, int> name_and_keylen = + translate_algo(line.substr(4)); + + algo = name_and_keylen.first; + key = seq(name_and_keylen.second); + } + else if(algo != "") + { + boost::regex vec_regex("^([ 0-9]{3}): (.*), (.*)$"); + + boost::smatch what; + + if(boost::regex_match(line, what, vec_regex, boost::match_extra)) + { + unsigned n = from_string(what[1]); + std::string ciphertext = what[2]; + std::string tag = what[3]; + + std::string plaintext = seq(n); + std::string header = seq(n); + std::string nonce = seq(n); + + eax_test(algo, key, nonce, header, tag, + plaintext, ciphertext); + + key = rep(tag, key.size()); // repeat as needed + } + } + } + + + } + +} + +int main() + { + std::ifstream in("eax_tv.txt"); + + Botan::LibraryInitializer init; + + if(!in) + { + std::cerr << "Couldn't read input file\n"; + return 1; + } + + run_tests(in); + + } diff --git a/examples/eax_tv.txt b/examples/eax_tv.txt new file mode 100644 index 000000000..95cd7c1ab --- /dev/null +++ b/examples/eax_tv.txt @@ -0,0 +1,461 @@ +EAX Test Vectors. Uses the 00010203...NN-1 pattern for header/nonce/plaintext/key. The outputs +are of the form ciphertext,tag for a given NN. The key for step N>1 is the tag of the previous +step repeated sufficiently. + +EAX-aes (16 byte key) + 0: , 9AD07E7DBFF301F505DE596B9615DFFF + 1: 47, 57C4AC75A42D05260AFA093ACD4499ED + 2: C4E2, 26C5AB00325306772E6F6E4C8093F3D2 + 3: 16177B, 852260F91F27898D4FC176E311F6E1D1 + 4: F09F68BE, 700766CA231643B5D60C3B91B1B700C1 + 5: 8472705EDF, AC4C3359326EEA4CF71FC03E0E0292F2 + 6: 14C25EB5FD0D, 8DBD749CA79CCF11C1B370F8C975858C + 7: F6A37F60670A85, AFBD1D5921557187504ADE61014C9622 + 8: 1AACFEAE8FBAD833, 82F477325D6F76BB81940AE25F9801C2 + 9: 069414324EC293697C, B980E21C09CA129B69E9032D980A9DC5 + 10: D8174DE9A2FC92B7DA9C, 1E42CC58BA2C8BFD83806444EA29DB61 + 11: 2C087DEA30F8B7EE510990, 83DB400A080C4D43CAA6EC3F1085A923 + 12: F36B93C272A703D3422C6A11, 1370C3AF2F3392916364BBBCC2C62EC1 + 13: A0F33477BAE2E28E6747AA3193, B626DC719528CAC65DB0EF94E35422CE + 14: FCF5193506052E8BFA095C1A5205, F5BD02E0B3C91CC7D6FAAA8A9A76CE6A + 15: 3797D7F8599B8EEAB39C56241880DC, 0B70003E77146B903F06EF294FECD517 + 16: C4BAD0E0356FFD369110C048D45D81BE, DE7C2B1D83BE2CC8EA402ABE1038BB79 + 17: AF5C358BD31CDCAC2F0EA5252F1C3BE1E4, 2D700986F93B22DFE6695C2A243B4E42 + 18: 7DEF9056FBDAF491D7206B26B19DEF617AA1, E71A7D00BE972D85C77931D7591B2151 + 19: 6E9B2C0A90BF9D38A6EA3B5D2B9B2D97F938EB, 5B483D7F15C39602C2918181E57DA341 + 20: 7C5F68DEE9BBA3B04F11D5FC7C9C7FE6E8B5025C, 0AE6A12D37A9C10BB1A494E16705DC05 + 21: AF0A886BF673BC72045FC074F06A0176C96105E2E6, 06B2DC9A2868C23F86D710E01E37E07B + 22: 5F228A986DFE4301EDBAF07A02E114F1B30932995CD1, 74EBF68627C78B1FD024A59B56B2A8FA + 23: 911322F60555118CBECD8DD82F186AC19514316E8D48BA, B6A8BAF2F175CD0C71B63B1EF37E185E + 24: E7F52730CFB808EFDB376A5D5DF31A7EF8292DC5FC37E9BC, BA2AD158A2D2E5CE01296402B592E1DB + 25: B3F8D7CA47D8D86E94D670AFBAFA3B8D9E186C97DC029D4705, 709D2D2B9975D4729C19D4EAC430E65E + 26: 7178FEC027AFADDC2C03518E75CF34D207CAC2EB1537A0DBA520, A315F034CE5E66601444402520F55DE2 + 27: FC230B2B8522F53459D0B968421469BBA7E683ACB0190393B2870F, 48679A78E470E175CF3D3E9B46CEDFCE + 28: 35A641127C78C721ECDC50866C21637FDC9515E41CE60F09015EA713, 0062987222F6412B7AAF8A9ABF6FBF98 + 29: 3D42D6C113421743C08A6F682CFA0E517D5531BB66241C02EC4DCC26F7, B1AAFE11FA2D6E0C870177DDD7F98FF0 + 30: DAD065B4669B7C59C8392D8E7BD7E64BC01CEFFF27E335B25A328D356F0E, 8973B9B9ECF26DAB58CCF0787EE928E5 + 31: EBE626F9E241FD233D9781C359430C982667AA26921B62E98FAEC502C01B0B, 2AC0D7052A2CDCCE8E26FEA7595198AA + 32: 64D842B66796A797C2B4C6905742FDF2148FFC445E192F9E03B53810C082F788, 9778B345EC12D222DCC6DBABD2651750 + +EAX-blowfish (8 byte key) + 0: , D8C4C23A6AC0B7B7 + 1: 2A, 5E0E4BDDB60772FB + 2: 7695, 7581B16CCC9C45F1 + 3: EB14C8, 6223A121CFA216C7 + 4: 5A5C809C, 4A47658796337D6A + 5: 8BC2041181, E1FBA8DBA00571FC + 6: 89C666F015FA, 2B4A76A0E699FCFE + 7: 86C1FA92484AF6, 31B3B738A261D6F5 + 8: D1F401C145C9328B, 4C4A045EB489F59C + 9: 70C9C7753698324A73, AB298B5B20567EB4 + 10: A50D9D88DC101B6DC8D2, 529DFCBFD13B8E6C + 11: 7CC2885C2BE79C44F28FF2, 566255022B40C81C + 12: 6902D58347C29250EE07981C, 34619AF18E14C690 + 13: AB6C3C4AD3EC45143392B642DA, E6D2DD323DA175BB + 14: 7065B28BA8AB67B2FB7B6D5E3FAF, AEDCAA54F4B0772F + 15: CBBA14A74AD4ADC0EF036EDAE42D51, F2BFFA4D81BAC034 + 16: 60A315193F58144F5701D547C79FEEED, 912FDBDB05467DF5 + +EAX-xtea (16 byte key) + 0: , 86881D824E3BC561 + 1: EE, 4C3505F04611D9C2 + 2: 80C8, 6A3428BEEAD60738 + 3: BF88E7, 04F1E99E9F5906C2 + 4: E06574B7, 33B0153AAEF9776F + 5: 42D950AF63, 4A0F415640322FDF + 6: C30F6AD46EC9, 9646FE909D2B95CB + 7: A0049FCA856A14, A0257289C6BBF278 + 8: 2814B0C1358440E0, C4B0A2354925E887 + 9: BF4F062B52C1E489CF, B56442A3CA57A041 + 10: 63DF433956831B8780FC, ADF9ED0B46DCA19E + 11: C317FD079817F50E0E8A16, 2EA0EC993FC603AE + 12: 2BD12FDDD81EB11660346D2A, FBC6F69125BBA88D + 13: 85D356536FE2843C6BBE60EDBC, BB2FEFD04F230E79 + 14: 22493009DB01B4746F4927A8C4FB, 64CC08471D93C9AC + 15: C0F3C0DB08DC93FBA725D1E02DE084, 77B762213DDCCFFE + 16: 568B66D3112556BD98FF9339E9C002E5, C8355F508219FE0C + +EAX-rc5 (8 byte key) + 0: , 169C7954341EF44D + 1: 22, DABFDA9A0B0BA067 + 2: 2E54, 6A3D6D9AA5877C5A + 3: 2A6ECF, 2A34A3AF5DE8919E + 4: 9CC5F84F, D3F673EDAF75E3B5 + 5: FF5611756C, CC647FAAC8D49BF1 + 6: 74C939BEB31C, C335999CCFE8F5FA + 7: 7976B6F7709B5F, 2A7969C5FD063A88 + 8: 421EEC5022276174, 2C9BFB1EAC3C54A2 + 9: 6A4761CD266B1C0ECB, 3EA3CCEBC85FAC4E + 10: 7C09201098E764239A2E, 8043ABA9BF4D5AEE + 11: 8CE26277562F646DE33C88, D72AED48895E3B40 + 12: 52150F44D37D121560DA87F6, 58E865E22B485906 + 13: BA0A73B45F93ECFBFC3AB3D8D0, 683D52FA47FB1A52 + 14: 96546CBE01054AD24CC95DB54724, D80D0D530E5D1DDE + 15: 61E654BB18CD26FC36C09F874DC2C7, C65884CB9D9FEC1E + 16: 1D77B8BF02CDEAB4A707C07628826D5B, F18D1730C3D64701 + +EAX-rc6 (16 byte key) + 0: , 1DF8B0B92A3F0C951C425AF4830E63FD + 1: 1A, 8A2959EBBE90180999994DEB7036DB85 + 2: 435D, 7EF00CB57DB7B4155DB530D75CE6B025 + 3: 08A6CF, 2ED6AF0F2D5BAB05F623D389480A01F2 + 4: A86E54D3, FC69547C8BD922A5BF2F7B26C4D20F98 + 5: ED0822E439, 0007A3C6DEFC6C912C0E5B853B520368 + 6: 7BEFC7FD4054, D32C43A4D1086D57C5BCFAEE04EBC600 + 7: 5235E58E79287C, A27E9C781327C0FC7C55410EB0C828A9 + 8: CEB5EE99BE521F4D, 547F46383987F2A3582A81A3BCF9B280 + 9: 0358B063D5F99C3770, C0A73730512CDA6AD49599775D59EDA1 + 10: 434B9AEE07DFADD0A332, 499BD88881E558E09A8E822BE27D2496 + 11: D47849E650F350BB622D74, 638E37A84E7FAAF8F5D77F1B061773DC + 12: 814592F568284085E79A024B, 9EB1405E8422FE50BC0D88D837A2C650 + 13: 6F2B55EC91B591082053AF692E, C48F91EF01AA43A1EE3B36D233DDD48B + 14: 506CBDD2901838EE2F178B6953DA, 03778957F536509BFCA577B23A18F726 + 15: 446EE435D3D1848B51BB8C5F7BE4A1, 1129EAEAADE534940546D43242A4C839 + 16: FB9D2B150C42465B1685D8F069CC06DB, 41E2940F5DC63CB4E2FBEC25ED8A31E6 + 17: 9684F683260107BE8FEBBEE1D3EEDAA7BD, BAE7C116F7FF96631F4ACEE95C65CEF3 + 18: 5082B1FE48CD3AB58F63C2DCFDD4069AC736, 19AC7B8EE315CBB7131A283851B32266 + 19: 8C72AE495B6F003A3C784D144E84E88885F78E, FA4CEC023740A8D670E351FBCF62C1CB + 20: 815D6361C7AE34C9D796ADF9C71ABC46AEF88BC9, 9A1F7288C61A6623B9A82748137ED7CC + 21: 904A853E2E96BD2B85AAB3F5DFB900E9B3642EE667, 9AA90DBDD461CAD20495DCFBCB513DD2 + 22: 79D738A462F727B3D3C529ED999B6FDCCD991D1C5A4D, BF0987BEDDE650D73CAE7D380FED3431 + 23: B2DEFDB7D503A84E83155A04B8DE8C8DBB68C2FC475007, B7CE900CF43CD518024123C76F6DA328 + 24: 9E723E15439E12F6C46DF8A309AE1E97B6FD18436259CFB0, DF8B6E1E23512CC4CF5FF531A1908F69 + 25: A7F0AD03CEBCC9202718AA164886E1026975306A664C5AC7A9, 4A771BF8B9A4325705C85E5499FD98E9 + 26: A53A92AD1C6835F28E04EF591E783D36F3D76E489B31B87BEB7A, AA263B52A6E6A043DE4D7029D4DC73F5 + 27: 79BE3C38291A7F77E932C8A9DEAC08DE6442EA9B3895B101A14E7B, 33B84DE06342E675E019CD0237292ED0 + 28: FA108123C5A69571CFDFE8C3D00535121FDE3096DDC0D700F8F26A5A, 764025D7CA1A3F2C54D28956423B0C77 + 29: 36EC2D67FD977BD2B73DB6D8EB756B3EADA13690E1B6DFC12A4781B34B, 4BC6B38DE3B02283D92F4DF19A5C48C5 + 30: 96D3243C945905C9732B5927E46F00886D511463B38C86002FC26B65AB8C, 5B5511CDEC35687AB8425AB22D58B4F1 + 31: 9CF83B87BEA3374AF7722E999863E3DABB858B0383383EAC7757F5B80FD44B, 1E0CBC961940FDA93B73A92DACFD67F3 + 32: CE3BC3C9FA5EF4AFE5272B3EDD24B1B003FED2C2E501528CFF44D3FABFF52CB4, DC94FDDC78AAB2B7CAA1E1EF149AC355 + +EAX-safer+ (16 byte key) + 0: , B120C7B37450C46189712E4DFD1F0C44 + 1: CA, 82BA1869C5FF1EF2A4F6ADC1E7DC1F1D + 2: DD20, 6BD5601B16C9943A84AC1F99A176E6D1 + 3: C1C09F, 0911DC63AA414C004E2BD825BECDC93B + 4: 27E43F59, BD858F084B082F76814DC385E1FB20D1 + 5: 2A9A92F246, 5ADC4A32491934AC0BD00FCE686B26F1 + 6: 52C78C0CD6F4, F35886F46C03EDCA10B3D01CF07B1E0A + 7: 23E0D3CED3795F, FE33D96FC98B78A30C0A412C60E93992 + 8: CD3FC9961559F239, 9982364A61609FC41068260267231EE9 + 9: 6EA46CB7AD7505C1BC, BB15053EF0F78B9091B3064118F3E9BF + 10: 05D9BA230A56CCA0703A, 1338E68E3DC992B6EB2685C668E75869 + 11: 7AAD6049DFDCA6771AE42B, 35267E431051E1812495615324C4CBE6 + 12: 8695091532B83B23C296F620, 7B2EEA861E9A91E6B6A911E10FC3FDD1 + 13: D909DA4BC7372ACAEA78E6A0EE, EA6C1CD16180DF0B07F4E204A4B4FACB + 14: 7DEC8443600D0563AEFE87A2064F, DA454728069B3B409889664783588189 + 15: C042FE656742CD2FE5D9C212D18C6C, 5929E4AECC2CA047BAE948E7023FE4D0 + 16: 0B84D3CF59EEF7319633F4A397D47CF8, 31F892FFDB7535DF5D9143456E404163 + 17: 8C9E57AAFA7969B142742B63AB73286600, C418231C44F96660DDBA8C26B3BB3681 + 18: E9EED66D370A3A6A39C7E0E570D96F807EAC, A4AFE8D1D3C31B956A3BDBD043E7A665 + 19: 1A5D47992DA5597D1449B4C8DD47B7404C7657, F3ECEE5182014FC3365FDBC4C33CC06A + 20: E7C7945FD1AFD3F5DCE666D8A5A2E8A3C11A7A5F, 86D78B2FBA7597B8806BED505B52BDF6 + 21: 9E2165B47B29CBC4ACD50660E011D691F061209969, E9B1E860BD02085177E1A94E1EE6F3F0 + 22: 48EA2945C8DD3FE09407BAC8973A861DB15B788C8FFD, 502926712EDB1B3DD13806052C6C75D7 + 23: F37D46B35B60819EA52B00457D79155C04B55972D0DFA9, BB2B7D210BF0570F422640BF81F39B9E + 24: 12E85C0C78227205CC682360C79E35BF58EC6551CF8FE2D0, 042990D7A58D458C570A15DD375DB4E7 + 25: 4F6C15109DE980DD14A7F4C27F48671E4787C53A564232F427, B097A5990D8067DD89C21473150C070F + 26: AAC472E49DB101B564A8A01E2C80C0C6AE9065D332C2DE79FAB6, ACDD587A7DB86542E195DF73AF1C1CBC + 27: B9912CE18019C31692A1F7E11D9CCB20297ACCB9DC62C47C01D2C2, B0ACBF028CA5B15E0035D2EB8CA916BE + 28: B4F2B1FE14A1ECDC9C8EA1A0120395E6ED1E69D3FC85DD0F3F90F350, 9A561EBC769369B95B9CB74FC6AC27D3 + 29: 3FE397C8AD02689B7437A37861F0907AF1F6014A293B46419348771C5A, 6B7BEB9BD5018FECD71BE5081C7C2544 + 30: 5019089142199F7207E1B7731B8B247A18A685B231499DF12A73F5D67D37, 307E93446777005BA1B088F178A0DB6E + 31: EAE8F9F02F8DB3D70B78B08CFB0949D99F1A86C958A8E3823736BCEAB86BE1, 6C94F48591C18BF9C450515B73379973 + 32: B9C795F7A87305B4AD36DBA10B3B1C70B329D29E49C8C6A932D96A74334AEE4A, D18E6E233FEFD6E5C7148BDC1504299C + +EAX-twofish (16 byte key) + 0: , DB0C02CB069E3773296D3BD4A87A381B + 1: 99, 7D21D19E9C440F68E99F1F2EA2668694 + 2: 0696, EA590EC417C88E23FD23917F9ECFB0C6 + 3: B9B082, 82D4C9B68DDB02C906496413E13A2D68 + 4: D6B29D74, 5BCE5CA4F662E883BF7FCAAE5FB2CE01 + 5: A59C9CB009, CBFB04226D1029A7EC9D64A48A6729BE + 6: F4924FE3E355, 3D85B3900DECA0528C815F1447A1F209 + 7: 679C88D52FB519, 931C7A863C3701D8015FDBD8696C6C30 + 8: 26DA41C0D115375E, 7627E23E791A4DCB0FA5ED71B1ED2288 + 9: 8FEC6EB7016AD2B178, F65ED0286A724F0CB2EA317D5022B0D8 + 10: B5F22415B1334133C531, 87C4F3A8991BBB85984BC4D3305A5CF1 + 11: 23E1D0ED2E820AFE7DA2FE, 100499F1093FAB2ECF73B643594E98E3 + 12: 79519ABA91F46B8DAD6D5335, FBDCD1FCDB20AB99135F28A714C6992F + 13: 5968D0B4198A0AAD3D0395018F, 781F22E2DA98F83398FCF911B2010057 + 14: 4E55B14432B601E3EF2EF567CB15, 8BF6E53D7657E56EA3DA1BFD9C9EC06E + 15: 6ED89651CE19B3DD1EE5C8780B5015, 131CFD657D32D4E1B35140ADDCA0E13A + 16: 2295A968B4D072D12757756247554850, F35FAC95C2AA4155450EAAA6E2E789B5 + 17: F9B2AA2AA502EA79BBA0C5EAD932B8E1EE, 0ED81AA40B9BF39A9AAEDDDB7A04BEA6 + 18: 385055F1C1C26C0472A504B4CD225DCA55FE, 24831680B56368231AC54227D737F582 + 19: 771529585C741A3F8B1C973709892F255A99EE, 2A132B4BF96FD5109DB04459103F5E84 + 20: E7A2197D9FAA8AB8B303B5EC71AE34AD5EC5DD66, CCAB6518371EC8E0A9E9EE4F7CA5878B + 21: 279E54F755EAC6B57375B9EC4406E43DB3139D740C, 7B6F26F2C0ECC9F2DF4EDD7513E6E0B7 + 22: 27816AA94CBA2BF98E49E595AF5B3FAD12BF1D6F1AC6, D04876C5492D275F15C834E3CF794F0E + 23: B5658DC148855F68B282211D879F688F3C142FE555CF81, 4539CDA8A65DB9047AAD76B421B81120 + 24: 72F0BD4F939C2C9B4FA734DCB0AE4FB9BD342BC8459ED2FE, CEA8469BC0457EBF3418C1114288C904 + 25: 70568245E6E6BD5D11AD0C74030D7AE08BA05057DEA0FBF4AD, 71554FDE6B87477A51EE4499D78783D2 + 26: 8702D35BE07D7ADF70684046CC6C72FBBBF821E0BBCCBC973601, 33CC6FBFDA15E306919E0C3BB2E22BB6 + 27: 0BA23F4A6174165D4A8BA80B7C875340B0F8B2A6967D34E106BC22, 00E6679496714236EECEC84B9AF3072E + 28: B9E25ABA84C6BD95B5149E7616FE2E1D6FAACEAAD77A636C60279176, 8D8AD0B9D4C709E1DA370EE01611482A + 29: 74759711F6D542581F9F83498FB616638D092732BA07109BF4B5BE045C, 71A40DC777BD09F75362F7B20E0B7576 + 30: ADBF7E98926484BA2C7F6CD7CD9734FC19265F68AF3BFCAEB025F6296E37, 8DF15B5F69B67F7DABE44E3666B55047 + 31: 2DC26D449379997D110309B2A0DC2760FCE8CADB4B14ED580F86C70F69C9BA, EFCB60EB2B25737E256BC76700B198EF + 32: 2B1890EB9FC0B8293E45D42D2126F4072754AA54E220C853C5F20FBA86BE0795, 1A1B15BBC287372FB9AF035FB124B6A1 + +EAX-safer-k64 (8 byte key) + 0: , 9065118C8F6F7842 + 1: A1, 1926B3F5112C33BA + 2: 2E9A, 5FA6078A0AA7B7C8 + 3: 56FCE2, 984E385F9441FEC8 + 4: C33ACE8A, 24AC1CBBCCD0D00A + 5: 24307E196B, DD2D52EFCA571B68 + 6: 31471EAA5155, EB41C2B36FAAA774 + 7: 03D397F6CFFF62, 7DFBC8485C8B169B + 8: 8FA39E282C21B5B2, 2C7EC769966B36D7 + 9: FEA5402D9A8BE34946, A058E165B5FFB556 + 10: 6CDEF76554CA845193F0, FED516001FFE039A + 11: DC50D19E98463543D94820, 8F9CCF32394498A1 + 12: 42D8DC34F1974FB4EB2535D7, 77F648526BCBB5AF + 13: B75F1299EF6211A6318F6A8EAA, C5086AEA1BE7640B + 14: 1E28D68373330829DD1FFC5D083E, 33EDA06A7B5929A2 + 15: 85529CF87C4706751B0D47CC89CEA6, D031905D6141CBED + 16: FE5CB61BAF93B30ED3C296EE85F51864, CC484888F0ABD922 + +EAX-safer-sk64 (8 byte key) + 0: , 5254AB3079CDCB78 + 1: 75, 798DCF14FEF8F4D1 + 2: 0300, D5FCA75DAC97849C + 3: 520F98, 10E357957CE20898 + 4: 80E2764D, 5C7F46656C6A46EA + 5: C48960CDAA, 3CCF44BD41F01CA8 + 6: E0E60BD9AA2C, EBB493983FCEE79D + 7: D13D8804906A1B, 6EDDCA919978F0B6 + 8: B7AE14C37A343BFB, 2369E38A9B686747 + 9: 5DE326BBCC7D0D35E9, 041E5EE8568E941C + 10: 13494F5B0635BA3D6E53, EAEEA8AFA55141DD + 11: A9BB35B14C831FDA0D83F7, 4002A696F1363987 + 12: E242043A1C355409819FABFC, 63A085B8886C5FDC + 13: 204598B889272C6FE694BDBB4D, 194A1530138EFECE + 14: EE3F39E0823A82615679C664DEBF, 1EFF8134C8BEFB3A + 15: 8579D87FD3B5E2780BC229665F1D1B, A832CD3E1C1C2289 + 16: 74D7290D72DA67C4A9EAD434AE3A0A85, 96BAA615A5253CB5 + +EAX-safer-k128 (16 byte key) + 0: , 7E32E3F943777EE7 + 1: D1, BA00336F561731A7 + 2: F6D7, 8E3862846CD1F482 + 3: 5323B5, BD1B8C27B061969B + 4: A3EC3416, 170BBB9CE17D1D62 + 5: 0C74D66716, 7BD024B890C5CE01 + 6: 6158A630EB37, B5C5BD0652ACB712 + 7: 17F2D0E019947D, F9FF81E2638EC21C + 8: 68E135CC154509C8, AA9EAEF8426886AA + 9: EDB1ABE0B486749C21, 355C99E4651C0400 + 10: DB0C30E9367A72E8F5B2, 631B5671B8A1DB9A + 11: D4E5453D9A4C9DB5170FCE, 75A2DF0042E14D82 + 12: 3F429CC9A550CBDA44107AA7, 2C2977EA13FEBD45 + 13: A7CA22A97C2361171B415E7083, BFE81185F31727A8 + 14: 170F79D8B0E3F77299C44208C5B1, D5ED9F9459DF9C22 + 15: 2E24312D2AE5D5F09D5410900A4BBA, 2FC865CA96EA5A7E + 16: 8F3C49A316BA27067FF2C6D99EC8C846, 9D840F40CDB62E4B + +EAX-safer-sk128 (16 byte key) + 0: , 22D90A75BBA5F298 + 1: 3F, 98C31AB2DE61DE82 + 2: 584D, F4701D4A1A09928C + 3: B9DEAD, 6E221A98505153DA + 4: 06D4A6EB, 0E57C51B96BA13B6 + 5: 7B58B441CA, E28CCF271F5D0A29 + 6: 7950E0D1EC24, 2ACDDE6E38180C07 + 7: 65A4F4E098D7C6, 7DC1C9E9602BACF2 + 8: FEBE4E72BAA0848F, C4607EA3F138BAD9 + 9: 9B7BD6D6D655985AA3, 8B2C58A9530EA6AC + 10: 60C92F925D1478470203, 51E6F5F6DC996F84 + 11: 7B40769370E651F64AA654, 74F1F8A8D3F4B9AF + 12: 7215832C2FB9C54DF7A9C686, 9BF9AEF14F9151D1 + 13: AD0F9C79008572AB8AE2466EFF, F375D0583D921B69 + 14: C05076E2C330A0D25D7CEC80597F, 843C12F84B00A8E0 + 15: D18F0563AB0278140B0CD9A9B07B34, 262B1688E16A171E + 16: 650747091F5C532EE37D2D78EE1EC605, 1BAC36144F9A0E8D + +EAX-rc2 (8 byte key) + 0: , D6CC8632EEE0F46B + 1: 4C, EA19572CB8970CB4 + 2: 5537, 3EDD3253F6D0C1A8 + 3: 206FA6, 20FA88F03F240D31 + 4: 17EE8B40, 702E8194F1FCBFDE + 5: 2A89287136, 31C5534786E15FB3 + 6: 3A6AEDC7066B, 3C663A4081E1D243 + 7: 8BC5203947A644, 6AAC806C92BFBD6E + 8: 2E0274BBE14D21A3, CEB0E0CB73C3664C + 9: 9C4B292B0CF17E3A29, F23CD535559023EC + 10: 8E322734308F85662877, 46363D7EFC322821 + 11: C413C405767FF5F98E3667, E7BA35D8F3678E7E + 12: D77806B7A218098B1569EADC, BA67C306E5C0181B + 13: 4BE5EF74F9E9799A4D636FEA9F, 4C511C44ADBA4030 + 14: 7E19969170C2C8D8AEBA8C7FBC2C, 54CC6D466A2DF6DA + 15: 2EF1CEDC1DD3403CF440FC5561BE33, 61C6FB277E93701F + 16: DE052719153EBACE9D7B19F52AC4282F, 4AC2A96F2FA8634C + +EAX-des (8 byte key) + 0: , 44048B7F240B6F5F + 1: 0A, 37009B7D4E09953A + 2: 03BA, BFD2FD7758961728 + 3: 37EE10, 16A6AF96DE888A19 + 4: 07F44290, 100CA84AA0EDAA1D + 5: 389EF0023B, 9614FB800A533268 + 6: 3F4DBA8AA01C, EFA6B55B7ED5E40F + 7: 8C7B837896EAE7, C113CE8F664CE3D4 + 8: 7011D993D8EDB0C7, B4C370A919F60497 + 9: 0DEB30A31351B13D7B, 00ABC82DC5F3A1AF + 10: 8D3897B2CBE323D6EE1C, 7A2D15627CA1441B + 11: DBC002C817DEBFB419F94B, D8EB87F86D6ACDEF + 12: 17048E2976FA85AA849E9A80, 229FCD1C9D1E3B9C + 13: 30B989EF646544885A478AC198, C1B7EB4F799105C8 + 14: 5C2E12A7F118A08D6FD585F9C839, C358679FEE6FE7D7 + 15: 8D1A1E888BBB8648E638C4E74E11B8, 685E006C441448B8 + 16: 93AE906B8BE4EAC8ED6D8F48F04A7AFF, 71DD7AF752FE28FB + +EAX-3des (24 byte key) + 0: , 8914311BB990B725 + 1: D8, 2094EDC5D03E54B1 + 2: FEE5, 781CFB0EBE3895CA + 3: DECF5E, 59918E8A5C4B459B + 4: BD583AAD, 2013BEEBEEA795A1 + 5: 2BC01C6C78, 0B1134DBBEAB5D3F + 6: 4D5EAF01A895, AB4D17516ECBA50A + 7: AF229F90614480, D3113C0A9D133CD4 + 8: BCA6F375DF4568E0, 8E9EAEC8E77786BC + 9: 575F34219E6DD8DB4C, B40C75139E5D1860 + 10: A199B8AC433B615EC96F, 774AF803698ADE3D + 11: 718A2975DD9A872A68AE10, 3B9460F849CBA7FB + 12: AB38E148180F6E2FFBB96F91, E3EE3B8FC50DADBC + 13: EB10E0233507459D4A6C29EE80, 8D90B46BB1EAB27E + 14: EB48559C320DFB056C37458E19B5, 9315F0C4AF8500EB + 15: 9E8C73EADA105749B5D8D97392EDC3, 2E749EE66C1E6A16 + 16: 600FA4149AF252C87B828C780AEFF8BC, 33D7D11DCDC19936 + +EAX-cast5 (8 byte key) + 0: , 382FB8F7E9F69FDC + 1: 99, 20DA959849B3F7AB + 2: C54B, D05547C6AFA3484A + 3: 579836, AAA92B2321FC50C5 + 4: FEB7AE55, 639EDF01C4FB965D + 5: EA8A6023FA, 01274B3ED5CE102C + 6: B7C4E995121F, 712BFE27CAFF6DDE + 7: F44236660B0004, FAC51D1DF8EC7093 + 8: 01CD7E3D0BF29E8A, 049C47A45D868D0B + 9: DAB170493DFD6E0365, 6F3AEDD9A3ECF4FD + 10: 82C9EEC4803D9CD11FA8, 32683C0A9128C6EA + 11: 324AC59E87B244ECE0F32F, F6B095AAB49353CF + 12: DBDDAB11D02C9CA5843C406E, EA728FC46DDD3B04 + 13: D67376C2A4AD92E7DD80E39303, CAF72B7E7C237EB3 + 14: F2B9BBEF08036C2982C6DDD06918, 70A29D780C22752C + 15: 96E3D9141F8EBF520540C2BC9A9C23, CEFC86A1CD48203D + 16: 70CABBA983179106AE7FCD5F1F31D5C3, BF7F9168F4F82F56 + +EAX-noekeon (16 byte key) + 0: , 556805EEA595CFB9A30FAD196103D7FD + 1: F5, 0A7DAEDFB656526CEF4DDBA8087A227A + 2: 7B8C, 249895D79962D5B4D18FE07366281B72 + 3: ACFF15, DCC489D24832EB106F576AE6B6EB957A + 4: 08ADE7DB, 0D3215999E9960EDAB29B78744C7F139 + 5: 66139213F6, 505E1E7141D043E903C26EE0959EEECD + 6: 078B79F880A8, 35B7EB326A55E50332866EEDB682EC20 + 7: 2809E34D9667D4, FFDEC555F68524A09A6ABACA372077D9 + 8: 93D267DE1EC635D3, 4FF3561990A56E4B374618722EF850FF + 9: F377A4D93FF32F4A51, 91D4070423A90FC54D305169C03F49ED + 10: 6244B717E082993EB7A1, 2E3A8A354AFA9473667ED7FDD46BE9FC + 11: E917559625D25E6E5F2EDA, 19295C37A70314CC9A1D11FDE8D23C92 + 12: 1E6DF2EE112A893AB14DFA92, 12C4A89D4CD65F8116A03A135AFD3701 + 13: 47B18CD762E011770E203CF605, 434909A97E118B20D3AEDC79AFE33A9E + 14: 72D9A1A7DA6F33D5E0B927F9F32C, 779C23714FCAA2B2321EC7FB5B03E222 + 15: DA8B830FFCB3DB274807F780D33240, EDC2F1C8A401F328A53392597730B007 + 16: B53DD2BB840AD933D36A7B5FFDCCFBBB, 4EC0E6D1F916BF633869239B672B37A1 + 17: 42936BB9A936C30408660855F4F47F3314, F0DAA6DDA15585E1697ABBB4790B15B5 + 18: 00372E47F5BA016F1B2A1E680B76AB02052A, CDBF3D241BF7FF96D3DFBEDDB872E901 + 19: 8AA236B0C8BEF6F67A97C2DF90628F6E5838FF, 731DCD61F7F26004C03519F9500EA824 + 20: 55338647812FC9D86CBDDCED7120268A4D43F8BA, 0E61B3C835CAD95FD49FEF002C014E72 + 21: 435820B28E52154B47A04D5E635D8FE37FA47FC985, F6A96DCE4917E8D7C610923627E80970 + 22: 0D30C15B6FEB4A48B14DD15D41A4B25D442AA677B25C, 28E15CCB74AE992C68BDDC8D87802050 + 23: D9D701F9AD6B0E13D2CDDA15A5194E7CE8BD2C02137391, 2DB9A15884E9C996C3D6B5BDA44B9598 + 24: E2390AC5CE10CCFBC72106A52C7F180CB477E3C193CBACA8, 22D3F7DCD6947EA4E78DF57A8E1A9A59 + 25: ADEFB7D9500658D34996AF6BE6336CD78891064EA1DB8E9785, F239D67D039A15C620A7CD4BE4796B3F + 26: 89964C90ABF54A6DF9F13C3681E70C702D80A17BE79F8160F30E, 6336F729ECE1ED7368669D75B7E2DCBA + 27: 576B2813CECDA4F905BD5D58349EF070FF41B7EB6BB2B01B061B0B, 125324CBF2ACF1011A44A99A11EC8AFC + 28: 430B957481748519A60494F0B5F698F34B1A8235B00AC0D1F0A4442E, 1E80A7FCEBBB8E1E12D6831906154485 + 29: E781BFE5FCDE0BFC056CC86C4A0B9DD3B815BE8CA678204CF47289B5B5, 190D5AAA9EC1CB4CC86FACE53BF1201B + 30: 78BFAC07A9B7B2AE9329BF9F9BF18A1A49DD9587001EFCA00E9AD9752764, 4FB5ECBEEB0995C150EBC66508FA19C1 + 31: 7D6C20694109DE21F7955855A8FF832347518DD496C2A114DF142C68ACDEAA, B25D4BB34056DC091A7A3950D46C32EC + 32: 3E1E4395DEC1AFEA9212B95F37E679B6E2D14DF23C5DE49018C2C8038CC4AD45, 9A6DE7BD41A21918AD504490EF4E581D + +EAX-skipjack (10 byte key) + 0: , 85F74B6AFFB10ACD + 1: 3F, 604DF8BDD98A0B3F + 2: EA87, 792374FE07588BF9 + 3: 0169CA, 489AB8AF69DA3306 + 4: A7AC3EB1, 428DAF508E24B583 + 5: AA9028D5B3, C0A44EDA71FB2C86 + 6: DA97BA88A061, DA2EC34077F42585 + 7: 7E25FAA41CEBC8, 36D4987551E06D5B + 8: F662DA6C9001CBFE, B7DEF76680C316A9 + 9: 6D3F73EC716E1DA897, 5F0F83BAE4D3513B + 10: 2A300F585BEE9C889743, F4756C24DEB72A9C + 11: 80518B010DD77C82D19106, 50FF5CAA365F4A70 + 12: 6E579A2173C861B6F37B4CD3, 81E3E5ABBA8F0292 + 13: 5B04829880A72C38871C7021F3, 6B26F463708A3294 + 14: 934177878E9A9A9FB4DEB3895922, EBC1C32F0A2A3E96 + 15: 07AF486D1C458AAB2DBF13C3243FAD, 87288E41A9E64089 + 16: 84059283DF9A2A8563E7AF69235F26DF, 351652A0DBCE9D6E + +EAX-anubis (16 byte key) + 0: , 8E20F19D9BA22ABA09FB86FDE6B9EF38 + 1: 3B, F4201E546A9160F989191942EC8FD1D3 + 2: 9F38, 4E3CEAE3E1CB954E021A10E814B71732 + 3: 4F4769, 3E8F35A6A5B11200E9F1AA38590066CD + 4: AB41F5FC, EC4C97A8892AAF5433106D4AC8A49843 + 5: 414F95D61B, BF831E34D1E3FECB973A8C730ECA2E6D + 6: 4798322F06D1, 005BBC30BFEDBE6463536C4F80D1A071 + 7: F256B6CD1BF4F5, 468A28F0661884B846B191B530C8D064 + 8: 90906F27A633ADDE, 6D9200A37A7F6A456CB103673184C2E5 + 9: 16CD3C17C9B4EAB135, 6D716E23D7B35109F55B036EDFA7742E + 10: 7AD1C22F1F06298DFB25, B076990F8193543C8F3185D3792BCE56 + 11: 0476F2ABCD057FE6FEE39D, BB2876DB18C00038FADBBD9B264ACC3C + 12: B69EDE336407DBC2EE735857, AB63E5906116A8BE22C52B5DA31B1839 + 13: C3864C1354065A56470669E602, C72BFD3A0BC73BFF051C9AB2F0DFED93 + 14: 296D8F183A59020D33890420DD7B, C9D90B9EB42C32EDCF6223587D1598A6 + 15: 256ED8E9D982616680559979BDF2E9, 179FE4E7BA7E966050D35900317E9916 + 16: D4ED8F30FF9C0470D75B3B16750A3AE4, 5D50F05BB270A292DFF9F67A3BA84675 + 17: 40CDEB6388274143CA3C4F6020BD9A4875, B27C7DFB1BFBB3FCCEE0171852C7924E + 18: 54EF262EC1801D505C7629D038654EBA0594, 9D2060FCD0A2C577511C7752ADE60BBE + 19: F39EE54A37F16DD38B624D7AB8F0D9CBD4B981, BC056C7D2C09D813703CDD63C1C69F44 + 20: F4E7AD474FCA153ABD670E43081ED09EB2C4CC1A, F244BD4D630272F0D98FCA04226C04F1 + 21: 039ECC36A0A16273E7246CA1FF19D213AC87B53F29, 3056DB6916C925DF220B6C9980EE141A + 22: 7DE1DCDEF01447CA2FE83375A48DD84E4A7CB7C01992, 79AFEA4816EAF8DAC8A5E93960F1594F + 23: A886C4B914BF0983003272F226F9B2197EF2DC05ACDDE0, B59D85A0FDA5FA4422F7203C055B97A9 + 24: 00B3E1E91448E250AAFB695C0643A6577AB453EFECFABF53, 4A7EFF1CBC1AB535122A017203616D85 + 25: 85E972E774D66D0531E40B8FE9E264A77B50FA883AB0943080, B18E164BF89B7E7AB0DC256DFEC7C72F + 26: 004849E39334969B392CB0CF3FDEFB3D792DCBBC15F8328C7EDC, 3C51295711F5F878DE8F0B2B5A26A227 + 27: A0BAD6C2264AB1578993BA49E59D4598822FFED20A57D88F756FF1, 2EB9D525697A419A10DB2A84AEEA5FBC + 28: C34DD806EAB5AD823D78BCA78A7709A705FC94ECC521A367D76C9588, 3C57580C7903039D645C06DBAF07B477 + 29: C447EC77512938CF7862388C32AF22ACE6B5E4CBAA998BE4F5CBC4D215, 43425D09B7ACFD90371C08953946A955 + 30: 2C16993AAE624CBA4CDAF34FE3D368559E6BE548292B281439866375013B, 3B7360C3FA8FB1C15D19F567153CB46C + 31: 538E5DFAF14854A786851E4165F2E01CDDA963E318FCE4FB58E31A6B5CFC33, 2F8EA13B7A6873FE556CA535ABA0968B + 32: 5E29CDB7D9695A110043E9C260104BDF020A3A2A139D4112E918AB584BDD7EDA, 9133213AA7BCF062D2BD37F866683D3F + +EAX-khazad (16 byte key) + 0: , 75968E54452F6781 + 1: 95, ADAF5949F09B5A22 + 2: 6B8F, A06B201947424A11 + 3: 5BE668, 3251416625DF347A + 4: 5A92E82B, 33E25772427D9786 + 5: 62F9F2ABCC, DE714F5F5D17D6D0 + 6: 0E3CD825BD8D, A7991C8CB8975ED9 + 7: 4AD0D999503AAD, 53A827D7886F7227 + 8: BB08E6FAED1DAEE8, 91A118749B7AB9F3 + 9: 16E30CB12E20D18495, F8F8B8C1280158F9 + 10: 616DBCC6346959D89E4A, 506BF35A70297D53 + 11: F86B022D4B28FDB1F0B7D3, EA42220C805FD759 + 12: 9B8A3D9CDBADD9BBCCCD2B28, BB478D3CE9A229C9 + 13: CDC4AB4EF2D5B46E87827241F0, 658EDB9497A91823 + 14: 1A113D96B21B4AEBDB13E34C381A, 63AD0C4084AC84B0 + 15: 14DA751E5AF7E01F35B3CE74EE1ACF, 3C76AB64E1724DCE + 16: A13BBC7E408D2C550634CBC64690B8FE, 3D4BBC0C76536730 + diff --git a/examples/ecdsa.cpp b/examples/ecdsa.cpp new file mode 100644 index 000000000..df1e1b93a --- /dev/null +++ b/examples/ecdsa.cpp @@ -0,0 +1,61 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/ecdsa.h> +#include <botan/pubkey.h> + +#include <memory> +#include <iostream> + +using namespace Botan; + +int main() + { + Botan::LibraryInitializer init; + + try + { + AutoSeeded_RNG rng; + + EC_Domain_Params params("1.3.132.0.8"); + + ECDSA_PrivateKey ecdsa(rng, params); + + ECDSA_PublicKey ecdsa_pub = ecdsa; + + /* + std::cout << params.get_curve().get_p() << "\n"; + std::cout << params.get_order() << "\n"; + std::cout << X509::PEM_encode(ecdsa); + std::cout << PKCS8::PEM_encode(ecdsa); + */ + + PK_Signer signer(ecdsa, "EMSA1(SHA-256)"); + + const char* message = "Hello World"; + + signer.update((const byte*)message, strlen(message)); + + SecureVector<byte> sig = signer.signature(rng); + + std::cout << sig.size() << "\n"; + + PK_Verifier verifier(ecdsa_pub, "EMSA1(SHA-256)"); + + verifier.update((const byte*)message, strlen(message)); + + bool ok = verifier.check_signature(sig); + if(ok) + std::cout << "Signature valid\n"; + else + std::cout << "Bad signature\n"; + } + catch(std::exception& e) + { + std::cout << e.what() << "\n"; + } + } diff --git a/examples/encrypt.cpp b/examples/encrypt.cpp new file mode 100644 index 000000000..28017d875 --- /dev/null +++ b/examples/encrypt.cpp @@ -0,0 +1,193 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Encrypt a file using a block cipher in CBC mode. Compresses the plaintext +with Zlib, MACs with HMAC(SHA-1). Stores the block cipher used in the file, +so you don't have to specify it when decrypting. + +What a real application would do (and what this example should do), is test for +the presence of the Zlib module, and use it only if it's available. Then add +some marker to the stream so the other side knows whether or not the plaintext +was compressed. Bonus points for supporting multiple compression schemes. + +Another flaw is that is stores the entire ciphertext in memory, so if the file +you're encrypting is 1 Gb... you better have a lot of RAM. +*/ + +#include <fstream> +#include <iostream> +#include <string> +#include <vector> +#include <cstring> +#include <memory> + +#include <botan/botan.h> + +#if defined(BOTAN_HAS_COMPRESSOR_ZLIB) + #include <botan/zlib.h> +#endif + +using namespace Botan; + +std::string b64_encode(const SecureVector<byte>&); + +int main(int argc, char* argv[]) + { + if(argc < 2) + { + std::cout << "Usage: " << argv[0] << " [-c algo] -p passphrase file\n" + " -p : Use this passphrase to encrypt\n" + " -c : Encrypt with block cipher 'algo' (default 3DES)\n"; + return 1; + } + + Botan::LibraryInitializer init; + + std::string algo = "TripleDES"; + std::string filename, passphrase; + + // Holy hell, argument processing is a PITA + for(int j = 1; argv[j] != 0; j++) + { + if(std::strcmp(argv[j], "-c") == 0) + { + if(argv[j+1]) + { + algo = argv[j+1]; + j++; + } + else + { + std::cout << "No argument for -c option" << std::endl; + return 1; + } + } + else if(std::strcmp(argv[j], "-p") == 0) + { + if(argv[j+1]) + { + passphrase = argv[j+1]; + j++; + } + else + { + std::cout << "No argument for -p option" << std::endl; + return 1; + } + } + else + { + if(filename != "") + { + std::cout << "You can only specify one file at a time\n"; + return 1; + } + filename = argv[j]; + } + } + + if(passphrase == "") + { + std::cout << "You have to specify a passphrase!" << std::endl; + return 1; + } + + std::ifstream in(filename.c_str(), std::ios::binary); + if(!in) + { + std::cout << "ERROR: couldn't open " << filename << std::endl; + return 1; + } + + std::string outfile = filename + ".enc"; + std::ofstream out(outfile.c_str()); + if(!out) + { + std::cout << "ERROR: couldn't open " << outfile << std::endl; + return 1; + } + + try + { + const BlockCipher* cipher_proto = global_state().algorithm_factory().prototype_block_cipher(algo); + + if(!cipher_proto) + { + std::cout << "Don't know about the block cipher \"" << algo << "\"\n"; + return 1; + } + + const u32bit key_len = cipher_proto->maximum_keylength(); + const u32bit iv_len = cipher_proto->block_size(); + + AutoSeeded_RNG rng; + + std::auto_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(SHA-1)")); + + SecureVector<byte> salt(8); + rng.randomize(&salt[0], salt.size()); + + const u32bit PBKDF2_ITERATIONS = 8192; + + SymmetricKey bc_key = pbkdf->derive_key(key_len, "BLK" + passphrase, + &salt[0], salt.size(), + PBKDF2_ITERATIONS); + + InitializationVector iv = pbkdf->derive_key(iv_len, "IVL" + passphrase, + &salt[0], salt.size(), + PBKDF2_ITERATIONS); + + SymmetricKey mac_key = pbkdf->derive_key(16, "MAC" + passphrase, + &salt[0], salt.size(), + PBKDF2_ITERATIONS); + + // Just to be all fancy we even write a (simple) header. + out << "-------- ENCRYPTED FILE --------" << std::endl; + out << algo << std::endl; + out << b64_encode(salt) << std::endl; + + Pipe pipe(new Fork( + new Chain(new MAC_Filter("HMAC(SHA-1)", mac_key), + new Base64_Encoder + ), + new Chain( +#ifdef BOTAN_HAS_COMPRESSOR_ZLIB + new Zlib_Compression, +#endif + get_cipher(algo + "/CBC", bc_key, iv, ENCRYPTION), + new Base64_Encoder(true) + ) + ) + ); + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + + out << pipe.read_all_as_string(0) << std::endl; + out << pipe.read_all_as_string(1); + + } + catch(Algorithm_Not_Found) + { + std::cout << "Don't know about the block cipher \"" << algo << "\"\n"; + return 1; + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + return 1; + } + return 0; + } + +std::string b64_encode(const SecureVector<byte>& in) + { + Pipe pipe(new Base64_Encoder); + pipe.process_msg(in); + return pipe.read_all_as_string(); + } diff --git a/examples/encrypt2.cpp b/examples/encrypt2.cpp new file mode 100644 index 000000000..41f4fb478 --- /dev/null +++ b/examples/encrypt2.cpp @@ -0,0 +1,66 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/pbkdf2.h> +#include <botan/hmac.h> +#include <botan/sha160.h> + +#include <fstream> + +using namespace Botan; + +int main() + { + Botan::LibraryInitializer init; + + AutoSeeded_RNG rng; + + std::string passphrase = "secret"; + + std::ifstream infile("readme.txt"); + std::ofstream outfile("readme.txt.enc"); + + PKCS5_PBKDF2 pbkdf2(new HMAC(new SHA_160)); + + const u32bit PBKDF2_ITERATIONS = 8192; + + SecureVector<byte> salt(8); + rng.randomize(&salt[0], salt.size()); + + SecureVector<byte> master_key = pbkdf2.derive_key(48, passphrase, + &salt[0], salt.size(), + PBKDF2_ITERATIONS).bits_of(); + + KDF* kdf = get_kdf("KDF2(SHA-1)"); + + SymmetricKey key = kdf->derive_key(20, master_key, "cipher key"); + + SymmetricKey mac_key = kdf->derive_key(20, master_key, "hmac key"); + + InitializationVector iv = kdf->derive_key(8, master_key, "cipher iv"); + + Pipe pipe(new Fork( + new Chain( + get_cipher("Blowfish/CBC/PKCS7", key, iv, ENCRYPTION), + new Base64_Encoder, + new DataSink_Stream(outfile) + ), + new Chain( + new MAC_Filter("HMAC(SHA-1)", mac_key), + new Hex_Encoder) + ) + ); + + outfile.write((const char*)salt.begin(), salt.size()); + + pipe.start_msg(); + infile >> pipe; + pipe.end_msg(); + + SecureVector<byte> hmac = pipe.read_all(1); + outfile.write((const char*)hmac.begin(), hmac.size()); + } diff --git a/examples/factor.cpp b/examples/factor.cpp new file mode 100644 index 000000000..58b12d9a5 --- /dev/null +++ b/examples/factor.cpp @@ -0,0 +1,154 @@ +/* +* (C) 2009-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +* +* Factor integers using a combination of trial division by small +* primes, and Pollard's Rho algorithm +*/ + +#include <botan/botan.h> +#include <botan/reducer.h> +#include <botan/numthry.h> +using namespace Botan; + +#include <algorithm> +#include <iostream> +#include <iterator> + +namespace { + +/* +* Pollard's Rho algorithm, as described in the MIT algorithms book. We +* use (x^2+x) mod n instead of (x*2-1) mod n as the random function, +* it _seems_ to lead to faster factorization for the values I tried. +*/ +BigInt rho(const BigInt& n, RandomNumberGenerator& rng) + { + BigInt x = BigInt::random_integer(rng, 0, n-1); + BigInt y = x; + BigInt d = 0; + + Modular_Reducer mod_n(n); + + u32bit i = 1, k = 2; + while(true) + { + i++; + + if(i == 0) // overflow, bail out + break; + + x = mod_n.multiply((x + 1), x); + + d = gcd(y - x, n); + if(d != 1 && d != n) + return d; + + if(i == k) + { + y = x; + k = 2*k; + } + } + return 0; + } + +// Remove (and return) any small (< 2^16) factors +std::vector<BigInt> remove_small_factors(BigInt& n) + { + std::vector<BigInt> factors; + + while(n.is_even()) + { + factors.push_back(2); + n /= 2; + } + + for(u32bit j = 0; j != PRIME_TABLE_SIZE; j++) + { + if(n < PRIMES[j]) + break; + + BigInt x = gcd(n, PRIMES[j]); + + if(x != 1) + { + n /= x; + + u32bit occurs = 0; + while(x != 1) + { + x /= PRIMES[j]; + occurs++; + } + + for(u32bit k = 0; k != occurs; k++) + factors.push_back(PRIMES[j]); + } + } + + return factors; + } + +std::vector<BigInt> factorize(const BigInt& n_in, + RandomNumberGenerator& rng) + { + BigInt n = n_in; + std::vector<BigInt> factors = remove_small_factors(n); + + while(n != 1) + { + if(check_prime(n, rng)) + { + factors.push_back(n); + break; + } + + BigInt a_factor = 0; + while(a_factor == 0) + a_factor = rho(n, rng); + + std::vector<BigInt> rho_factored = factorize(a_factor, rng); + for(u32bit j = 0; j != rho_factored.size(); j++) + factors.push_back(rho_factored[j]); + + n /= a_factor; + } + return factors; + } + +} + +int main(int argc, char* argv[]) + { + if(argc != 2) + { + std::cerr << "Usage: " << argv[0] << " integer\n"; + return 1; + } + + Botan::LibraryInitializer init; + + try + { + BigInt n(argv[1]); + + AutoSeeded_RNG rng; + + std::vector<BigInt> factors = factorize(n, rng); + std::sort(factors.begin(), factors.end()); + + std::cout << n << ": "; + std::copy(factors.begin(), + factors.end(), + std::ostream_iterator<BigInt>(std::cout, " ")); + std::cout << "\n"; + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; + } diff --git a/examples/fpe.cpp b/examples/fpe.cpp new file mode 100644 index 000000000..9b18d4879 --- /dev/null +++ b/examples/fpe.cpp @@ -0,0 +1,151 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +* 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> + +namespace { + +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(); + } + +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; + + 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 << "Input was: " << cc_number << ' ' + << luhn_check(cc_number) << '\n'; + + /** + * In practice something like PBKDF2 with a salt and high iteration + * count would be a good idea. + */ + SymmetricKey key = sha1(passwd); + + u64bit enc_cc = encrypt_cc_number(cc_number, key, acct_name); + + std::cout << "Encrypted: " << enc_cc + << ' ' << luhn_check(enc_cc) << '\n'; + + u64bit dec_cc = decrypt_cc_number(enc_cc, key, acct_name); + + std::cout << "Decrypted: " << dec_cc + << ' ' << luhn_check(dec_cc) << '\n'; + + if(dec_cc != cc_number) + std::cout << "Something went wrong :( Bad CC checksum?\n"; + } diff --git a/examples/gen_certs.cpp b/examples/gen_certs.cpp new file mode 100644 index 000000000..f8c9fe124 --- /dev/null +++ b/examples/gen_certs.cpp @@ -0,0 +1,134 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +* Generate a root CA plus httpd, dovecot, and postfix certs/keys +* +*/ + +#include <botan/botan.h> +#include <botan/rsa.h> +#include <botan/time.h> +#include <botan/x509self.h> +#include <botan/x509_ca.h> + +using namespace Botan; + +#include <iostream> +#include <fstream> + +namespace { + +void fill_commoninfo(X509_Cert_Options& opts) + { + opts.country = "US"; + opts.organization = "randombit.net"; + opts.email = "[email protected]"; + opts.locality = "Vermont"; + } + +X509_Certificate make_ca_cert(RandomNumberGenerator& rng, + const Private_Key& priv_key, + const X509_Time& now, + const X509_Time& later) + { + X509_Cert_Options opts; + fill_commoninfo(opts); + opts.common_name = "randombit.net CA"; + opts.start = now; + opts.end = later; + opts.CA_key(); + + return X509::create_self_signed_cert(opts, priv_key, "SHA-256", rng); + } + +PKCS10_Request make_server_cert_req(const Private_Key& key, + const std::string& hostname, + RandomNumberGenerator& rng) + { + X509_Cert_Options opts; + opts.common_name = hostname; + fill_commoninfo(opts); + + opts.add_ex_constraint("PKIX.ServerAuth"); + + return X509::create_cert_req(opts, key, "SHA-1", rng); + } + +void save_pair(const std::string& name, + const std::string& password, + const X509_Certificate& cert, + const Private_Key& key, + RandomNumberGenerator& rng) + { + std::string cert_fsname = name + "_cert.pem"; + std::string key_fsname = name + "_key.pem"; + + std::ofstream cert_out(cert_fsname.c_str()); + cert_out << cert.PEM_encode() << "\n"; + cert_out.close(); + + std::ofstream key_out(key_fsname.c_str()); + if(password != "") + key_out << PKCS8::PEM_encode(key, rng, password); + else + key_out << PKCS8::PEM_encode(key); + key_out.close(); + } + +} + +int main() + { + const u32bit seconds_in_a_year = 31556926; + + const u32bit current_time = system_time(); + + X509_Time now = X509_Time(current_time); + X509_Time later = X509_Time(current_time + 4*seconds_in_a_year); + + LibraryInitializer init; + + AutoSeeded_RNG rng; + + RSA_PrivateKey ca_key(rng, 2048); + + X509_Certificate ca_cert = make_ca_cert(rng, ca_key, now, later); + + const std::string ca_password = "sekrit"; + + save_pair("ca", ca_password, ca_cert, ca_key, rng); + + X509_CA ca(ca_cert, ca_key, "SHA-256"); + + RSA_PrivateKey httpd_key(rng, 1536); + X509_Certificate httpd_cert = ca.sign_request( + make_server_cert_req(httpd_key, "www.randombit.net", rng), + rng, now, later); + + save_pair("httpd", "", httpd_cert, httpd_key, rng); + + RSA_PrivateKey bugzilla_key(rng, 1536); + X509_Certificate bugzilla_cert = ca.sign_request( + make_server_cert_req(bugzilla_key, "bugs.randombit.net", rng), + rng, now, later); + + save_pair("bugzilla", "", bugzilla_cert, bugzilla_key, rng); + + RSA_PrivateKey postfix_key(rng, 1536); + X509_Certificate postfix_cert = ca.sign_request( + make_server_cert_req(postfix_key, "mail.randombit.net", rng), + rng, now, later); + + save_pair("postfix", "", postfix_cert, postfix_key, rng); + + RSA_PrivateKey dovecot_key(rng, 1536); + X509_Certificate dovecot_cert = ca.sign_request( + make_server_cert_req(dovecot_key, "imap.randombit.net", rng), + rng, now, later); + + save_pair("dovecot", "", dovecot_cert, dovecot_key, rng); + } diff --git a/examples/gtk/Makefile b/examples/gtk/Makefile new file mode 100644 index 000000000..10e069bb3 --- /dev/null +++ b/examples/gtk/Makefile @@ -0,0 +1,18 @@ + +LIBS=$(shell botan-config --libs) $(shell pkg-config --libs gtk+-2.0) +IFLAGS=$(shell botan-config --cflags) $(shell pkg-config --cflags gtk+-2.0) + +CXX = g++ +CXXFLAGS = -Wall -W $(IFLAGS) + +dsa: gtk_ui.o dsa.o + $(CXX) $^ $(LIBS) -o $@ + +gtk_ui.o: gtk_ui.cpp gtk_ui.h + $(CXX) $(CXXFLAGS) -c $< -o $@ + +dsa.o: dsa.cpp gtk_ui.h + $(CXX) $(CXXFLAGS) -c $< -o $@ + +clean: + rm -f dsa *.o diff --git a/examples/gtk/dsa.cpp b/examples/gtk/dsa.cpp new file mode 100644 index 000000000..2cd91b0e8 --- /dev/null +++ b/examples/gtk/dsa.cpp @@ -0,0 +1,566 @@ +/* + This shows some of the details involved in a GUI application that uses + Botan. Actually most of the code is just dealing with GTK+, but it shows how + the password callback and pulse function stuff works. (See gtk_ui.cpp for the + acutal password callback code.) + + The major points of interest (assuming what you care about is how to use + Botan from a GUI, and not looking at my terrible GTK code) are gtk_ui.cpp + and, in this file, GTK_Pulse, gen_key(), and get_key(): + + gtk_ui.cpp and get_key() show how to get a passphrase from a user for + decrypting (well, in theory, anything), but in this case, PKCS #8 private + keys. Which is coincidentally the only thing Botan currently uses UI + objects for, though that will probably change eventually. GTK_UI does + double duty, for getting passphrases for encryption as well (in + do_save_key). + + gen_key() and GTK_Pulse show how to do an activity meter while doing a + long-term operation inside Botan. Since, typically, the only operations + which take a long time and can't be broken up into smaller parts are prime + generation/testing, that is currently where the pulse hooks are + called. It's certainly not the most general callback method in the world, + but it's general enough that it's usable without getting in the way too + much. The callbacks will eventually be extended to other parts of the + library (Pipe, maybe) where it's useful. + + This program is in the public domain. +*/ +#include <fstream> +#include <iostream> +#include <memory> + +#include <botan/botan.h> +#include <botan/libstate.h> +#include <botan/look_pk.h> +#include <botan/filters.h> +#include <botan/pk_filts.h> +#include <botan/dsa.h> + +// we don't have a 'using namespace' here, so it's easy to grep for code that +// is actually dealing with the library (rather than messing around with GTK). + +#include <gtk/gtk.h> +#include "gtk_ui.h" + +static Botan::RandomNumberGenerator* rng = 0; + +/* +* Pop up an message box +*/ +static void show_dialog(const std::string& about_message, + const std::string& dialog_name) + { + GtkDialogFlags flags = + (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL); + + GtkWidget* dialog = gtk_dialog_new_with_buttons(dialog_name.c_str(), + NULL, flags, + GTK_STOCK_OK, + GTK_RESPONSE_NONE, + NULL); + GtkWidget* label = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(label), about_message.c_str()); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); + + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show_all(dialog); + } + +/* +* Pop up an About box +*/ +static void show_about() + { + const std::string about_message = + "<big>DSA Utility</big>\n" + "\n" + "A simple application showing how to use Botan within a GUI.\n" + "It lets you generate or load keys, and sign text files.\n" + "\n" + "Send comments/questions to <tt>[email protected]</tt>"; + + show_dialog(about_message, "About"); + } + +/* +* Pop up a help box +*/ +static void show_help() + { + const std::string help_message = + "<big>DSA Utility Help</big>\n" + "\n" + "Simply, this is a (very) simple text editor, with the added ability\n" + "of being able to generate or read a DSA private key, and sign the\n" + "text buffer using that key.\n" + "\n" + "You can load, edit, and save text files as you would normally. If a\n" + "key is loaded (done using the commands in the Keys menu), you can\n" + "also use the Sign command (in the Signing menu) to generate a\n" + "signature for the current file. It will be displayed at the bottom\n" + "of the screen (if it has been calculated for the current buffer\n" + "contents), and can be saved using the \"Save Sig\" command.\n" + "\n" + "Signatures generated by this program can be verified using a the\n" + "<tt>dsa_ver</tt> example included in the Botan distribution.\n"; + + show_dialog(help_message, "Help"); + } + +/* +* Get and return a filename from the user +*/ +static std::string get_filename(const std::string& title) + { + GtkWidget* dialog = gtk_file_selection_new(title.c_str()); + + /* Some window managers don't display the titles of transient windows, + put a message elsewhere for those people. + */ + GtkWidget* label = gtk_label_new(title.c_str()); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + + std::string fsname; + + gtk_widget_show(label); /* dialog_run won't show sub-widgets */ + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) + fsname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(dialog)); + gtk_widget_destroy(dialog); + + /* If it's a directory, that's no good */ + if(fsname.size() && fsname[fsname.size()-1] == '/') + return ""; + + return fsname; + } + +/* +* Global state +*/ +static Botan::DSA_PrivateKey* key = 0; // our key +static GtkTextBuffer* buffer = 0; // the text buffer +static std::string buffer_source; + // what file (if any) the buffer's data came from +static GtkWidget* sig_view = 0; // the signature + +/* +* Zap the currently set signature (if any) +*/ +static void zap_sig() + { + gtk_editable_delete_text(GTK_EDITABLE(sig_view), 0, -1); + } + +/* +* Save the current key +*/ +static void do_save_key(const std::string& title) + { + if(key == 0) + return; + + std::string filename = get_filename(title.c_str()); + + if(filename != "") + { + const std::string msg = "Select a passphrase to encrypt the key:"; + + std::ofstream out_priv(filename.c_str()); + + GTK_UI ui; + Botan::User_Interface::UI_Result result; + std::string passphrase = ui.get_passphrase(msg, result); + + if(result == Botan::User_Interface::OK) + out_priv << Botan::PKCS8::PEM_encode(*key, *rng, passphrase); + else + out_priv << Botan::PKCS8::PEM_encode(*key); + + // for testing + //std::cout << X509::PEM_encode(*key); + } + } + +/* +* Generate a signature for the text buffer +*/ +static void sign_buffer() + { + /* No key? Ignore request. */ + if(key == 0) + return; + + /* same format as the text-mode dsa_sign example */ + Botan::Pipe pipe(new Botan::PK_Signer_Filter( + Botan::get_pk_signer(*key, "EMSA1(SHA-1)"), *rng + ), + new Botan::Base64_Encoder + ); + + /* It would probably be smart to do this a little bit at a time */ + GtkTextIter start, end; + gtk_text_buffer_get_bounds(buffer, &start, &end); + gchar* bits = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); + size_t length = strlen(bits); + + pipe.start_msg(); + pipe.write((unsigned char*)bits, length); + pipe.end_msg(); + + std::string sig = pipe.read_all_as_string(); + + zap_sig(); + + gint position = 0; + gtk_editable_insert_text(GTK_EDITABLE(sig_view), sig.c_str(), sig.length(), + &position); + + g_free(bits); + } + +#if 0 +/* +* GTK+ pulse callback +*/ +class GTK_Pulse : public Botan::Library_State::UI + { + public: + void pulse(Botan::Pulse_Type); + }; + +void GTK_Pulse::pulse(Botan::Pulse_Type) + { + /* We need this to flush the updates, otherwise GTK+ will wait until we're + done with the computation before doing any updates (generally the right + thing, but not with a progress bar). + */ + + while(gtk_events_pending()) + gtk_main_iteration(); + } +#endif + +/* +* Actual do the pulse (as a GTK+ timeout func) * +*/ +static gboolean gtk_pulse_timeout(void* pbar) + { + GtkWidget* progress_bar = (GtkWidget*)pbar; + gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress_bar)); + return TRUE; /* keep calling us */ + } + +/* +* Generate a new key +*/ +static void gen_key() + { + /* This gives a nice smooth progress bar, though we do use up quite a bit of + CPU for it. Keep in mind that if PULSE_INTERVAL is significantly less + than the average time between pulses from the library, the progress bar + will jerk around going slower or faster. Keep it at at least 50ms. + */ + const double PROGRESS_PER_PULSE = .01; /* % of bar */ + const guint32 PULSE_INTERVAL = 30; /* ms */ + + delete key; + + GtkDialogFlags flags = + (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL); + + GtkWidget* dialog = + gtk_dialog_new_with_buttons("Generating Key", NULL, flags, NULL); + + GtkWidget* label = gtk_label_new(" Generating new key, please wait... \n"); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + + GtkWidget* progress_bar = gtk_progress_bar_new(); + gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(progress_bar), + PROGRESS_PER_PULSE); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), progress_bar); + + guint timer_id = gtk_timeout_add(PULSE_INTERVAL, gtk_pulse_timeout, + progress_bar); + + gtk_widget_show_all(dialog); + + while(gtk_events_pending()) + gtk_main_iteration(); + + /* Register gtk_pulse so it will be called every so often when we embark + on our prime generation quest... + */ + /* this just updates the GUI; the GTK+ timeout function actually updates + the progress bar. That's because the amount of time between pulses + from the library is rather irregular, so the progress bar looks jerky. + */ + //Botan::global_state().set_ui(new GTK_Pulse); + + /* Not generally recommended, since it's slow and there's not much point. + However, *because* it's slow, we'll want to put up a progress bar or + something, and part of this whole thing is to show how to do that and get + the pulse functions to do the right thing. + */ + Botan::DL_Group group(*rng, Botan::DL_Group::DSA_Kosherizer, 1024); + key = new Botan::DSA_PrivateKey(*rng, group); + + gtk_timeout_remove(timer_id); + //Botan::global_state().set_ui(0); // unset the pulse function + + gtk_widget_destroy(dialog); + + do_save_key("Save New Key"); + + /* new key, any old sigs are no longer useful */ + zap_sig(); + } + +/* +* Load up a key +*/ +static void get_key() + { + std::string fsname = get_filename("Select a DSA Key"); + + if(fsname != "") + { + try { + delete key; + key = 0; + zap_sig(); + + /* + A GTK_UI is a subclass of User_Interface that pops up a dialog that + asks the user for a passphrase. It actually works quite well, + though the fixed upper limit on the passphrase size is not + ideal. Feel free to use it as-is or modify it however you like + (gtk_ui.* is public domain). + */ + GTK_UI ui; + Botan::PKCS8_PrivateKey* p8_key = + Botan::PKCS8::load_key(fsname, *rng, ui); + + key = dynamic_cast<Botan::DSA_PrivateKey*>(p8_key); + if(!key) + show_dialog("The key in " + fsname + " is not a DSA key", + "Failure"); + } + catch(std::exception) + { + key = 0; // make sure it's not something random + show_dialog("Loading the key from " + fsname + " failed.", "Failure"); + } + } + } + +static void really_sign_buffer() + { + /* No key? Ask the user for one. */ + if(key == 0) + get_key(); + sign_buffer(); + } + +/* +* Clear the text buffer +*/ +static void new_buffer() + { + /* + In theory, it would be nice to check if this was unsaved text and prompt + to save it. However, this really isn't supposed to be a GTK+ example, so + we won't. + */ + gtk_text_buffer_set_text(buffer, "", -1); + buffer_source = ""; + } + +/* +* Put the contents of a file into the buffer +*/ +static void open_buffer() + { + std::string filename = get_filename("Select File"); + + if(filename == "") + return; + + std::ifstream in(filename.c_str()); + + new_buffer(); + buffer_source = filename; + + while(in.good()) + { + char buf[1024] = { 0 }; + + in.read(buf, 1024); + size_t got = in.gcount(); + + GtkTextIter iter; + gtk_text_buffer_get_end_iter(buffer, &iter); + gtk_text_buffer_insert(buffer, &iter, buf, got); + } + } + +/* +* Save the signature to a file +*/ +static void save_sig() + { + std::string sig_file = buffer_source; + + /* No sig, nothing to save */ + const gchar* sig = gtk_entry_get_text(GTK_ENTRY(sig_view)); + if(strlen(sig) == 0) + return; + + if(sig_file == "") + sig_file = get_filename("Select Signature Output File"); + else + sig_file += ".sig"; + + std::ofstream out(sig_file.c_str()); + out << sig << std::endl; + } + +/* +* Save the current key +*/ +static void save_key() + { + do_save_key("Save Current Key"); + } + +/* +* Common case of Save/Save As +*/ +static void do_save(const std::string& filename) + { + std::ofstream out(filename.c_str()); + + GtkTextIter start, end; + gtk_text_buffer_get_bounds(buffer, &start, &end); + gchar* bits = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); + out.write(bits, strlen(bits)); + g_free(bits); + buffer_source = filename; + } + +/* +* Save the buffer +*/ +static void save_buffer_as() + { + std::string filename = get_filename("Select Output File"); + if(filename != "") + do_save(filename); + } + +/* +* Save the buffer +*/ +static void save_buffer() + { + if(buffer_source != "") + do_save(buffer_source); + else + save_buffer_as(); + } + +/* +* Make a menubar for the app +*/ +static GtkWidget* make_menubar(GtkWidget *window) + { + static GtkItemFactoryEntry menu_items[] = { + { "/_File", NULL, NULL, 0, "<Branch>", NULL }, + { "/File/_New", "<control>N", new_buffer, 0, NULL, NULL }, + { "/File/_Open", "<control>O", open_buffer, 0, NULL, NULL }, + { "/File/_Save", "<control>S", save_buffer, 0, NULL, NULL }, + { "/File/Save _As", NULL, save_buffer_as, 0, NULL, NULL }, + { "/File/sep1", NULL, NULL, 0, "<Separator>", NULL }, + { "/File/Save Sig", NULL, save_sig, 0, NULL, NULL }, + { "/File/sep2", NULL, NULL, 0, "<Separator>", NULL }, + { "/File/_Quit", "<control>Q", gtk_main_quit, 0, NULL, NULL }, + + { "/_Keys", NULL, NULL, 0, "<Branch>", NULL }, + { "/Keys/Open", NULL, get_key, 0, NULL, NULL }, + { "/Keys/_Generate", NULL, gen_key, 0, NULL, NULL }, + { "/Keys/Save Current", NULL, save_key, 0, NULL, NULL }, + + { "/Signing", NULL, NULL, 0, "<Branch>", NULL }, + { "/Signing/Sign", NULL, really_sign_buffer, 0, NULL, NULL }, + + { "/_Help", NULL, NULL, 0, "<LastBranch>", NULL }, + { "/Help/Help", NULL, show_help, 0, NULL, NULL }, + { "/Help/sep1", NULL, NULL, 0, "<Separator>", NULL }, + { "/Help/About", NULL, show_about, 0, NULL, NULL }, + }; + + GtkAccelGroup* accel_group = gtk_accel_group_new(); + GtkItemFactory* item_factory = + gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group); + const gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); + gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL); + gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); + return gtk_item_factory_get_widget(item_factory, "<main>"); + } + +int main(int argc, char *argv[]) + { + gtk_init(&argc, &argv); + + try { + Botan::LibraryInitializer init; + + rng = new Botan::AutoSeeded_RNG; + + /* Create a new top-level window */ + GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "DSA Utility"); + gtk_signal_connect(GTK_OBJECT(window), "delete_event", + gtk_main_quit, NULL); + + /* Create the vbox to hold our stuff */ + GtkWidget* vbox = gtk_vbox_new(FALSE, 0); + gtk_container_border_width(GTK_CONTAINER(vbox), 1); + gtk_container_add(GTK_CONTAINER(window), vbox); + + /* Create the menu bar */ + GtkWidget *menubar = make_menubar(window); + + /* Create the entry that holds the signature */ + sig_view = gtk_entry_new(); + gtk_editable_set_editable(GTK_EDITABLE(sig_view), FALSE); + + /* Create the text box */ + GtkWidget* view = gtk_text_view_new(); + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); + + gtk_widget_set_size_request(view, 640, 480); + gtk_text_buffer_set_text(buffer, "Some initial contents.", -1); + + // Resign it on each change: fast enough, but probably not really useful + //g_signal_connect(G_OBJECT(buffer), "changed", sign_buffer, 0); + g_signal_connect(G_OBJECT(buffer), "changed", zap_sig, 0); + + gtk_container_add(GTK_CONTAINER(vbox), menubar); + gtk_container_add(GTK_CONTAINER(vbox), view); + gtk_container_add(GTK_CONTAINER(vbox), sig_view); + + gtk_widget_show_all(window); + + gtk_main(); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + } + return 0; + } diff --git a/examples/gtk/gtk_ui.cpp b/examples/gtk/gtk_ui.cpp new file mode 100644 index 000000000..d4e9cd238 --- /dev/null +++ b/examples/gtk/gtk_ui.cpp @@ -0,0 +1,79 @@ +/* +* GTK+ User Interface Source File +*/ + +#include "gtk_ui.h" +#include <cstring> + +/* +* GTK+ Callback * +*/ +void GTK_UI::callback(GtkWidget* entry, gpointer passphrase_ptr) + { + const gchar *entry_text = gtk_entry_get_text(GTK_ENTRY(entry)); + char* passphrase = (char*)passphrase_ptr; + std::strcpy(passphrase, entry_text); + } + +/* +* Get a passphrase from the user +*/ +std::string GTK_UI::get_passphrase(const std::string& what, + const std::string& source, + UI_Result& result) const + { + std::string msg = "A passphrase is needed to access the " + what; + if(source != "") msg += "\nin " + source; + return get_passphrase(msg, result); + } + +/* +* Get a passphrase from the user +*/ +std::string GTK_UI::get_passphrase(const std::string& label_text, + UI_Result& result) const + { + const int MAX_PASSPHRASE = 64; + + GtkDialogFlags flags = + (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL); + + GtkWidget* dialog = gtk_dialog_new_with_buttons( + "Enter Passphrase", + NULL, flags, + GTK_STOCK_OK, GTK_RESPONSE_OK, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + NULL); + + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); + + GtkWidget* label = gtk_label_new(label_text.c_str()); + + GtkWidget* entry = gtk_entry_new(); + gtk_entry_set_visibility(GTK_ENTRY(entry), 0); + gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); + gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_PASSPHRASE); + + char passphrase_buf[MAX_PASSPHRASE + 1] = { 0 }; + + gtk_signal_connect(GTK_OBJECT(entry), "activate", + GTK_SIGNAL_FUNC(callback), passphrase_buf); + + GtkWidget* vbox = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); + + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, TRUE, TRUE, 0); + gtk_widget_show_all(vbox); + + /* Block until we get something back */ + result = CANCEL_ACTION; + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) + result = OK; + + gtk_widget_destroy(dialog); + + if(result == OK) + return std::string(passphrase_buf); + return ""; + } diff --git a/examples/gtk/gtk_ui.h b/examples/gtk/gtk_ui.h new file mode 100644 index 000000000..065a4f76b --- /dev/null +++ b/examples/gtk/gtk_ui.h @@ -0,0 +1,27 @@ +/* +* (C) 2006 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EXT_GTK_UI__ +#define BOTAN_EXT_GTK_UI__ + +#include <botan/ui.h> +#include <gtk/gtk.h> + +/* +* GTK+ Passphrase Callback Object +*/ +class GTK_UI : public Botan::User_Interface + { + public: + std::string get_passphrase(const std::string&, const std::string&, + UI_Result&) const; + + std::string get_passphrase(const std::string&, UI_Result&) const; + + static void callback(GtkWidget*, gpointer); + }; + +#endif diff --git a/examples/gtk/readme.txt b/examples/gtk/readme.txt new file mode 100644 index 000000000..4f3691166 --- /dev/null +++ b/examples/gtk/readme.txt @@ -0,0 +1,18 @@ + +This is an example of how to use Botan in a GUI. You need at least +Botan 1.6.0. + +You'll also need GTK+ 2.x (tested with GTK+ 2.10; should work with +most versions). Keep in mind that I was learning GTK as I was writing +this code, so it is not exactly the best GTK code you're likely to +see. + +dsa.cpp is the main GTK+ driver. It has some comments at the top which +point out major areas of interest. + +gtk_ui.* implement a User_Interface object that opens up a GTK+ dialog +box that asks the user for their passphrase. It works pretty well, the +only major deficiency is a fixed upper limit on the size of the +passphrase (currently 64). You may want to use this in your own code, +assuming you use GTK. If not, it should at least provide an outline +for writing a version for your favorite windowing system. diff --git a/examples/hash.cpp b/examples/hash.cpp new file mode 100644 index 000000000..1a4ca1b64 --- /dev/null +++ b/examples/hash.cpp @@ -0,0 +1,58 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <iostream> +#include <fstream> +#include <botan/botan.h> + +int main(int argc, char* argv[]) + { + if(argc < 3) + { + std::cout << "Usage: " << argv[0] << " digest <filenames>" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + std::string hash = argv[1]; + /* a couple of special cases, kind of a crock */ + if(hash == "sha1") hash = "SHA-1"; + if(hash == "md5") hash = "MD5"; + + try { + if(!Botan::have_hash(hash)) + { + std::cout << "Unknown hash \"" << argv[1] << "\"" << std::endl; + return 1; + } + + Botan::Pipe pipe(new Botan::Hash_Filter(hash), + new Botan::Hex_Encoder); + + int skipped = 0; + for(int j = 2; argv[j] != 0; j++) + { + std::ifstream file(argv[j], std::ios::binary); + if(!file) + { + std::cout << "ERROR: could not open " << argv[j] << std::endl; + skipped++; + continue; + } + pipe.start_msg(); + file >> pipe; + pipe.end_msg(); + pipe.set_default_msg(j-2-skipped); + std::cout << pipe << " " << argv[j] << std::endl; + } + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + } + return 0; + } diff --git a/examples/hash_fd.cpp b/examples/hash_fd.cpp new file mode 100644 index 000000000..32acdbec3 --- /dev/null +++ b/examples/hash_fd.cpp @@ -0,0 +1,70 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +This is just like the normal hash application, but uses the Unix I/O +system calls instead of C++ iostreams. Previously, this version was +much faster and smaller, but GCC 3.1's libstdc++ seems to have been +improved enough that the difference is now fairly minimal. + +Nicely enough, doing the change required changing only about 3 lines +of code. +*/ + +#include <iostream> +#include <botan/botan.h> + +#if !defined(BOTAN_HAS_PIPE_UNIXFD_IO) + #error "You didn't compile the pipe_unixfd module into Botan" +#endif + +#include <fcntl.h> +#include <unistd.h> + +int main(int argc, char* argv[]) + { + if(argc < 3) + { + std::cout << "Usage: " << argv[0] << " digest <filenames>" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + try + { + Botan::Pipe pipe(new Botan::Hash_Filter(argv[1]), + new Botan::Hex_Encoder); + + int skipped = 0; + for(int j = 2; argv[j] != 0; j++) + { + int file = open(argv[j], O_RDONLY); + if(file == -1) + { + std::cout << "ERROR: could not open " << argv[j] << std::endl; + skipped++; + continue; + } + pipe.start_msg(); + file >> pipe; + pipe.end_msg(); + close(file); + pipe.set_default_msg(j-2-skipped); + std::cout << pipe << " " << argv[j] << std::endl; + } + } + catch(Botan::Algorithm_Not_Found) + { + std::cout << "Don't know about the hash function \"" << argv[1] << "\"" + << std::endl; + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + } + return 0; + } diff --git a/examples/hash_quickly.cpp b/examples/hash_quickly.cpp new file mode 100644 index 000000000..005a6d719 --- /dev/null +++ b/examples/hash_quickly.cpp @@ -0,0 +1,98 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Try to find the fastest SHA-1 implementation and use it to hash +files. In most programs this isn't worth the bother and +overhead. However with large amount of input, it is worth it. On tests +on a Core2 system with the SHA-1 SSE2 code enabled, over a few hundred +Mb or so the overhead paid for itself. + +Of course you could also just do this once and save it as an +application config, which is probably the smart thing to do. +*/ + +#include <botan/botan.h> +#include <botan/benchmark.h> +#include <botan/filters.h> + +#include <iostream> +#include <fstream> +#include <string> +#include <map> +#include <cstdlib> + +namespace { + +void set_fastest_implementation(const std::string& algo, + Botan::RandomNumberGenerator& rng, + double ms = 30) + { + Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory(); + + std::map<std::string, double> results = + Botan::algorithm_benchmark(algo, af, rng, ms, 16*1024); + + std::string fastest_provider = ""; + double best_res = 0; + + for(std::map<std::string, double>::iterator r = results.begin(); + r != results.end(); ++r) + { + std::cout << r->first << " @ " << r->second << " MiB/sec\n"; + + if(fastest_provider == "" || r->second > best_res) + { + fastest_provider = r->first; + best_res = r->second; + } + } + + std::cout << "Using " << fastest_provider << "\n"; + + af.set_preferred_provider(algo, fastest_provider); + } + +} + +int main(int argc, char* argv[]) + { + if(argc <= 1) + { + std::cout << "Usage: " << argv[0] << " <file> <file> ...\n"; + return 1; + } + + Botan::LibraryInitializer init; + Botan::AutoSeeded_RNG rng; + + const std::string hash = "SHA-1"; + + set_fastest_implementation(hash, rng); + + // Here we intentionally use the 'old style' lookup interface + // which will also respect the provider settings. Or can use: + // global_state().algorithm_factory().make_hash_function(hash) + Botan::Pipe pipe( + new Botan::Hash_Filter(Botan::get_hash(hash)), + new Botan::Hex_Encoder + ); + + for(size_t i = 1; argv[i]; ++i) + { + std::ifstream in(argv[i], std::ios::binary); + if(!in) + continue; + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + + std::cout << argv[i] << " = " + << pipe.read_all_as_string(Botan::Pipe::LAST_MESSAGE) << "\n"; + + } + } diff --git a/examples/hasher.cpp b/examples/hasher.cpp new file mode 100644 index 000000000..e5c52ba55 --- /dev/null +++ b/examples/hasher.cpp @@ -0,0 +1,55 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <fstream> +#include <iostream> +#include <string> +#include <botan/botan.h> + +int main(int argc, char* argv[]) + { + if(argc < 2) + { + std::cout << "Usage: " << argv[0] << " <filenames>" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + const int COUNT = 3; + std::string name[COUNT] = { "MD5", "SHA-1", "RIPEMD-160" }; + + for(int j = 1; argv[j] != 0; j++) + { + Botan::Filter* hash[COUNT] = { + new Botan::Chain(new Botan::Hash_Filter(name[0]), + new Botan::Hex_Encoder), + new Botan::Chain(new Botan::Hash_Filter(name[1]), + new Botan::Hex_Encoder), + new Botan::Chain(new Botan::Hash_Filter(name[2]), + new Botan::Hex_Encoder) + }; + + Botan::Pipe pipe(new Botan::Fork(hash, COUNT)); + + std::ifstream file(argv[j], std::ios::binary); + if(!file) + { + std::cout << "ERROR: could not open " << argv[j] << std::endl; + continue; + } + pipe.start_msg(); + file >> pipe; + pipe.end_msg(); + file.close(); + for(int k = 0; k != COUNT; k++) + { + pipe.set_default_msg(k); + std::cout << name[k] << "(" << argv[j] << ") = " << pipe << std::endl; + } + } + return 0; + } diff --git a/examples/hasher2.cpp b/examples/hasher2.cpp new file mode 100644 index 000000000..b6303b644 --- /dev/null +++ b/examples/hasher2.cpp @@ -0,0 +1,75 @@ +/* +* (C) 2001 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Identical to hasher.cpp, but uses Pipe in a different way. + +Note this tends to be much less efficient than hasher.cpp, because it +does three passes over the file. For a small file, it doesn't really +matter. But for a large file, or for something you can't re-read +easily (socket, stdin, ...) this is a bad idea. +*/ + +#include <fstream> +#include <iostream> +#include <string> +#include <botan/botan.h> + +int main(int argc, char* argv[]) + { + if(argc < 2) + { + std::cout << "Usage: " << argv[0] << " <filenames>" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + const int COUNT = 3; + std::string name[COUNT] = { "MD5", "SHA-1", "RIPEMD-160" }; + + Botan::Pipe pipe; + + int skipped = 0; + for(int j = 1; argv[j] != 0; j++) + { + Botan::Filter* hash[COUNT] = { + new Botan::Hash_Filter(name[0]), + new Botan::Hash_Filter(name[1]), + new Botan::Hash_Filter(name[2]), + }; + + std::ifstream file(argv[j], std::ios::binary); + if(!file) + { + std::cout << "ERROR: could not open " << argv[j] << std::endl; + skipped++; + continue; + } + for(int k = 0; k != COUNT; k++) + { + pipe.reset(); + pipe.append(hash[k]); + pipe.append(new Botan::Hex_Encoder); + pipe.start_msg(); + + // trickiness: the >> op reads until EOF, but seekg won't work + // unless we're in the "good" state (which EOF is not). + file.clear(); + file.seekg(0, std::ios::beg); + file >> pipe; + pipe.end_msg(); + } + file.close(); + for(int k = 0; k != COUNT; k++) + { + std::string out = pipe.read_all_as_string(COUNT*(j-1-skipped) + k); + std::cout << name[k] << "(" << argv[j] << ") = " << out << std::endl; + } + } + + return 0; + } diff --git a/examples/keywrap.cpp b/examples/keywrap.cpp new file mode 100644 index 000000000..730bcb6c9 --- /dev/null +++ b/examples/keywrap.cpp @@ -0,0 +1,38 @@ +/* +* NIST keywrap example +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/rfc3394.h> +#include <botan/hex.h> +#include <iostream> + +int main() + { + using namespace Botan; + + LibraryInitializer init; + + AutoSeeded_RNG rng; + + // The key to encrypt + SymmetricKey key(rng, 24); + + // The key encryption key + SymmetricKey kek(rng, 32); + + std::cout << "Original: " << key.as_string() << "\n"; + + Algorithm_Factory& af = global_state().algorithm_factory(); + + SecureVector<byte> enc = rfc3394_keywrap(key.bits_of(), kek, af); + + std::cout << "Encrypted: " << hex_encode(enc) << "\n"; + + SecureVector<byte> dec = rfc3394_keyunwrap(enc, kek, af); + + std::cout << "Decrypted: " << hex_encode(dec) << "\n"; + } diff --git a/examples/make_prime.cpp b/examples/make_prime.cpp new file mode 100644 index 000000000..acaaac698 --- /dev/null +++ b/examples/make_prime.cpp @@ -0,0 +1,79 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/numthry.h> +#include <botan/auto_rng.h> +#include <botan/botan.h> + +using namespace Botan; + +#include <set> +#include <iostream> +#include <iterator> +#include <map> + +int main() + { + Botan::LibraryInitializer init; + AutoSeeded_RNG rng; + + std::set<BigInt> primes; + + std::map<int, int> bit_count; + + int not_new = 0; + + while(primes.size() < 10000) + { + u32bit start_cnt = primes.size(); + + u32bit bits = 18; + + if(rng.next_byte() % 128 == 0) + bits -= rng.next_byte() % (bits-2); + + bit_count[bits]++; + + //std::cout << "random_prime(" << bits << ")\n"; + + BigInt p = random_prime(rng, bits); + + if(p.bits() != bits) + { + std::cout << "Asked for " << bits << " got " << p + << " " << p.bits() << " bits\n"; + return 1; + } + + primes.insert(random_prime(rng, bits)); + + if(primes.size() != start_cnt) + std::cout << primes.size() << "\n"; + else + not_new++; + + //std::cout << "miss: " << not_new << "\n"; + + if(not_new % 100000 == 0) + { + for(std::map<int, int>::iterator i = bit_count.begin(); + i != bit_count.end(); ++i) + std::cout << "bit_count[" << i->first << "] = " + << i->second << "\n"; + std::copy(primes.begin(), primes.end(), + std::ostream_iterator<BigInt>(std::cout, " ")); + } + } + + std::cout << "Generated all? primes\n"; + /* + for(u32bit j = 0; j != PRIME_TABLE_SIZE; ++j) + { + if(primes.count(PRIMES[j]) != 1) + std::cout << "Missing " << PRIMES[j] << "\n"; + } + */ + } diff --git a/examples/new_engine.cpp b/examples/new_engine.cpp new file mode 100644 index 000000000..42e5dbe33 --- /dev/null +++ b/examples/new_engine.cpp @@ -0,0 +1,106 @@ +/* +* Adding an application specific engine +* (C) 2004,2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/stream_cipher.h> +#include <botan/engine.h> + +using namespace Botan; + +class XOR_Cipher : public StreamCipher + { + public: + void clear() throw() { mask.clear(); mask_pos = 0; } + + // what we want to call this cipher + std::string name() const { return "XOR"; } + + // return a new object of this type + StreamCipher* clone() const { return new XOR_Cipher; } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(1, 32); + } + + XOR_Cipher() : mask_pos(0) {} + private: + void cipher(const byte in[], byte out[], size_t length) + { + for(size_t j = 0; j != length; j++) + { + out[j] = in[j] ^ mask[mask_pos]; + mask_pos = (mask_pos + 1) % mask.size(); + } + } + + void key_schedule(const byte key[], size_t length) + { + mask.resize(length); + copy_mem(&mask[0], key, length); + } + + SecureVector<byte> mask; + u32bit mask_pos; + }; + +class Application_Engine : public Engine + { + public: + std::string provider_name() const { return "application"; } + + StreamCipher* find_stream_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { + if(request.algo_name() == "XOR") + return new XOR_Cipher; + return 0; + } + }; + +#include <botan/botan.h> +#include <iostream> +#include <string> + +int main() + { + + Botan::LibraryInitializer init; + + global_state().algorithm_factory().add_engine( + new Application_Engine); + + // a hex key value + SymmetricKey key("010203040506070809101112AAFF"); + + /* + Since stream ciphers are typically additive, the encryption and + decryption ops are the same, so this isn't terribly interesting. + + If this where a block cipher you would have to add a cipher mode and + padding method, such as "/CBC/PKCS7". + */ + Pipe enc(get_cipher("XOR", key, ENCRYPTION), new Hex_Encoder); + Pipe dec(new Hex_Decoder, get_cipher("XOR", key, DECRYPTION)); + + // I think the pigeons are actually asleep at midnight... + std::string secret = "The pigeon flys at midnight."; + + std::cout << "The secret message is '" << secret << "'" << std::endl; + + enc.process_msg(secret); + std::string cipher = enc.read_all_as_string(); + + std::cout << "The encrypted secret message is " << cipher << std::endl; + + dec.process_msg(cipher); + secret = dec.read_all_as_string(); + + std::cout << "The decrypted secret message is '" + << secret << "'" << std::endl; + + return 0; + } diff --git a/examples/package.cpp b/examples/package.cpp new file mode 100644 index 000000000..02cf52816 --- /dev/null +++ b/examples/package.cpp @@ -0,0 +1,70 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/serpent.h> +#include <botan/package.h> + +#include <iostream> +#include <fstream> +#include <vector> + +using namespace Botan; + +namespace { + +std::vector<byte> slurp_file(const std::string& filename) + { + std::ifstream in(filename.c_str(), std::ios::binary); + + std::vector<byte> out; + byte buf[4096] = { 0 }; + + while(in.good()) + { + in.read((char*)buf, sizeof(buf)); + ssize_t got = in.gcount(); + + out.insert(out.end(), buf, buf+got); + } + + return out; + } + +} + +int main(int argc, char* argv[]) + { + if(argc != 2) + { + std::cout << "Usage: " << argv[0] << " filename\n"; + return 1; + } + + LibraryInitializer init; + + AutoSeeded_RNG rng; + + BlockCipher* cipher = new Serpent; + + std::vector<byte> input = slurp_file(argv[1]); + std::vector<byte> output(input.size() + cipher->block_size()); + + aont_package(rng, new Serpent, + &input[0], input.size(), + &output[0]); + + std::vector<byte> unpackage_output(output.size() - cipher->block_size()); + + aont_unpackage(new Serpent, + &output[0], output.size(), + &unpackage_output[0]); + + if(unpackage_output == input) + std::cout << "Package/unpackage worked\n"; + else + std::cout << "Something went wrong :(\n"; + } diff --git a/examples/passhash.cpp b/examples/passhash.cpp new file mode 100644 index 000000000..586c28c3f --- /dev/null +++ b/examples/passhash.cpp @@ -0,0 +1,50 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/passhash9.h> +#include <iostream> +#include <memory> + +#include <stdio.h> + +int main(int argc, char* argv[]) + { + if(argc != 2 && argc != 3) + { + std::cerr << "Usage: " << argv[0] << " password\n"; + std::cerr << "Usage: " << argv[0] << " password hash\n"; + return 1; + } + + Botan::LibraryInitializer init; + + try + { + + if(argc == 2) + { + Botan::AutoSeeded_RNG rng; + + std::cout << "H('" << argv[1] << "') = " + << Botan::generate_passhash9(argv[1], rng) << '\n'; + } + else + { + bool ok = Botan::check_passhash9(argv[1], argv[2]); + if(ok) + std::cout << "Password and hash match\n"; + else + std::cout << "Password and hash do not match\n"; + } + } + catch(std::exception& e) + { + std::cerr << e.what() << '\n'; + return 1; + } + return 0; + } diff --git a/examples/pkcs10.cpp b/examples/pkcs10.cpp new file mode 100644 index 000000000..3f5ec8e05 --- /dev/null +++ b/examples/pkcs10.cpp @@ -0,0 +1,70 @@ +/* +* (C) 2003 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/init.h> +#include <botan/auto_rng.h> +#include <botan/x509self.h> +#include <botan/rsa.h> +#include <botan/dsa.h> +using namespace Botan; + +#include <iostream> +#include <fstream> +#include <memory> + +int main(int argc, char* argv[]) + { + if(argc != 6) + { + std::cout << "Usage: " << argv[0] << + " passphrase name country_code organization email" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + try + { + AutoSeeded_RNG rng; + + RSA_PrivateKey priv_key(rng, 1024); + // If you want a DSA key instead of RSA, comment out the above line and + // uncomment this one: + //DSA_PrivateKey priv_key(DL_Group("dsa/jce/1024")); + + std::ofstream key_file("private.pem"); + key_file << PKCS8::PEM_encode(priv_key, rng, argv[1]); + + X509_Cert_Options opts; + + opts.common_name = argv[2]; + opts.country = argv[3]; + opts.organization = argv[4]; + opts.email = argv[5]; + + /* Some hard-coded options, just to give you an idea of what's there */ + opts.challenge = "a fixed challenge passphrase"; + opts.locality = "Baltimore"; + opts.state = "MD"; + opts.org_unit = "Testing"; + opts.add_ex_constraint("PKIX.ClientAuth"); + opts.add_ex_constraint("PKIX.IPsecUser"); + opts.add_ex_constraint("PKIX.EmailProtection"); + + opts.xmpp = "[email protected]"; + + PKCS10_Request req = X509::create_cert_req(opts, priv_key, "SHA-1", rng); + + std::ofstream req_file("req.pem"); + req_file << req.PEM_encode(); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; + } diff --git a/examples/pqg_gen.cpp b/examples/pqg_gen.cpp new file mode 100644 index 000000000..c033dac3b --- /dev/null +++ b/examples/pqg_gen.cpp @@ -0,0 +1,121 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> +#include <map> +#include <memory> + +#include <botan/botan.h> +#include <botan/auto_rng.h> +#include <botan/dsa.h> +#include <botan/numthry.h> +#include <botan/dl_group.h> +using namespace Botan; + +bool check(RandomNumberGenerator& rng, + std::map<std::string, std::string>); + +int main() + { + try { + Botan::LibraryInitializer init("use_engines"); + + AutoSeeded_RNG rng; + + std::ifstream in("PQGGen.rsp"); + if(!in) + throw std::runtime_error("Can't open response file"); + + std::map<std::string, std::string> inputs; + + while(in.good()) + { + std::string line; + std::getline(in, line); + + if(line == "" || line[0] == '[' || line[0] == '#') + continue; + + std::vector<std::string> name_and_val = split_on(line, '='); + + if(name_and_val.size() != 2) + throw std::runtime_error("Unexpected input: " + line); + + name_and_val[0].erase(name_and_val[0].size()-1); + name_and_val[1].erase(0, 1); + + std::string name = name_and_val[0], value = name_and_val[1]; + + inputs[name] = value; + + if(name == "H") + { + bool result = check(rng, inputs); + std::cout << "." << std::flush; + if(result == false) + { + std::cout << " Check failed\n"; + + std::map<std::string, std::string>::const_iterator i; + + for(i = inputs.begin(); i != inputs.end(); i++) + std::cout << i->first << " = " << i->second << "\n"; + + std::cout << "\n"; + } + + inputs.clear(); + } + } + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; + } + +bool check(RandomNumberGenerator& rng, + std::map<std::string, std::string> inputs) + { + BigInt p("0x"+inputs["P"]), + q("0x"+inputs["Q"]), + g("0x"+inputs["G"]), + h("0x"+inputs["H"]); + + if(h < 1 || h >= p-1) return false; + + //u32bit c = to_u32bit(inputs["c"]); + + Pipe pipe(new Hex_Decoder); + pipe.process_msg(inputs["Seed"]); + SecureVector<byte> seed = pipe.read_all(); + + BigInt our_p, our_q; + + u32bit qbits = (p.bits() <= 1024) ? 160 : 256; + + Algorithm_Factory& af = global_state().algorithm_factory(); + + bool found = generate_dsa_primes(rng, af, our_p, our_q, + p.bits(), qbits, seed); + + if(!found) /* bad seed */ + return false; + + if(our_p != p) return false; + if(our_q != q) return false; + + BigInt our_g = power_mod(h, (p-1)/q, p); + + if(our_g != g) return false; + + return true; + } diff --git a/examples/python/cipher.py b/examples/python/cipher.py new file mode 100755 index 000000000..1be2759ae --- /dev/null +++ b/examples/python/cipher.py @@ -0,0 +1,44 @@ +#!/usr/bin/python + +import botan +import sys + +def encrypt(input, passphrase): + rng = botan.RandomNumberGenerator() + + # Use as both EAX IV and PBKDF2 salt + salt = rng.gen_random(10) + + iterations = 10000 + output_size = 16 + + key = botan.pbkdf2(passphrase, salt, iterations, output_size, "SHA-1") + + encryptor = botan.Cipher("AES-128/EAX", "encrypt", key) + + ciphertext = encryptor.cipher(input, salt) + return (ciphertext, salt) + +def decrypt(input, salt, passphrase): + iterations = 10000 + output_size = 16 + + key = botan.pbkdf2(passphrase, salt, iterations, output_size, "SHA-1") + + decryptor = botan.Cipher("AES-128/EAX", "decrypt", key) + + return decryptor.cipher(input, salt) + +def main(args = None): + if args is None: + args = sys.argv + + passphrase = args[1] + input = ''.join(open(args[2]).readlines()) + + (ciphertext, salt) = encrypt(input, passphrase) + + print decrypt(ciphertext, salt, passphrase) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/examples/python/cryptobox.py b/examples/python/cryptobox.py new file mode 100755 index 000000000..f76ed6bc3 --- /dev/null +++ b/examples/python/cryptobox.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +import sys +import botan + +def main(args = None): + if args is None: + args = sys.argv + + if len(args) != 3: + raise Exception("Usage: <password> <input>"); + + password = args[1] + input = ''.join(open(args[2]).readlines()) + + rng = botan.RandomNumberGenerator() + + ciphertext = botan.cryptobox_encrypt(input, password, rng) + + print ciphertext + + plaintext = '' + + try: + plaintext = botan.cryptobox_decrypt(ciphertext, password + 'FAIL') + except Exception, e: + print "Good news: bad password caused exception: " + print e + + plaintext = botan.cryptobox_decrypt(ciphertext, password) + + print "Original input was: " + print plaintext + +if __name__ == '__main__': + sys.exit(main()) diff --git a/examples/python/nisttest.py b/examples/python/nisttest.py new file mode 100755 index 000000000..3ea8fda0f --- /dev/null +++ b/examples/python/nisttest.py @@ -0,0 +1,61 @@ +#!/usr/bin/python + +import sys, os, botan +from os.path import join; + +def validate(ca_certs, certs, crls, ee_certs): + store = botan.X509_Store() + for cert in certs: + if cert not in ee_certs: + store.add_cert(botan.X509_Certificate(cert), cert in ca_certs) + + for crl in crls: + r = store.add_crl(botan.X509_CRL(crl)) + if r != botan.verify_result.verified: + return r + + for ee in ee_certs: + r = store.validate(botan.X509_Certificate(ee)) + if r != botan.verify_result.verified: + return r + + return botan.verify_result.verified + +def run_test(files, rootdir, testname, expected): + crls = [join(rootdir,x) for x in files if x.endswith(".crl")] + certs = [join(rootdir,x) for x in files if x.endswith(".crt")] + end_entity = [x for x in certs if x.find("end.crt") != -1] + ca_certs = [x for x in certs if x.find("root.crt") != -1] + + print "%s..." % testname, + + result = validate(ca_certs, certs, crls, end_entity) + result = repr(result).replace('botan._botan.verify_result.', '') + + if result != expected: + print "FAILED: got %s, expected %s" % (result, expected) + else: + print "passed" + +def main(): + def load_results(file): + results = {} + for line in open(file, 'r'): + line = line[0:line.find('#')].strip() + if line: + test,result = line.split(' ') + results[test] = result + return results + + results = load_results('results.txt') + + for root, dirs, files in os.walk('../../checks/nist_tests/tests'): + if files: + thistest = root[root.rfind('/')+1:] + if thistest in results: + run_test(files, root, thistest, results[thistest]) + else: + print "%s... skipping - no expected result set" % thistest + +if __name__ == "__main__": + sys.exit(main()) diff --git a/examples/python/results.txt b/examples/python/results.txt new file mode 100644 index 000000000..7a3824001 --- /dev/null +++ b/examples/python/results.txt @@ -0,0 +1,60 @@ +# This is the file of expected results for nisttest.py +test01 verified +test02 signature_error +test03 signature_error +test04 verified +test05 cert_not_yet_valid +test06 cert_not_yet_valid +test07 verified +test08 cert_not_yet_valid +test09 cert_has_expired +test10 cert_has_expired +test11 cert_has_expired +test12 verified +test13 cert_issuer_not_found +test14 cert_issuer_not_found +test15 verified +test16 verified +test17 verified +test18 verified +# changed; should be no_revocation_data_available, but I don't want to +# force people to use CRLs +test19 verified +test20 cert_is_revoked +test21 cert_is_revoked +test22 ca_cert_not_for_cert_issuer +test23 ca_cert_not_for_cert_issuer +test24 verified +test25 ca_cert_not_for_cert_issuer +test26 verified +test27 verified +test28 ca_cert_not_for_cert_issuer +test29 ca_cert_not_for_cert_issuer +test30 verified +test31 ca_cert_not_for_crl_issuer +test32 ca_cert_not_for_crl_issuer +test33 verified +test54 cert_chain_too_long +test55 cert_chain_too_long +test56 verified +test57 verified +test58 cert_chain_too_long +test59 cert_chain_too_long +test60 cert_chain_too_long +test61 cert_chain_too_long +test62 verified +test63 verified +test64 signature_error +# changed; I have no idea why this test is supposed to fail +test65 verified +test66 crl_issuer_not_found +# changed; one of the CRLs has an unknown creator, so we fail +# prior to getting to the end-entity check +test67 crl_issuer_not_found +test68 cert_is_revoked +test69 cert_is_revoked +test70 cert_is_revoked +test71 cert_is_revoked +test72 crl_has_expired +test73 crl_has_expired +test74 verified diff --git a/examples/python/rng_test.py b/examples/python/rng_test.py new file mode 100755 index 000000000..06c79b84e --- /dev/null +++ b/examples/python/rng_test.py @@ -0,0 +1,22 @@ +#!/usr/bin/python + +import botan + +rng = botan.RandomNumberGenerator() + +print "name", rng.name() + +rng.add_entropy("blah") + +print "random 16", rng.gen_random(16).encode("hex") +print "random 32", rng.gen_random(32).encode("base64"), + +rng.reseed() + +for i in range(0, 10): + print rng.gen_random_byte(), +print + +rng.add_entropy("blah") + +print "random 16", rng.gen_random(16).encode("hex") diff --git a/examples/python/rsa.py b/examples/python/rsa.py new file mode 100755 index 000000000..8ca95ff8b --- /dev/null +++ b/examples/python/rsa.py @@ -0,0 +1,47 @@ +#!/usr/bin/python + +import botan + +def make_into_c_array(ber): + output = 'static unsigned char key_data[%d] = {\n\t' % (len(ber)) + + for (idx,c) in zip(range(len(ber)), ber): + if idx != 0 and idx % 8 == 0: + output += "\n\t" + output += "0x%s, " % (c.encode('hex')) + + output += "\n};\n" + + return output + +rng = botan.RandomNumberGenerator() + +rsa_priv = botan.RSA_PrivateKey(768, rng) + +print rsa_priv.to_string() +print int(rsa_priv.get_N()) +print int(rsa_priv.get_E()) + +rsa_pub = botan.RSA_PublicKey(rsa_priv) + +print make_into_c_array(rsa_pub.to_ber()) +#print make_into_c_array(rsa_priv.to_ber()) + +key = rng.gen_random(20) + +ciphertext = rsa_pub.encrypt(key, 'EME1(SHA-1)', rng) + +print ciphertext.encode('hex') + +plaintext = rsa_priv.decrypt(ciphertext, 'EME1(SHA-1)') + +print plaintext == key + +signature = rsa_priv.sign(key, 'EMSA4(SHA-256)', rng) + +print rsa_pub.verify(key, signature, 'EMSA4(SHA-256)') + +# Corrupt the signature, make sure it doesn't verify +signature = signature.replace(signature[0], '0') + +print rsa_pub.verify(key, signature, 'EMSA4(SHA-256)') diff --git a/examples/read_ssh.cpp b/examples/read_ssh.cpp new file mode 100644 index 000000000..f6299a29d --- /dev/null +++ b/examples/read_ssh.cpp @@ -0,0 +1,129 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +* Example of reading SSH2 format public keys (see RFC 4716) +*/ + +#include <fstream> +#include <botan/x509_key.h> +#include <botan/filters.h> +#include <botan/loadstor.h> +#include <botan/rsa.h> +#include <botan/dsa.h> + +using namespace Botan; + +namespace { + +u32bit read_u32bit(Pipe& pipe) + { + byte out[4] = { 0 }; + pipe.read(out, 4); + u32bit len = load_be<u32bit>(out, 0); + if(len > 10000) + throw Decoding_Error("Huge size in read_u32bit, something went wrong"); + return len; + } + +std::string read_string(Pipe& pipe) + { + u32bit len = read_u32bit(pipe); + + std::string out(len, 'X'); + pipe.read(reinterpret_cast<byte*>(&out[0]), len); + return out; + } + +BigInt read_bigint(Pipe& pipe) + { + u32bit len = read_u32bit(pipe); + + SecureVector<byte> buf(len); + pipe.read(&buf[0], len); + return BigInt::decode(buf); + } + +Public_Key* read_ssh_pubkey(const std::string& file) + { + std::ifstream in(file.c_str()); + + const std::string ssh_header = "---- BEGIN SSH2 PUBLIC KEY ----"; + const std::string ssh_trailer = "---- END SSH2 PUBLIC KEY ----"; + + std::string hex_bits; + + std::string line; + std::getline(in, line); + + if(line != ssh_header) + return 0; + + while(in.good()) + { + std::getline(in, line); + + if(line.find("Comment: ") == 0) + { + while(line[line.size()-1] == '\\') + std::getline(in, line); + std::getline(in, line); + } + + if(line == ssh_trailer) + break; + + hex_bits += line; + } + + Pipe pipe(new Base64_Decoder); + pipe.process_msg(hex_bits); + + std::string key_type = read_string(pipe); + + if(key_type != "ssh-rsa" && key_type != "ssh-dss") + return 0; + + if(key_type == "ssh-rsa") + { + BigInt e = read_bigint(pipe); + BigInt n = read_bigint(pipe); + return new RSA_PublicKey(n, e); + } + else if(key_type == "ssh-dss") + { + BigInt p = read_bigint(pipe); + BigInt q = read_bigint(pipe); + BigInt g = read_bigint(pipe); + BigInt y = read_bigint(pipe); + + return new DSA_PublicKey(DL_Group(p, q, g), y); + } + + return 0; + } + +} + +#include <botan/init.h> +#include <iostream> + +int main() + { + LibraryInitializer init; + + Public_Key* key = read_ssh_pubkey("dsa.ssh"); + + if(key == 0) + { + std::cout << "Failed\n"; + return 1; + } + + std::cout << X509::PEM_encode(*key); + + return 0; + } diff --git a/examples/readme.txt b/examples/readme.txt new file mode 100644 index 000000000..fb6a03ddf --- /dev/null +++ b/examples/readme.txt @@ -0,0 +1,77 @@ +This directory contains some simple example applications for the Botan crypto +library. If you want to see something a bit more complicated, check out the +stuff in the checks/ directory. Both it and the files in this directory are in +the public domain, and you may do with them however you please. + +The makefile assumes that you built the library with g++; you'll have to change +it if this assumption proves incorrect. + +Some of these examples will not build on all configurations of the library, +particularly 'bzip', 'encrypt', 'decrypt', and 'hash_fd', as they require +various extensions. + +The examples are fairly small (50-150 lines). And that's with argument +processing, I/O, error checking, etc (which counts for 40% or more of most of +them). This is partially to make them easy to understand, and partially because +I'm lazy. For the most part, the examples cover the stuff a 'regular' +application might need. + +Feel free to contribute new examples. You too can gain fame and fortune by +writing example apps for obscure libraries! + +The examples are: + +* X.509 examples +-------- +ca: A (very) simple CA application + +x509info: Prints some information about an X.509 certificate + +pkcs10: Generates a PKCS #10 certificate request for a 1024 bit RSA key + +self_sig: Generates a self-signed X.509v3 certificate with a 1024 bit RSA key +-------- + +* RSA examples (also uses X.509, PKCS #8, block ciphers, MACs, PBKDF algorithms) +-------- +rsa_kgen: Generate an RSA key, encrypt the private key with a passphrase, + output the keys to a pair of files +rsa_enc: Take a public key (generated by rsa_kgen) and encrypt a file + using CAST-128, MAC it with HMAC(SHA-1) +rsa_dec: Decrypt a file encrypted by rsa_enc + +* DSA examples (also uses X.509, PKCS #8) +-------- +dsa_kgen: Generates a DSA key, encrypts the private key with a passphrase + and stores it in PKCS #8 format. +dsa_sign: Produce a DSA signature for a file. Uses SHA-1 +dsa_ver: Verify a message signed with dsa_sign + +* Encryption examples +-------- +encrypt: Encrypt a file in CBC mode with a block cipher of your choice. Adds + a MAC for authentication, and compresses the plaintext with Zlib. + +decrypt: Decrypt the result of 'encrypt' + +xor_ciph: Shows how to add a new algorithm from application code + +* Hash function examples (also shows different methods of using Pipe) +-------- +hash: Print digests of files, using any chosen hash function + +hash_fd: Same as hash, except that it uses Unix file I/O. Requires the + pipe_unixfd extension + +hasher: Print MD5, SHA-1, and RIPEMD-160 digests of files + +hasher2: Same as hasher, just shows an alternate method + +stack: A demonstration of some more advanced Pipe functionality. Prints + MD5 hashes + +* Misc examples +-------- +base64: Simple base64 encoding/decoding tool + +bzip: Bzip2 compression/decompression. diff --git a/examples/rng_test.cpp b/examples/rng_test.cpp new file mode 100644 index 000000000..c0d24fd80 --- /dev/null +++ b/examples/rng_test.cpp @@ -0,0 +1,126 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/x931_rng.h> +#include <botan/hex.h> +#include <botan/lookup.h> + +#include <iostream> +#include <fstream> +#include <deque> +#include <stdexcept> + +using namespace Botan; + +namespace { + +class Fixed_Output_RNG : public RandomNumberGenerator + { + public: + bool is_seeded() const { return !buf.empty(); } + + byte random() + { + if(buf.empty()) + throw std::runtime_error("Out of bytes"); + + byte out = buf.front(); + buf.pop_front(); + return out; + } + + void randomize(byte out[], size_t len) throw() + { + for(size_t j = 0; j != len; j++) + out[j] = random(); + } + + std::string name() const { return "Fixed_Output_RNG"; } + + void reseed(size_t) {} + + void clear() throw() {} + + void add_entropy(const byte in[], size_t len) + { + buf.insert(buf.end(), in, in + len); + } + + void add_entropy_source(EntropySource* es) { delete es; } + + Fixed_Output_RNG() {} + private: + std::deque<byte> buf; + }; + +void x931_tests(std::vector<std::pair<std::string, std::string> > vecs, + const std::string& cipher) + { + for(size_t j = 0; j != vecs.size(); ++j) + { + const std::string result = vecs[j].first; + const std::string input = vecs[j].second; + + ANSI_X931_RNG prng(get_block_cipher(cipher), + new Fixed_Output_RNG); + + SecureVector<byte> x = hex_decode(input); + prng.add_entropy(x.begin(), x.size()); + + SecureVector<byte> output(result.size() / 2); + prng.randomize(output, output.size()); + + if(hex_decode(result) != output) + std::cout << "FAIL"; + else + std::cout << "PASS"; + + std::cout << " Seed " << input << " " + << "Got " << hex_encode(output) << " " + << "Exp " << result << "\n"; + } + + } + +std::vector<std::pair<std::string, std::string> > +read_file(const std::string& fsname) + { + std::ifstream in(fsname.c_str()); + + std::vector<std::pair<std::string, std::string> > out; + + while(in.good()) + { + std::string line; + std::getline(in, line); + + if(line == "") + break; + + std::vector<std::string> l = split_on(line, ':'); + + if(l.size() != 2) + throw std::runtime_error("Bad line " + line); + + out.push_back(std::make_pair(l[0], l[1])); + } + + return out; + } + +} + +int main() + { + Botan::LibraryInitializer init; + + x931_tests(read_file("ANSI931_AES128VST.txt.vst"), "AES-128"); + x931_tests(read_file("ANSI931_AES192VST.txt.vst"), "AES-192"); + x931_tests(read_file("ANSI931_AES256VST.txt.vst"), "AES-256"); + x931_tests(read_file("ANSI931_TDES2VST.txt.vst"), "TripleDES"); + x931_tests(read_file("ANSI931_TDES3VST.txt.vst"), "TripleDES"); + } diff --git a/examples/row_encryptor.cpp b/examples/row_encryptor.cpp new file mode 100644 index 000000000..685850945 --- /dev/null +++ b/examples/row_encryptor.cpp @@ -0,0 +1,171 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <string> +#include <memory> +#include <sstream> +#include <iostream> +#include <stdexcept> + +#include <botan/botan.h> +#include <botan/filters.h> +#include <botan/eax.h> + +using namespace Botan; + +/* +* Encrypt and decrypt small rows +*/ +class Row_Encryptor + { + public: + Row_Encryptor(const std::string& passphrase, + RandomNumberGenerator& rng); + + Row_Encryptor(const std::string& passphrase, + const MemoryRegion<byte>& salt); + + std::string encrypt(const std::string& input, + const MemoryRegion<byte>& salt); + + std::string decrypt(const std::string& input, + const MemoryRegion<byte>& salt); + + SecureVector<byte> get_pbkdf_salt() const { return pbkdf_salt; } + private: + void init(const std::string& passphrase); + + Row_Encryptor(const Row_Encryptor&) {} + Row_Encryptor& operator=(const Row_Encryptor&) { return (*this); } + + SecureVector<byte> pbkdf_salt; + Pipe enc_pipe, dec_pipe; + EAX_Encryption* eax_enc; // owned by enc_pipe + EAX_Decryption* eax_dec; // owned by dec_pipe; + }; + +Row_Encryptor::Row_Encryptor(const std::string& passphrase, + RandomNumberGenerator& rng) + { + pbkdf_salt.resize(10); // 80 bits + rng.randomize(&pbkdf_salt[0], pbkdf_salt.size()); + init(passphrase); + } + +Row_Encryptor::Row_Encryptor(const std::string& passphrase, + const MemoryRegion<byte>& salt) + { + pbkdf_salt = salt; + init(passphrase); + } + +void Row_Encryptor::init(const std::string& passphrase) + { + std::auto_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(SHA-160)")); + + SecureVector<byte> key = pbkdf->derive_key(32, passphrase, + &pbkdf_salt[0], pbkdf_salt.size(), + 10000).bits_of(); + + /* + Save pointers to the EAX objects so we can change the IV as needed + */ + + Algorithm_Factory& af = global_state().algorithm_factory(); + + const BlockCipher* proto = af.prototype_block_cipher("Serpent"); + + if(!proto) + throw std::runtime_error("Could not get a Serpent proto object"); + + enc_pipe.append(eax_enc = new EAX_Encryption(proto->clone())); + dec_pipe.append(eax_dec = new EAX_Decryption(proto->clone())); + + eax_enc->set_key(key); + eax_dec->set_key(key); + } + +std::string Row_Encryptor::encrypt(const std::string& input, + const MemoryRegion<byte>& salt) + { + eax_enc->set_iv(salt); + enc_pipe.process_msg(input); + return enc_pipe.read_all_as_string(Pipe::LAST_MESSAGE); + } + +std::string Row_Encryptor::decrypt(const std::string& input, + const MemoryRegion<byte>& salt) + { + eax_dec->set_iv(salt); + dec_pipe.process_msg(input); + return dec_pipe.read_all_as_string(Pipe::LAST_MESSAGE); + } + +/* +* Test code follows: +*/ + +int main() + { + Botan::LibraryInitializer init; + + AutoSeeded_RNG rng; + + const std::string secret_passphrase = "secret passphrase"; + + Row_Encryptor encryptor("secret passphrase", rng); + + std::vector<std::string> original_inputs; + + for(u32bit i = 0; i != 50000; ++i) + { + std::ostringstream out; + + u32bit output_bytes = rng.next_byte(); + + for(u32bit j = 0; j != output_bytes; ++j) + out << std::hex << (int)rng.next_byte(); + + original_inputs.push_back(out.str()); + } + + std::vector<std::string> encrypted_values; + MemoryVector<byte> salt(4); // keep out of loop to avoid excessive dynamic allocation + + for(u32bit i = 0; i != original_inputs.size(); ++i) + { + std::string input = original_inputs[i]; + + for(u32bit j = 0; j != 4; ++j) + salt[j] = (i >> 8) & 0xFF; + + encrypted_values.push_back(encryptor.encrypt(input, salt)); + } + + for(u32bit i = 0; i != encrypted_values.size(); ++i) + { + std::string ciphertext = encrypted_values[i]; + + // NOTE: same salt value as previous loop (index value) + for(u32bit j = 0; j != 4; ++j) + salt[j] = (i >> 8) & 0xFF; + + std::string output = encryptor.decrypt(ciphertext, salt); + + if(output != original_inputs[i]) + std::cout << "BOOM " << i << "\n"; + } + + Row_Encryptor test_pbkdf_salt_copy(secret_passphrase, + encryptor.get_pbkdf_salt()); + + zeroise(salt); + std::string test = test_pbkdf_salt_copy.decrypt(encrypted_values[0], salt); + if(test != original_inputs[0]) + std::cout << "PBKDF salt copy failed to decrypt properly\n"; + + return 0; + } diff --git a/examples/rsa_dec.cpp b/examples/rsa_dec.cpp new file mode 100644 index 000000000..81592328c --- /dev/null +++ b/examples/rsa_dec.cpp @@ -0,0 +1,129 @@ +/* +* (C) 2002-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Decrypt an encrypted RSA private key. Then use that key to decrypt a +message. This program can decrypt messages generated by rsa_enc, and uses the +same key format as that generated by rsa_kgen. +*/ + +#include <iostream> +#include <fstream> +#include <string> +#include <memory> + +#include <botan/botan.h> +#include <botan/pubkey.h> +#include <botan/rsa.h> +using namespace Botan; + +SecureVector<byte> b64_decode(const std::string&); +SymmetricKey derive_key(const std::string&, const SymmetricKey&, u32bit); + +const std::string SUFFIX = ".enc"; + +int main(int argc, char* argv[]) + { + if(argc != 4) + { + std::cout << "Usage: " << argv[0] << " keyfile messagefile passphrase" + << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + try + { + AutoSeeded_RNG rng; + + std::auto_ptr<PKCS8_PrivateKey> key( + PKCS8::load_key(argv[1], rng, argv[3])); + + RSA_PrivateKey* rsakey = dynamic_cast<RSA_PrivateKey*>(key.get()); + if(!rsakey) + { + std::cout << "The loaded key is not a RSA key!\n"; + return 1; + } + + std::ifstream message(argv[2]); + if(!message) + { + std::cout << "Couldn't read the message file." << std::endl; + return 1; + } + + std::string outfile(argv[2]); + outfile = outfile.replace(outfile.find(SUFFIX), SUFFIX.length(), ""); + + std::ofstream plaintext(outfile.c_str(), std::ios::binary); + if(!plaintext) + { + std::cout << "Couldn't write the plaintext to " + << outfile << std::endl; + return 1; + } + + std::string enc_masterkey_str; + std::getline(message, enc_masterkey_str); + std::string mac_str; + std::getline(message, mac_str); + + SecureVector<byte> enc_masterkey = b64_decode(enc_masterkey_str); + + PK_Decryptor_EME decryptor(*rsakey, "EME1(SHA-1)"); + + SecureVector<byte> masterkey = decryptor.decrypt(enc_masterkey); + + SymmetricKey cast_key = derive_key("CAST", masterkey, 16); + InitializationVector iv = derive_key("IV", masterkey, 8); + SymmetricKey mac_key = derive_key("MAC", masterkey, 16); + + Pipe pipe(new Base64_Decoder, + get_cipher("CAST-128/CBC/PKCS7", cast_key, iv, DECRYPTION), + new Fork( + 0, + new Chain( + new MAC_Filter("HMAC(SHA-1)", mac_key, 12), + new Base64_Encoder + ) + ) + ); + + pipe.start_msg(); + message >> pipe; + pipe.end_msg(); + + std::string our_mac = pipe.read_all_as_string(1); + + if(our_mac != mac_str) + std::cout << "WARNING: MAC in message failed to verify\n"; + + plaintext << pipe.read_all_as_string(0); + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + return 1; + } + return 0; + } + +SecureVector<byte> b64_decode(const std::string& in) + { + Pipe pipe(new Base64_Decoder); + pipe.process_msg(in); + return pipe.read_all(); + } + +SymmetricKey derive_key(const std::string& param, + const SymmetricKey& masterkey, + u32bit outputlength) + { + std::auto_ptr<KDF> kdf(get_kdf("KDF2(SHA-1)")); + return kdf->derive_key(outputlength, masterkey.bits_of(), param); + } diff --git a/examples/rsa_enc.cpp b/examples/rsa_enc.cpp new file mode 100644 index 000000000..ac609c4b3 --- /dev/null +++ b/examples/rsa_enc.cpp @@ -0,0 +1,151 @@ +/* +* (C) 2002 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* + Grab an RSA public key from the file given as an argument, grab a message + from another file, and encrypt the message. + + Algorithms used: + RSA with EME1(SHA-1) padding to encrypt the master key + CAST-128 in CBC mode with PKCS#7 padding to encrypt the message. + HMAC with SHA-1 is used to authenticate the message + + The keys+IV used are derived from the master key (the thing that's encrypted + with RSA) using KDF2(SHA-1). The 3 outputs of KDF2 are parameterized by P, + where P is "CAST", "IV" or "MAC", in order to make each key/IV unique. + + The format is: + 1) First line is the master key, encrypted with the recipients public key + using EME1(SHA-1), and then base64 encoded. + 2) Second line is the first 96 bits (12 bytes) of the HMAC(SHA-1) of + the _plaintext_ + 3) Following lines are base64 encoded ciphertext (CAST-128 as described), + each broken after ~72 characters. +*/ + +#include <iostream> +#include <fstream> +#include <string> +#include <memory> + +#include <botan/botan.h> +#include <botan/pubkey.h> +#include <botan/rsa.h> +using namespace Botan; + +std::string b64_encode(const SecureVector<byte>&); +SymmetricKey derive_key(const std::string&, const SymmetricKey&, u32bit); + +int main(int argc, char* argv[]) + { + if(argc != 3) + { + std::cout << "Usage: " << argv[0] << " keyfile messagefile" << std::endl; + return 1; + } + + std::ifstream message(argv[2], std::ios::binary); + if(!message) + { + std::cout << "Couldn't read the message file." << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + std::string output_name(argv[2]); + output_name += ".enc"; + std::ofstream ciphertext(output_name.c_str()); + if(!ciphertext) + { + std::cout << "Couldn't write the ciphertext to " << output_name + << std::endl; + return 1; + } + + try { + std::auto_ptr<X509_PublicKey> key(X509::load_key(argv[1])); + RSA_PublicKey* rsakey = dynamic_cast<RSA_PublicKey*>(key.get()); + if(!rsakey) + { + std::cout << "The loaded key is not a RSA key!\n"; + return 1; + } + + AutoSeeded_RNG rng; + + PK_Encryptor_EME encryptor(*rsakey, "EME1(SHA-1)"); + + /* Generate the master key (the other keys are derived from this) + + Basically, make the key as large as can be encrypted by this key, up + to a limit of 256 bits. For 512 bit keys, the master key will be >160 + bits. A >600 bit key will use the full 256 bit master key. + + In theory, this is not enough, because we derive 16+16+8=40 bytes of + secrets (if you include the IV) using the master key, so they are not + statistically indepedent. Practically speaking I don't think this is + a problem. + */ + SymmetricKey masterkey(rng, + std::min<size_t>(32, + encryptor.maximum_input_size())); + + SymmetricKey cast_key = derive_key("CAST", masterkey, 16); + SymmetricKey mac_key = derive_key("MAC", masterkey, 16); + SymmetricKey iv = derive_key("IV", masterkey, 8); + + SecureVector<byte> encrypted_key = + encryptor.encrypt(masterkey.bits_of(), rng); + + ciphertext << b64_encode(encrypted_key) << std::endl; + + Pipe pipe(new Fork( + new Chain( + get_cipher("CAST-128/CBC/PKCS7", cast_key, iv, + ENCRYPTION), + new Base64_Encoder(true) // true == do linebreaking + ), + new Chain( + new MAC_Filter("HMAC(SHA-1)", mac_key, 12), + new Base64_Encoder + ) + ) + ); + + pipe.start_msg(); + message >> pipe; + pipe.end_msg(); + + /* Write the MAC as the second line. That way we can pull it off right + from the start, and feed the rest of the file right into a pipe on the + decrypting end. + */ + + ciphertext << pipe.read_all_as_string(1) << std::endl; + ciphertext << pipe.read_all_as_string(0); + } + catch(std::exception& e) + { + std::cout << "Exception: " << e.what() << std::endl; + } + return 0; + } + +std::string b64_encode(const SecureVector<byte>& in) + { + Pipe pipe(new Base64_Encoder); + pipe.process_msg(in); + return pipe.read_all_as_string(); + } + +SymmetricKey derive_key(const std::string& param, + const SymmetricKey& masterkey, + u32bit outputlength) + { + std::auto_ptr<KDF> kdf(get_kdf("KDF2(SHA-1)")); + return kdf->derive_key(outputlength, masterkey.bits_of(), param); + } diff --git a/examples/rsa_kgen.cpp b/examples/rsa_kgen.cpp new file mode 100644 index 000000000..f4566263b --- /dev/null +++ b/examples/rsa_kgen.cpp @@ -0,0 +1,66 @@ +/* +* (C) 2002 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Generate an RSA key of a specified bitlength, and put it into a pair of key +files. One is the public key in X.509 format (PEM encoded), the private key is +in PKCS #8 format (also PEM encoded). +*/ + +#include <iostream> +#include <fstream> +#include <string> +#include <cstdlib> +#include <memory> + +#include <botan/botan.h> +#include <botan/rsa.h> +using namespace Botan; + +int main(int argc, char* argv[]) + { + if(argc != 2 && argc != 3) + { + std::cout << "Usage: " << argv[0] << " bitsize [passphrase]" + << std::endl; + return 1; + } + + u32bit bits = std::atoi(argv[1]); + if(bits < 1024 || bits > 16384) + { + std::cout << "Invalid argument for bitsize" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + std::ofstream pub("rsapub.pem"); + std::ofstream priv("rsapriv.pem"); + if(!priv || !pub) + { + std::cout << "Couldn't write output files" << std::endl; + return 1; + } + + try + { + AutoSeeded_RNG rng; + + RSA_PrivateKey key(rng, bits); + pub << X509::PEM_encode(key); + + if(argc == 2) + priv << PKCS8::PEM_encode(key); + else + priv << PKCS8::PEM_encode(key, rng, argv[2]); + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + } + return 0; + } diff --git a/examples/rsa_manykey.cpp b/examples/rsa_manykey.cpp new file mode 100644 index 000000000..e6a511753 --- /dev/null +++ b/examples/rsa_manykey.cpp @@ -0,0 +1,42 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Generate a whole sequence of keys (for benchmarking) +*/ + +#include <iostream> +#include <fstream> +#include <string> +#include <cstdlib> +#include <memory> + +#include <botan/botan.h> +#include <botan/rsa.h> +#include <botan/parsing.h> +using namespace Botan; + +int main() + { + Botan::LibraryInitializer init; + + AutoSeeded_RNG rng; + + for(u32bit j = 512; j <= 8192; j += 256) + { + std::cout << j << "..."; + + RSA_PrivateKey key(rng, j); + + std::ofstream priv(("rsa/" + to_string(j) + ".pem").c_str()); + priv << PKCS8::PEM_encode(key); + priv.close(); + + std::cout << " done" << std::endl; + } + + return 0; + } diff --git a/examples/self_sig.cpp b/examples/self_sig.cpp new file mode 100644 index 000000000..6710cfb51 --- /dev/null +++ b/examples/self_sig.cpp @@ -0,0 +1,83 @@ +/* +* (C) 2003 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +Generate a 1024 bit RSA key, and then create a self-signed X.509v3 +certificate with that key. If the do_CA variable is set to true, then +it will be marked for CA use, otherwise it will get extensions +appropriate for use with a client certificate. The private key is +stored as an encrypted PKCS #8 object in another file. +*/ + +#include <botan/botan.h> +#include <botan/x509self.h> +#include <botan/rsa.h> +#include <botan/dsa.h> +using namespace Botan; + +#include <iostream> +#include <fstream> +#include <memory> + +int main(int argc, char* argv[]) + { + if(argc != 7) + { + std::cout << "Usage: " << argv[0] + << " passphrase [CA|user] name country_code organization email" + << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + std::string CA_flag = argv[2]; + bool do_CA = false; + + if(CA_flag == "CA") do_CA = true; + else if(CA_flag == "user") do_CA = false; + else + { + std::cout << "Bad flag for CA/user switch: " << CA_flag << std::endl; + return 1; + } + + try + { + AutoSeeded_RNG rng; + + RSA_PrivateKey key(rng, 1024); + + std::ofstream priv_key("private.pem"); + priv_key << PKCS8::PEM_encode(key, rng, argv[1]); + + X509_Cert_Options opts; + + opts.common_name = argv[3]; + opts.country = argv[4]; + opts.organization = argv[5]; + opts.email = argv[6]; + /* Fill in other values of opts here */ + + //opts.xmpp = "[email protected]"; + + if(do_CA) + opts.CA_key(); + + X509_Certificate cert = + X509::create_self_signed_cert(opts, key, "SHA-256", rng); + + std::ofstream cert_file("cert.pem"); + cert_file << cert.PEM_encode(); + } + catch(std::exception& e) + { + std::cout << "Exception: " << e.what() << std::endl; + return 1; + } + + return 0; + } diff --git a/examples/sig_gen.cpp b/examples/sig_gen.cpp new file mode 100644 index 000000000..cf273216a --- /dev/null +++ b/examples/sig_gen.cpp @@ -0,0 +1,96 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> +#include <map> +#include <memory> + +#include <botan/botan.h> +#include <botan/dsa.h> +#include <botan/pubkey.h> +using namespace Botan; + +bool check(std::map<std::string, std::string>); + +int main() + { + try { + Botan::LibraryInitializer init; + + std::ifstream in("SigGen.rsp"); + if(!in) + throw Exception("Can't open response file"); + + std::map<std::string, std::string> inputs; + + while(in.good()) + { + std::string line; + std::getline(in, line); + + if(line == "" || line[0] == '[' || line[0] == '#') + continue; + + std::vector<std::string> name_and_val = split_on(line, '='); + + if(name_and_val.size() != 2) + throw Decoding_Error("Unexpected input: " + line); + + name_and_val[0].erase(name_and_val[0].size()-1); + name_and_val[1].erase(0, 1); + + std::string name = name_and_val[0], value = name_and_val[1]; + + inputs[name] = value; + + if(name == "S") + { + bool result = check(inputs); + if(result == false) + { + std::cout << " Check failed\n"; + + std::map<std::string, std::string>::const_iterator i; + + for(i = inputs.begin(); i != inputs.end(); i++) + std::cout << i->first << " = " << i->second << "\n"; + } + inputs["Msg"] = inputs["R"] = inputs["S"] = ""; + } + } + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; + } + +bool check(std::map<std::string, std::string> inputs) + { + BigInt p("0x"+inputs["P"]), + q("0x"+inputs["Q"]), + g("0x"+inputs["G"]), + y("0x"+inputs["Y"]); + + DSA_PublicKey key(DL_Group(p, q, g), y); + + Pipe pipe(new Hex_Decoder); + + pipe.process_msg(inputs["Msg"]); + pipe.start_msg(); + pipe.write(inputs["R"]); + pipe.write(inputs["S"] ); + pipe.end_msg(); + + PK_Verifier verifier(key, "EMSA1(SHA-1)"); + + return verifier.verify_message(pipe.read_all(0), pipe.read_all(1)); + } diff --git a/examples/stack.cpp b/examples/stack.cpp new file mode 100644 index 000000000..0c00ed183 --- /dev/null +++ b/examples/stack.cpp @@ -0,0 +1,88 @@ +/* +* (C) 2002 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +/* +An Botan example application showing how to use the pop and prepend +functions of Pipe. Based on the md5 example. It's output should always +be identical to such. +*/ + +#include <iostream> +#include <fstream> +#include <botan/botan.h> + +int main(int argc, char* argv[]) + { + if(argc < 2) + { + std::cout << "Usage: " << argv[0] << " <filenames>" << std::endl; + return 1; + } + + Botan::LibraryInitializer init; + + // this is a pretty vacuous example, but it's useful as a test + Botan::Pipe pipe; + + // CPS == Current Pipe Status, ie what Filters are set up + + pipe.prepend(new Botan::Hash_Filter("MD5")); + // CPS: MD5 + + pipe.prepend(new Botan::Hash_Filter("RIPEMD-160")); + // CPS: RIPEMD-160 | MD5 + + pipe.prepend(new Botan::Chain( + new Botan::Hash_Filter("RIPEMD-160"), + new Botan::Hash_Filter("RIPEMD-160"))); + // CPS: (RIPEMD-160 | RIPEMD-160) | RIPEMD-160 | MD5 + + pipe.pop(); // will pop everything inside the Chain as well as Chain itself + // CPS: RIPEMD-160 | MD5 + + pipe.pop(); // will get rid of the RIPEMD-160 Hash_Filter + // CPS: MD5 + + pipe.prepend(new Botan::Hash_Filter("SHA-1")); + // CPS: SHA-1 | MD5 + + pipe.append(new Botan::Hex_Encoder); + // CPS: SHA-1 | MD5 | Hex_Encoder + + pipe.prepend(new Botan::Hash_Filter("SHA-1")); + // CPS: SHA-1 | SHA-1 | MD5 | Hex_Encoder + + pipe.pop(); // Get rid of the Hash_Filter(SHA-1) + pipe.pop(); // Get rid of the other Hash_Filter(SHA-1) + // CPS: MD5 | Hex_Encoder + // The Hex_Encoder is safe because it is at the end of the Pipe, + // and pop() pulls off the Filter that is at the start. + + pipe.prepend(new Botan::Hash_Filter("RIPEMD-160")); + // CPS: RIPEMD-160 | MD5 | Hex_Encoder + + pipe.pop(); // Get rid of that last prepended Hash_Filter(RIPEMD-160) + // CPS: MD5 | Hex_Encoder + + int skipped = 0; + for(int j = 1; argv[j] != 0; j++) + { + std::ifstream file(argv[j], std::ios::binary); + if(!file) + { + std::cout << "ERROR: could not open " << argv[j] << std::endl; + skipped++; + continue; + } + pipe.start_msg(); + file >> pipe; + pipe.end_msg(); + file.close(); + pipe.set_default_msg(j-1-skipped); + std::cout << pipe << " " << argv[j] << std::endl; + } + return 0; + } diff --git a/examples/tls_client.cpp b/examples/tls_client.cpp new file mode 100644 index 000000000..10ead20cc --- /dev/null +++ b/examples/tls_client.cpp @@ -0,0 +1,96 @@ +/* +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/init.h> +#include <botan/tls_client.h> +#include <botan/unx_sock.h> + +using namespace Botan; + +#include <stdio.h> +#include <string> +#include <iostream> +#include <memory> + +class Client_TLS_Policy : public TLS_Policy + { + public: + bool check_cert(const std::vector<X509_Certificate>& certs) const + { + for(size_t i = 0; i != certs.size(); ++i) + { + std::cout << certs[i].to_string(); + } + + std::cout << "Warning: not checking cert signatures\n"; + + return true; + } + }; + +int main(int argc, char* argv[]) + { + if(argc != 2 && argc != 3) + { + printf("Usage: %s host [port]\n", argv[0]); + return 1; + } + + try + { + LibraryInitializer init; + + std::string host = argv[1]; + u32bit port = argc == 3 ? Botan::to_u32bit(argv[2]) : 443; + + printf("Connecting to %s:%d...\n", host.c_str(), port); + + Unix_Socket sock(argv[1], port); + + std::auto_ptr<Botan::RandomNumberGenerator> rng( + Botan::RandomNumberGenerator::make_rng()); + + Client_TLS_Policy policy; + + TLS_Client tls(std::tr1::bind(&Socket::read, std::tr1::ref(sock), _1, _2), + std::tr1::bind(&Socket::write, std::tr1::ref(sock), _1, _2), + policy, *rng); + + printf("Handshake extablished...\n"); + +#if 0 + std::string http_command = "GET / HTTP/1.1\r\n" + "Server: " + host + ':' + to_string(port) + "\r\n\r\n"; +#else + std::string http_command = "GET / HTTP/1.0\r\n\r\n"; +#endif + + tls.write((const byte*)http_command.c_str(), http_command.length()); + + u32bit total_got = 0; + + while(true) + { + if(tls.is_closed()) + break; + + byte buf[16+1] = { 0 }; + u32bit got = tls.read(buf, sizeof(buf)-1); + printf("%s", buf); + fflush(0); + + total_got += got; + } + + printf("\nRetrieved %d bytes total\n", total_got); + } + catch(std::exception& e) + { + printf("%s\n", e.what()); + return 1; + } + return 0; + } diff --git a/examples/tls_server.cpp b/examples/tls_server.cpp new file mode 100644 index 000000000..da13953f8 --- /dev/null +++ b/examples/tls_server.cpp @@ -0,0 +1,108 @@ +/* +* (C) 2008-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/tls_server.h> +#include <botan/unx_sock.h> + +#include <botan/rsa.h> +#include <botan/dsa.h> +#include <botan/x509self.h> + +using namespace Botan; + +#include <stdio.h> +#include <string> +#include <iostream> +#include <memory> + +class Server_TLS_Policy : public TLS_Policy + { + public: + bool check_cert(const std::vector<X509_Certificate>& certs) const + { + for(size_t i = 0; i != certs.size(); ++i) + { + std::cout << certs[i].to_string(); + } + + std::cout << "Warning: not checking cert signatures\n"; + + return true; + } + }; +int main(int argc, char* argv[]) + { + + int port = 4433; + + if(argc == 2) + port = to_u32bit(argv[1]); + + try + { + LibraryInitializer init; + + AutoSeeded_RNG rng; + + //RSA_PrivateKey key(rng, 1024); + DSA_PrivateKey key(rng, DL_Group("dsa/jce/1024")); + + X509_Cert_Options options( + "localhost/US/Syn Ack Labs/Mathematical Munitions Dept"); + + X509_Certificate cert = + X509::create_self_signed_cert(options, key, "SHA-1", rng); + + Unix_Server_Socket listener(port); + + Server_TLS_Policy policy; + + while(true) + { + try { + printf("Listening for new connection on port %d\n", port); + + Socket* sock = listener.accept(); + + printf("Got new connection\n"); + + TLS_Server tls( + std::tr1::bind(&Socket::read, std::tr1::ref(sock), _1, _2), + std::tr1::bind(&Socket::write, std::tr1::ref(sock), _1, _2), + policy, + rng, + cert, + key); + + std::string hostname = tls.requested_hostname(); + + if(hostname != "") + printf("Client requested host '%s'\n", hostname.c_str()); + + printf("Writing some text\n"); + + char msg[] = "Foo\nBar\nBaz\nQuux\n"; + tls.write((const byte*)msg, strlen(msg)); + + printf("Now trying a read...\n"); + + char buf[1024] = { 0 }; + u32bit got = tls.read((byte*)buf, sizeof(buf)-1); + printf("%d: '%s'\n", got, buf); + + tls.close(); + } + catch(std::exception& e) { printf("%s\n", e.what()); } + } + } + catch(std::exception& e) + { + printf("%s\n", e.what()); + return 1; + } + return 0; + } diff --git a/examples/toolbox.cpp b/examples/toolbox.cpp new file mode 100644 index 000000000..622a1f56f --- /dev/null +++ b/examples/toolbox.cpp @@ -0,0 +1,235 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> + +#if defined(BOTAN_HAS_COMPRESSOR_BZIP2) + #include <botan/bzip2.h> +#endif + +#if defined(BOTAN_HAS_COMPRESSOR_ZLIB) + #include <botan/zlib.h> +#endif + +#include <iostream> +#include <fstream> + +using namespace Botan; + +#include "../../checks/getopt.h" + +class Encoder_Decoder + { + public: + Encoder_Decoder(const std::string& command, + bool decode, + const std::vector<std::string>& args) : + type(command), + args(args), + decode(decode) + { } + + void run(std::istream& in, std::ostream& out) + { + Filter* filt = decode ? decoder(type) : encoder(type); + + DataSource_Stream src(in); + Pipe pipe(filt, new DataSink_Stream(out)); + pipe.process_msg(src); + } + + Filter* encoder(const std::string& type) const + { + if(type == "hex") return new Hex_Encoder; + if(type == "base64") return new Base64_Encoder; + +#if defined(BOTAN_HAS_COMPRESSOR_BZIP2) + if(type == "bzip2") return new Bzip_Compression; +#endif + +#if defined(BOTAN_HAS_COMPRESSOR_ZLIB) + if(type == "zlib") return new Zlib_Compression; +#endif + return 0; + } + + Filter* decoder(const std::string& type) const + { + if(type == "hex") return new Hex_Decoder; + if(type == "base64") return new Base64_Decoder; + +#if defined(BOTAN_HAS_COMPRESSOR_BZIP2) + if(type == "bzip2") return new Bzip_Decompression; +#endif + +#if defined(BOTAN_HAS_COMPRESSOR_ZLIB) + if(type == "zlib") return new Zlib_Decompression; +#endif + + return 0; + } + + private: + std::string type; + std::vector<std::string> args; + bool decode; + }; + +void run_command(const std::string& command, + const std::vector<std::string>& arguments, + const OptionParser& opts) + { + if(command == "hex" || + command == "base64" || + command == "bzip2" || + command == "zlib") + { + bool decode = opts.is_set("decode"); + + std::string output = opts.value_or_else("output", "-"); + std::string input = opts.value_or_else("input", "-"); + + Encoder_Decoder enc_dec(command, decode, arguments); + + try + { + if(output == "-") + { + if(input == "-") + enc_dec.run(std::cin, std::cout); + else + { + std::ifstream in(input.c_str()); + enc_dec.run(in, std::cout); + } + } + else // output != "-" + { + std::ofstream out(output.c_str()); + + if(input == "-") + enc_dec.run(std::cin, out); + else + { + std::ifstream in(input.c_str()); + enc_dec.run(in, out); + } + } + } + catch(Botan::Stream_IO_Error& e) + { + std::cout << "I/O failure - " << e.what() << '\n'; + } + } + else if(command == "hash" || + command == "sha1" || + command == "md5") + { + std::string hash; + + if(command == "md5") + hash = "MD5"; + if(command == "sha1") + hash = "SHA-160"; + else + hash = opts.value_or_else("hash", "SHA-160"); // sha1 is default + + Pipe pipe(new Hash_Filter(get_hash(hash)), + new Hex_Encoder(false, 0, Hex_Encoder::Lowercase)); + + for(size_t i = 0; i != arguments.size(); ++i) + { + std::string file_name = arguments[i]; + + u32bit previously = pipe.message_count(); + + if(file_name == "-") + { + pipe.start_msg(); + std::cin >> pipe; + pipe.end_msg(); + } + else + { + std::ifstream in(file_name.c_str()); + if(in) + { + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + } + else + std::cerr << "Could not read " << file_name << '\n'; + } + + if(pipe.message_count() > previously) + std::cout << pipe.read_all_as_string(Pipe::LAST_MESSAGE) << " " + << file_name << '\n'; + } + + } + else + { + std::cerr << "Command " << command << " not known\n"; + } + } + +int main(int argc, char* argv[]) + { + LibraryInitializer init; + + OptionParser opts("help|version|seconds=|" + "input=|output=|decode|" + "hash=|key="); + + try + { + opts.parse(argv); + } + catch(std::runtime_error& e) + { + std::cout << "Command line problem: " << e.what() << '\n'; + return 2; + } + + if(opts.is_set("version") || argc <= 1) + { + std::cerr << "Botan Toolbox v" << version_string() << '\n'; + std::cerr << "Commands: hash hex base64 "; +#if defined(BOTAN_HAS_COMPRESSOR_BZIP2) + std::cerr << "bzip2 "; +#endif + +#if defined(BOTAN_HAS_COMPRESSOR_ZLIB) + std::cerr << "zlib "; +#endif + + std::cerr << "\n"; + + return 0; + } + + if(opts.is_set("help")) + { + std::vector<std::string> what = opts.leftovers(); + + for(size_t i = 0; i != what.size(); ++i) + std::cerr << what[i] << "? Never heard of it\n"; + return 0; + } + + std::vector<std::string> args = opts.leftovers(); + + if(args.size() == 0) + return 0; + + std::string command = args[0]; + args.erase(args.begin()); + + run_command(command, args, opts); + + return 0; + } diff --git a/examples/tss.cpp b/examples/tss.cpp new file mode 100644 index 000000000..03d7699bf --- /dev/null +++ b/examples/tss.cpp @@ -0,0 +1,44 @@ +/* +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/tss.h> +#include <iostream> +#include <stdio.h> + +namespace { + +void print(const Botan::SecureVector<Botan::byte>& r) + { + for(Botan::u32bit i = 0; i != r.size(); ++i) + printf("%02X", r[i]); + printf("\n"); + } + +} + +int main() + { + using namespace Botan; + + LibraryInitializer init; + + AutoSeeded_RNG rng; + + byte id[16]; + for(int i = 0; i != 16; ++i) + id[i] = i; + + const byte S2[] = { 0xDE, 0xAD, 0xCA, 0xFE, 0xBA, 0xBE, 0xBE, 0xEF }; + + std::vector<RTSS_Share> shares = + RTSS_Share::split(4, 6, S2, sizeof(S2), id, rng); + + for(size_t i = 0; i != shares.size(); ++i) + std::cout << i << " = " << shares[i].to_string() << "\n"; + + print(RTSS_Share::reconstruct(shares)); + } diff --git a/examples/x509info.cpp b/examples/x509info.cpp new file mode 100644 index 000000000..b22b4ebd8 --- /dev/null +++ b/examples/x509info.cpp @@ -0,0 +1,35 @@ +/* +* Read an X.509 certificate, and print various things about it +* (C) 2003 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/botan.h> +#include <botan/x509cert.h> +using namespace Botan; + +#include <iostream> + +int main(int argc, char* argv[]) + { + if(argc != 2) + { + std::cout << "Usage: " << argv[0] << " <x509cert>\n"; + return 1; + } + + Botan::LibraryInitializer init; + + try { + X509_Certificate cert(argv[1]); + + std::cout << cert.to_string(); + } + catch(std::exception& e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; + } |