aboutsummaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/examples/GNUmakefile21
-rw-r--r--doc/examples/asn1.cpp312
-rw-r--r--doc/examples/base64.cpp80
-rw-r--r--doc/examples/bcrypt.cpp45
-rw-r--r--doc/examples/bench.cpp107
-rw-r--r--doc/examples/benchmark.cpp46
-rw-r--r--doc/examples/bzip.cpp116
-rw-r--r--doc/examples/ca.cpp76
-rw-r--r--doc/examples/cert_verify.cpp35
-rw-r--r--doc/examples/checksum.cpp37
-rw-r--r--doc/examples/cms_dec.cpp120
-rw-r--r--doc/examples/cms_enc.cpp59
-rw-r--r--doc/examples/cpuid.cpp46
-rw-r--r--doc/examples/cryptobox.cpp53
-rw-r--r--doc/examples/decrypt.cpp173
-rw-r--r--doc/examples/dh.cpp62
-rw-r--r--doc/examples/dsa_kgen.cpp58
-rw-r--r--doc/examples/dsa_sign.cpp81
-rw-r--r--doc/examples/dsa_ver.cpp98
-rw-r--r--doc/examples/eax_test.cpp251
-rw-r--r--doc/examples/eax_tv.txt461
-rw-r--r--doc/examples/ecdsa.cpp61
-rw-r--r--doc/examples/encrypt.cpp193
-rw-r--r--doc/examples/encrypt2.cpp66
-rw-r--r--doc/examples/factor.cpp154
-rw-r--r--doc/examples/fpe.cpp151
-rw-r--r--doc/examples/gen_certs.cpp134
-rw-r--r--doc/examples/gtk/Makefile18
-rw-r--r--doc/examples/gtk/dsa.cpp566
-rw-r--r--doc/examples/gtk/gtk_ui.cpp79
-rw-r--r--doc/examples/gtk/gtk_ui.h27
-rw-r--r--doc/examples/gtk/readme.txt18
-rw-r--r--doc/examples/hash.cpp58
-rw-r--r--doc/examples/hash_fd.cpp70
-rw-r--r--doc/examples/hash_quickly.cpp98
-rw-r--r--doc/examples/hasher.cpp55
-rw-r--r--doc/examples/hasher2.cpp75
-rw-r--r--doc/examples/keywrap.cpp38
-rw-r--r--doc/examples/make_prime.cpp79
-rw-r--r--doc/examples/new_engine.cpp106
-rw-r--r--doc/examples/package.cpp70
-rw-r--r--doc/examples/passhash.cpp50
-rw-r--r--doc/examples/pkcs10.cpp70
-rw-r--r--doc/examples/pqg_gen.cpp121
-rwxr-xr-xdoc/examples/python/cipher.py44
-rwxr-xr-xdoc/examples/python/cryptobox.py36
-rwxr-xr-xdoc/examples/python/nisttest.py61
-rw-r--r--doc/examples/python/results.txt60
-rwxr-xr-xdoc/examples/python/rng_test.py22
-rwxr-xr-xdoc/examples/python/rsa.py47
-rw-r--r--doc/examples/read_ssh.cpp129
-rw-r--r--doc/examples/readme.txt77
-rw-r--r--doc/examples/rng_test.cpp126
-rw-r--r--doc/examples/row_encryptor.cpp171
-rw-r--r--doc/examples/rsa_dec.cpp129
-rw-r--r--doc/examples/rsa_enc.cpp151
-rw-r--r--doc/examples/rsa_kgen.cpp66
-rw-r--r--doc/examples/rsa_manykey.cpp42
-rw-r--r--doc/examples/self_sig.cpp83
-rw-r--r--doc/examples/sig_gen.cpp96
-rw-r--r--doc/examples/socket.h211
-rw-r--r--doc/examples/stack.cpp88
-rw-r--r--doc/examples/tls_client.cpp96
-rw-r--r--doc/examples/tls_server.cpp109
-rw-r--r--doc/examples/toolbox.cpp235
-rw-r--r--doc/examples/tss.cpp44
-rw-r--r--doc/examples/x509info.cpp35
-rw-r--r--doc/pubkey.txt135
68 files changed, 6916 insertions, 71 deletions
diff --git a/doc/examples/GNUmakefile b/doc/examples/GNUmakefile
new file mode 100644
index 000000000..c386f4390
--- /dev/null
+++ b/doc/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/doc/examples/asn1.cpp b/doc/examples/asn1.cpp
new file mode 100644
index 000000000..b0a6aa104
--- /dev/null
+++ b/doc/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/doc/examples/base64.cpp b/doc/examples/base64.cpp
new file mode 100644
index 000000000..dbe8d19e3
--- /dev/null
+++ b/doc/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/doc/examples/bcrypt.cpp b/doc/examples/bcrypt.cpp
new file mode 100644
index 000000000..27a98cf33
--- /dev/null
+++ b/doc/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/doc/examples/bench.cpp b/doc/examples/bench.cpp
new file mode 100644
index 000000000..20e6ec40b
--- /dev/null
+++ b/doc/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/doc/examples/benchmark.cpp b/doc/examples/benchmark.cpp
new file mode 100644
index 000000000..7ad1775e2
--- /dev/null
+++ b/doc/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/doc/examples/bzip.cpp b/doc/examples/bzip.cpp
new file mode 100644
index 000000000..6137bb6af
--- /dev/null
+++ b/doc/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/doc/examples/ca.cpp b/doc/examples/ca.cpp
new file mode 100644
index 000000000..8dd3e981f
--- /dev/null
+++ b/doc/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/doc/examples/cert_verify.cpp b/doc/examples/cert_verify.cpp
new file mode 100644
index 000000000..04bcbecad
--- /dev/null
+++ b/doc/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/doc/examples/checksum.cpp b/doc/examples/checksum.cpp
new file mode 100644
index 000000000..dba7a7d70
--- /dev/null
+++ b/doc/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/doc/examples/cms_dec.cpp b/doc/examples/cms_dec.cpp
new file mode 100644
index 000000000..84355fb4a
--- /dev/null
+++ b/doc/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/doc/examples/cms_enc.cpp b/doc/examples/cms_enc.cpp
new file mode 100644
index 000000000..2cf813987
--- /dev/null
+++ b/doc/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/doc/examples/cpuid.cpp b/doc/examples/cpuid.cpp
new file mode 100644
index 000000000..6d4cc7593
--- /dev/null
+++ b/doc/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/doc/examples/cryptobox.cpp b/doc/examples/cryptobox.cpp
new file mode 100644
index 000000000..38d750d17
--- /dev/null
+++ b/doc/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/doc/examples/decrypt.cpp b/doc/examples/decrypt.cpp
new file mode 100644
index 000000000..ea510c5e9
--- /dev/null
+++ b/doc/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/doc/examples/dh.cpp b/doc/examples/dh.cpp
new file mode 100644
index 000000000..8489df8fe
--- /dev/null
+++ b/doc/examples/dh.cpp
@@ -0,0 +1,62 @@
+#include <botan/botan.h>
+#include <botan/dh.h>
+#include <botan/pubkey.h>
+using namespace Botan;
+
+#include <iostream>
+#include <memory>
+
+int main()
+ {
+ try
+ {
+ LibraryInitializer init;
+
+ AutoSeeded_RNG rng;
+
+ // Alice and Bob agree on a DH domain to use
+ DL_Group shared_domain("modp/ietf/2048");
+
+ // Alice creates a DH key
+ DH_PrivateKey private_a(rng, shared_domain);
+
+ // Bob creates a key with a matching group
+ DH_PrivateKey private_b(rng, shared_domain);
+
+ // Alice sends to Bob her public key and a session parameter
+ MemoryVector<byte> public_a = private_a.public_value();
+ const std::string session_param =
+ "Alice and Bob's shared session parameter";
+
+ // Bob sends his public key to Alice
+ MemoryVector<byte> public_b = private_b.public_value();
+
+ // Now Alice performs the key agreement operation
+ PK_Key_Agreement ka_alice(private_a, "KDF2(SHA-256)");
+ SymmetricKey alice_key = ka1.derive_key(32, public_b, session_param);
+
+ // Bob does the same:
+ PK_Key_Agreement ka_bob(private_b, "KDF2(SHA-256)");
+ SymmetricKey bob_key = ka2.derive_key(32, public_a, session_param);
+
+ 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/doc/examples/dsa_kgen.cpp b/doc/examples/dsa_kgen.cpp
new file mode 100644
index 000000000..fe3157370
--- /dev/null
+++ b/doc/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/doc/examples/dsa_sign.cpp b/doc/examples/dsa_sign.cpp
new file mode 100644
index 000000000..5f02c0dc1
--- /dev/null
+++ b/doc/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/doc/examples/dsa_ver.cpp b/doc/examples/dsa_ver.cpp
new file mode 100644
index 000000000..a666259c1
--- /dev/null
+++ b/doc/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/doc/examples/eax_test.cpp b/doc/examples/eax_test.cpp
new file mode 100644
index 000000000..32311800d
--- /dev/null
+++ b/doc/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/doc/examples/eax_tv.txt b/doc/examples/eax_tv.txt
new file mode 100644
index 000000000..95cd7c1ab
--- /dev/null
+++ b/doc/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/doc/examples/ecdsa.cpp b/doc/examples/ecdsa.cpp
new file mode 100644
index 000000000..df1e1b93a
--- /dev/null
+++ b/doc/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/doc/examples/encrypt.cpp b/doc/examples/encrypt.cpp
new file mode 100644
index 000000000..28017d875
--- /dev/null
+++ b/doc/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/doc/examples/encrypt2.cpp b/doc/examples/encrypt2.cpp
new file mode 100644
index 000000000..41f4fb478
--- /dev/null
+++ b/doc/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/doc/examples/factor.cpp b/doc/examples/factor.cpp
new file mode 100644
index 000000000..58b12d9a5
--- /dev/null
+++ b/doc/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/doc/examples/fpe.cpp b/doc/examples/fpe.cpp
new file mode 100644
index 000000000..9b18d4879
--- /dev/null
+++ b/doc/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/doc/examples/gen_certs.cpp b/doc/examples/gen_certs.cpp
new file mode 100644
index 000000000..f8c9fe124
--- /dev/null
+++ b/doc/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/doc/examples/gtk/Makefile b/doc/examples/gtk/Makefile
new file mode 100644
index 000000000..10e069bb3
--- /dev/null
+++ b/doc/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/doc/examples/gtk/dsa.cpp b/doc/examples/gtk/dsa.cpp
new file mode 100644
index 000000000..2cd91b0e8
--- /dev/null
+++ b/doc/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/doc/examples/gtk/gtk_ui.cpp b/doc/examples/gtk/gtk_ui.cpp
new file mode 100644
index 000000000..d4e9cd238
--- /dev/null
+++ b/doc/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/doc/examples/gtk/gtk_ui.h b/doc/examples/gtk/gtk_ui.h
new file mode 100644
index 000000000..065a4f76b
--- /dev/null
+++ b/doc/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/doc/examples/gtk/readme.txt b/doc/examples/gtk/readme.txt
new file mode 100644
index 000000000..4f3691166
--- /dev/null
+++ b/doc/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/doc/examples/hash.cpp b/doc/examples/hash.cpp
new file mode 100644
index 000000000..1a4ca1b64
--- /dev/null
+++ b/doc/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/doc/examples/hash_fd.cpp b/doc/examples/hash_fd.cpp
new file mode 100644
index 000000000..32acdbec3
--- /dev/null
+++ b/doc/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/doc/examples/hash_quickly.cpp b/doc/examples/hash_quickly.cpp
new file mode 100644
index 000000000..005a6d719
--- /dev/null
+++ b/doc/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/doc/examples/hasher.cpp b/doc/examples/hasher.cpp
new file mode 100644
index 000000000..e5c52ba55
--- /dev/null
+++ b/doc/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/doc/examples/hasher2.cpp b/doc/examples/hasher2.cpp
new file mode 100644
index 000000000..b6303b644
--- /dev/null
+++ b/doc/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/doc/examples/keywrap.cpp b/doc/examples/keywrap.cpp
new file mode 100644
index 000000000..730bcb6c9
--- /dev/null
+++ b/doc/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/doc/examples/make_prime.cpp b/doc/examples/make_prime.cpp
new file mode 100644
index 000000000..acaaac698
--- /dev/null
+++ b/doc/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/doc/examples/new_engine.cpp b/doc/examples/new_engine.cpp
new file mode 100644
index 000000000..42e5dbe33
--- /dev/null
+++ b/doc/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/doc/examples/package.cpp b/doc/examples/package.cpp
new file mode 100644
index 000000000..02cf52816
--- /dev/null
+++ b/doc/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/doc/examples/passhash.cpp b/doc/examples/passhash.cpp
new file mode 100644
index 000000000..586c28c3f
--- /dev/null
+++ b/doc/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/doc/examples/pkcs10.cpp b/doc/examples/pkcs10.cpp
new file mode 100644
index 000000000..3f5ec8e05
--- /dev/null
+++ b/doc/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/doc/examples/pqg_gen.cpp b/doc/examples/pqg_gen.cpp
new file mode 100644
index 000000000..c033dac3b
--- /dev/null
+++ b/doc/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/doc/examples/python/cipher.py b/doc/examples/python/cipher.py
new file mode 100755
index 000000000..1be2759ae
--- /dev/null
+++ b/doc/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/doc/examples/python/cryptobox.py b/doc/examples/python/cryptobox.py
new file mode 100755
index 000000000..f76ed6bc3
--- /dev/null
+++ b/doc/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/doc/examples/python/nisttest.py b/doc/examples/python/nisttest.py
new file mode 100755
index 000000000..3ea8fda0f
--- /dev/null
+++ b/doc/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/doc/examples/python/results.txt b/doc/examples/python/results.txt
new file mode 100644
index 000000000..7a3824001
--- /dev/null
+++ b/doc/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/doc/examples/python/rng_test.py b/doc/examples/python/rng_test.py
new file mode 100755
index 000000000..06c79b84e
--- /dev/null
+++ b/doc/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/doc/examples/python/rsa.py b/doc/examples/python/rsa.py
new file mode 100755
index 000000000..8ca95ff8b
--- /dev/null
+++ b/doc/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/doc/examples/read_ssh.cpp b/doc/examples/read_ssh.cpp
new file mode 100644
index 000000000..f6299a29d
--- /dev/null
+++ b/doc/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/doc/examples/readme.txt b/doc/examples/readme.txt
new file mode 100644
index 000000000..fb6a03ddf
--- /dev/null
+++ b/doc/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/doc/examples/rng_test.cpp b/doc/examples/rng_test.cpp
new file mode 100644
index 000000000..c0d24fd80
--- /dev/null
+++ b/doc/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/doc/examples/row_encryptor.cpp b/doc/examples/row_encryptor.cpp
new file mode 100644
index 000000000..685850945
--- /dev/null
+++ b/doc/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/doc/examples/rsa_dec.cpp b/doc/examples/rsa_dec.cpp
new file mode 100644
index 000000000..81592328c
--- /dev/null
+++ b/doc/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/doc/examples/rsa_enc.cpp b/doc/examples/rsa_enc.cpp
new file mode 100644
index 000000000..ac609c4b3
--- /dev/null
+++ b/doc/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/doc/examples/rsa_kgen.cpp b/doc/examples/rsa_kgen.cpp
new file mode 100644
index 000000000..f4566263b
--- /dev/null
+++ b/doc/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/doc/examples/rsa_manykey.cpp b/doc/examples/rsa_manykey.cpp
new file mode 100644
index 000000000..e6a511753
--- /dev/null
+++ b/doc/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/doc/examples/self_sig.cpp b/doc/examples/self_sig.cpp
new file mode 100644
index 000000000..6710cfb51
--- /dev/null
+++ b/doc/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/doc/examples/sig_gen.cpp b/doc/examples/sig_gen.cpp
new file mode 100644
index 000000000..cf273216a
--- /dev/null
+++ b/doc/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/doc/examples/socket.h b/doc/examples/socket.h
new file mode 100644
index 000000000..c4fa46600
--- /dev/null
+++ b/doc/examples/socket.h
@@ -0,0 +1,211 @@
+/*
+* Unix Socket
+* (C) 2004-2010 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef SOCKET_WRAPPER_H__
+#define SOCKET_WRAPPER_H__
+
+#include <stdexcept>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+class Socket
+ {
+ public:
+ size_t read(unsigned char[], size_t);
+ void write(const unsigned char[], size_t);
+
+ std::string peer_id() const { return peer; }
+
+ void close()
+ {
+ if(sockfd != -1)
+ {
+ if(::close(sockfd) != 0)
+ throw std::runtime_error("Socket::close failed");
+ sockfd = -1;
+ }
+ }
+
+ Socket(int fd, const std::string& peer_id = "") :
+ peer(peer_id), sockfd(fd)
+ {
+ }
+
+ Socket(const std::string&, unsigned short);
+ ~Socket() { close(); }
+ private:
+ std::string peer;
+ int sockfd;
+ };
+
+class Server_Socket
+ {
+ public:
+ /**
+ * Accept a new connection
+ */
+ Socket* accept()
+ {
+ int retval = ::accept(sockfd, 0, 0);
+ if(retval == -1)
+ throw std::runtime_error("Server_Socket: accept failed");
+ return new Socket(retval);
+ }
+
+ void close()
+ {
+ if(sockfd != -1)
+ {
+ if(::close(sockfd) != 0)
+ throw std::runtime_error("Server_Socket::close failed");
+ sockfd = -1;
+ }
+ }
+
+ Server_Socket(unsigned short);
+ ~Server_Socket() { close(); }
+ private:
+ int sockfd;
+ };
+
+/**
+* Unix Socket Constructor
+*/
+Socket::Socket(const std::string& host, unsigned short port) : peer(host)
+ {
+ sockfd = -1;
+
+ hostent* host_addr = ::gethostbyname(host.c_str());
+
+ if(host_addr == 0)
+ throw std::runtime_error("Socket: gethostbyname failed for " + host);
+ if(host_addr->h_addrtype != AF_INET) // FIXME
+ throw std::runtime_error("Socket: " + host + " has IPv6 address");
+
+ int fd = ::socket(PF_INET, SOCK_STREAM, 0);
+ if(fd == -1)
+ throw std::runtime_error("Socket: Unable to acquire socket");
+
+ sockaddr_in socket_info;
+ ::memset(&socket_info, 0, sizeof(socket_info));
+ socket_info.sin_family = AF_INET;
+ socket_info.sin_port = htons(port);
+
+ ::memcpy(&socket_info.sin_addr,
+ host_addr->h_addr,
+ host_addr->h_length);
+
+ socket_info.sin_addr = *(struct in_addr*)host_addr->h_addr; // FIXME
+
+ if(::connect(fd, (sockaddr*)&socket_info, sizeof(struct sockaddr)) != 0)
+ {
+ ::close(fd);
+ throw std::runtime_error("Socket: connect failed");
+ }
+
+ sockfd = fd;
+ }
+
+/**
+* Read from a Unix socket
+*/
+size_t Socket::read(unsigned char buf[], size_t length)
+ {
+ if(sockfd == -1)
+ throw std::runtime_error("Socket::read: Socket not connected");
+
+ size_t got = 0;
+
+ while(length)
+ {
+ ssize_t this_time = ::recv(sockfd, buf + got, length, MSG_NOSIGNAL);
+
+ if(this_time == 0)
+ break;
+
+ if(this_time == -1)
+ {
+ if(errno == EINTR)
+ this_time = 0;
+ else
+ throw std::runtime_error("Socket::read: Socket read failed");
+ }
+
+ got += this_time;
+ length -= this_time;
+ }
+ return got;
+ }
+
+/**
+* Write to a Unix socket
+*/
+void Socket::write(const unsigned char buf[], size_t length)
+ {
+ if(sockfd == -1)
+ throw std::runtime_error("Socket::write: Socket not connected");
+
+ size_t offset = 0;
+ while(length)
+ {
+ ssize_t sent = ::send(sockfd, buf + offset, length, MSG_NOSIGNAL);
+
+ if(sent == -1)
+ {
+ if(errno == EINTR)
+ sent = 0;
+ else
+ throw std::runtime_error("Socket::write: Socket write failed");
+ }
+
+ offset += sent;
+ length -= sent;
+ }
+ }
+
+/**
+* Unix Server Socket Constructor
+*/
+Server_Socket::Server_Socket(unsigned short port)
+ {
+ sockfd = -1;
+
+ int fd = ::socket(PF_INET, SOCK_STREAM, 0);
+ if(fd == -1)
+ throw std::runtime_error("Server_Socket: Unable to acquire socket");
+
+ sockaddr_in socket_info;
+ ::memset(&socket_info, 0, sizeof(socket_info));
+ socket_info.sin_family = AF_INET;
+ socket_info.sin_port = htons(port);
+
+ // FIXME: support limiting listeners
+ socket_info.sin_addr.s_addr = INADDR_ANY;
+
+ if(::bind(fd, (sockaddr*)&socket_info, sizeof(struct sockaddr)) != 0)
+ {
+ ::close(fd);
+ throw std::runtime_error("Server_Socket: bind failed");
+ }
+
+ if(listen(fd, 100) != 0) // FIXME: totally arbitrary
+ {
+ ::close(fd);
+ throw std::runtime_error("Server_Socket: listen failed");
+ }
+
+ sockfd = fd;
+ }
+
+#endif
diff --git a/doc/examples/stack.cpp b/doc/examples/stack.cpp
new file mode 100644
index 000000000..0c00ed183
--- /dev/null
+++ b/doc/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/doc/examples/tls_client.cpp b/doc/examples/tls_client.cpp
new file mode 100644
index 000000000..9f6f6229a
--- /dev/null
+++ b/doc/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 "socket.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);
+
+ 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/doc/examples/tls_server.cpp b/doc/examples/tls_server.cpp
new file mode 100644
index 000000000..087ba86fa
--- /dev/null
+++ b/doc/examples/tls_server.cpp
@@ -0,0 +1,109 @@
+/*
+* (C) 2008-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/botan.h>
+#include <botan/tls_server.h>
+
+#include <botan/rsa.h>
+#include <botan/dsa.h>
+#include <botan/x509self.h>
+
+#include "socket.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);
+
+ 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/doc/examples/toolbox.cpp b/doc/examples/toolbox.cpp
new file mode 100644
index 000000000..622a1f56f
--- /dev/null
+++ b/doc/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/doc/examples/tss.cpp b/doc/examples/tss.cpp
new file mode 100644
index 000000000..03d7699bf
--- /dev/null
+++ b/doc/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/doc/examples/x509info.cpp b/doc/examples/x509info.cpp
new file mode 100644
index 000000000..b22b4ebd8
--- /dev/null
+++ b/doc/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;
+ }
diff --git a/doc/pubkey.txt b/doc/pubkey.txt
index 1be471e1b..254880f65 100644
--- a/doc/pubkey.txt
+++ b/doc/pubkey.txt
@@ -99,8 +99,9 @@ predefined ``BigInt`` private key value is different:
constructors described above, to match the integer modulo prime
versions. Only use them if you really need them.
+.. _serializing_private_keys:
-Serializing Private Keys
+Serializing Private Keys Using PKCS #8
----------------------------------------
The standard format for serializing a private key is PKCS #8, the
@@ -157,7 +158,16 @@ decrypt, if necessary) a PKCS #8 private key:
.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, RandomNumberGenerator& rng, const std::string& passphrase = "")
-The result is an object allocated using ``new``.
+These functions will return an object allocated key object based on
+the data from whatever source it is using (assuming, of course, the
+source is in fact storing a representation of a private key, and the
+decryption was sucessful). The encoding used (PEM or BER) need not be
+specified; the format will be detected automatically. The key is
+allocated with ``new``, and should be released with ``delete`` when
+you are done with it. The first takes a generic ``DataSource`` that
+you have to create - the other is a simple wrapper functions that take
+either a filename or a memory buffer and create the appropriate
+``DataSource``.
The versions that pass the passphrase as a ``std::string`` are
primarily for compatibility, but they are useful in limited
@@ -179,6 +189,25 @@ passphrase passed in first, and then it cancels.
In a future version, it is likely that ``User_Interface`` will be
replaced by a simple callback using ``std::function``.
+Serializing Public Keys
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To import and export public keys, use:
+
+.. cpp:function:: MemoryVector<byte> X509::BER_encode(const Public_Key& key)
+
+.. cpp:function:: std::string X509::PEM_encode(const Public_Key& key)
+
+.. cpp:function:: Public_Key* X509::load_key(DataSource& in)
+
+.. cpp:function:: Public_Key* X509::load_key(const SecureVector<byte>& buffer)
+
+.. cpp:function:: Public_Key* X509::load_key(const std::string& filename)
+
+ These functions operate in the same way as the ones described in
+ :ref:`serializing_private_keys`, except that no encryption option is
+ availabe.
+
.. _dl_group:
DL_Group
@@ -224,7 +253,7 @@ You can generate a new random group using
bits. If the *type* is ``Prime_Subgroup`` or ``DSA_Kosherizer``,
then *qbits* specifies the size of the subgroup.
-You can export a ``DL_Group`` using
+You can serialize a ``DL_Group`` using
.. cpp:function:: SecureVector<byte> DL_Group::DER_Encode(Format format)
@@ -232,13 +261,28 @@ or
.. cpp:function:: std::string DL_Group::PEM_encode(Format format)
-where *format* is any of
+where *format* is any of
+
+* ``ANSI_X9_42`` (or ``DH_PARAMETERS``) for modp groups
+* ``ANSI_X9_57`` (or ``DSA_PARAMETERS``) for DSA-style groups
+* ``PKCS_3`` is an older format for modp groups; it should only
+ be used for backwards compatability.
+
+You can reload a serialized group using
+
+.. cpp:function:: void DL_Group::BER_decode(DataSource& source, Format format)
+
+.. cpp:function:: void DL_Group::PEM_decode(DataSource& source)
.. _ec_dompar:
EC_Domain_Params
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+An ``EC_Domain_Params`` is initialized by passing the name of the
+group to be used to the constructor. These groups have
+semi-standardized names like "secp256r1" and "brainpool512r1".
+
Key Checking
---------------------------------
@@ -246,22 +290,20 @@ Most public key algorithms have limitations or restrictions on their
parameters. For example RSA requires an odd exponent, and algorithms
based on the discrete logarithm problem need a generator $> 1$.
-Each low-level public key type has a function named ``check_key`` that
-takes a ``bool``. This function returns a Boolean value that declares
-whether or not the key is valid (from an algorithmic standpoint). For
-example, it will check to make sure that the prime parameters of a DSA
-key are, in fact, prime. It does not have anything to do with the
-validity of the key for any particular use, nor does it have anything
-to do with certificates that link a key (which, after all, is just
-some numbers) with a user or other entity. If ``check_key``'s argument
-is ``true``, then it does "strong" checking, which includes expensive
-operations like primality checking.
-
-Keys are always checked when they are loaded or generated, so typically there
-is no reason to use this function directly. However, you can disable or reduce
-the checks for particular cases (public keys, loaded private keys, generated
-private keys) by setting the right config toggle (see the section on the
-configuration subsystem for details).
+Each public key type has a function
+
+.. cpp:function:: bool Public_Key::check_key(RandomNumberGenerator& rng, bool strong)
+
+ This function performs a number of algorithm-specific tests that the
+ key seems to be mathematically valid and consistent, and returns
+ true if all of the tests pass.
+
+ It does not have anything to do with the validity of the key for any
+ particular use, nor does it have anything to do with certificates
+ that link a key (which, after all, is just some numbers) with a user
+ or other entity. If *strong* is ``true``, then it does "strong"
+ checking, which includes expensive operations like primality
+ checking.
Getting a PK algorithm object
---------------------------------
@@ -423,55 +465,6 @@ in new applications. The X9.42 algorithm may be useful in some
circumstances, but unless you need X9.42 compatibility, KDF2 is easier
to use.
-There is a Diffie-Hellman example included in the distribution, which you may
-want to examine.
-
-.. _pk_import_export:
-
-Importing and Exporting Keys
----------------------------------
-
-There are many, many different (often conflicting) standards
-surrounding public key cryptography. There is, thankfully, only two
-major standards surrounding the representation of a public or private
-key: the X.509 subject public key info format (for public keys), and
-PKCS #8 (for private keys). Other crypto libraries, such as Crypto++
-and OpenSSL, also support these formats, so you can easily exchange
-keys with software that doesn't use Botan.
-
-In addition to "plain" public keys, Botan also supports X.509
-certificates. These are documented in :ref:`x509_certificates`.
-
-.. _import_export_public_keys:
-
-Importing/Exporting Public Keys
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To import and export public keys, use:
-
-.. cpp:function:: MemoryVector<byte> X509::BER_encode(const Public_Key& key)
-
-
-.. cpp:function:: std::string X509::PEM_encode(const Public_Key& key)
-
-
-.. cpp:function:: Public_Key* X509::load_key(DataSource& in)
-
-.. cpp:function:: Public_Key* X509::load_key(const SecureVector<byte>& buffer)
-
-.. cpp:function:: Public_Key* X509::load_key(const std::string& filename)
-
- For loading a public key, use one of the variants of ``load_key``.
- This function will return a newly allocated key based on the data
- from whatever source it is using (assuming, of course, the source is
- in fact storing a representation of a public key). The encoding used
- (PEM or BER) need not be specified; the format will be detected
- automatically. The key is allocated with ``new``, and should be
- released with ``delete`` when you are done with it. The first takes
- a generic ``DataSource`` that you have to create - the other is a
- simple wrapper functions that take either a filename or a memory
- buffer and create the appropriate ``DataSource``.
-
-Importing/Exporting Private Keys
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+An example of using Diffie-Hellman:
+.. literalinclude:: examples/dh.cpp