aboutsummaryrefslogtreecommitdiffstats
path: root/doc/examples
diff options
context:
space:
mode:
Diffstat (limited to 'doc/examples')
-rw-r--r--doc/examples/Makefile124
-rw-r--r--doc/examples/asn1.cpp294
-rw-r--r--doc/examples/base.cpp30
-rw-r--r--doc/examples/base64.cpp81
-rw-r--r--doc/examples/bzip.cpp102
-rw-r--r--doc/examples/ca.cpp65
-rw-r--r--doc/examples/decrypt.cpp158
-rw-r--r--doc/examples/dh.cpp54
-rw-r--r--doc/examples/dsa_kgen.cpp57
-rw-r--r--doc/examples/dsa_sign.cpp79
-rw-r--r--doc/examples/dsa_ver.cpp94
-rw-r--r--doc/examples/encrypt.cpp175
-rw-r--r--doc/examples/fips140.cpp59
-rw-r--r--doc/examples/hash.cpp64
-rw-r--r--doc/examples/hash_fd.cpp70
-rw-r--r--doc/examples/hasher.cpp58
-rw-r--r--doc/examples/hasher2.cpp72
-rw-r--r--doc/examples/pkcs10.cpp68
-rw-r--r--doc/examples/readme.txt77
-rw-r--r--doc/examples/rsa_dec.cpp122
-rw-r--r--doc/examples/rsa_enc.cpp149
-rw-r--r--doc/examples/rsa_kgen.cpp55
-rw-r--r--doc/examples/self_sig.cpp76
-rw-r--r--doc/examples/stack.cpp86
-rw-r--r--doc/examples/x509info.cpp142
-rw-r--r--doc/examples/xor_ciph.cpp95
26 files changed, 2506 insertions, 0 deletions
diff --git a/doc/examples/Makefile b/doc/examples/Makefile
new file mode 100644
index 000000000..351d802da
--- /dev/null
+++ b/doc/examples/Makefile
@@ -0,0 +1,124 @@
+# Assumes Botan was compiled with GCC
+
+BOTAN_DIR = ../..
+
+CXX = g++
+WARNINGS = -ansi -W -Wall
+#CXX = icc
+#WARNINGS = -w1
+
+INCLUDES = `$(BOTAN_DIR)/botan-config --cflags`
+LIBS = `$(BOTAN_DIR)/botan-config --libs`
+FLAGS = $(INCLUDES) $(WARNINGS) -I$(BOTAN_DIR)/build/include -L$(BOTAN_DIR)
+
+X509_EX = ca pkcs10 self_sig x509info asn1
+RSA_EX = rsa_kgen rsa_enc rsa_dec
+DSA_EX = dsa_kgen dsa_sign dsa_ver
+DH_EX = dh
+HASH_EX = hash hash_fd hasher hasher2 stack
+MISC_EX = base base64 bzip encrypt decrypt fips140 xor_ciph
+
+PROGS = $(X509_EX) $(RSA_EX) $(DSA_EX) $(DH_EX) $(HASH_EX) $(MISC_EX)
+
+STRIP = true
+
+all: $(PROGS)
+
+clean:
+ @rm -f $(PROGS)
+
+asn1: asn1.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+base: base.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+base64: base64.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+bzip: bzip.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+ca: ca.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+decrypt: decrypt.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+dh: dh.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+dsa_kgen: dsa_kgen.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+dsa_sign: dsa_sign.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+dsa_ver: dsa_ver.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+encrypt: encrypt.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+fips140: fips140.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+hash: hash.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+hash_fd: hash_fd.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+hasher: hasher.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+hasher2: hasher2.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+pkcs10: pkcs10.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+rsa_dec: rsa_dec.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+rsa_enc: rsa_enc.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+rsa_kgen: rsa_kgen.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+self_sig: self_sig.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+stack: stack.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+x509info: x509info.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
+xor_ciph: xor_ciph.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
diff --git a/doc/examples/asn1.cpp b/doc/examples/asn1.cpp
new file mode 100644
index 000000000..91fb995e1
--- /dev/null
+++ b/doc/examples/asn1.cpp
@@ -0,0 +1,294 @@
+/*
+ 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
+
+ This file is in the public domain.
+*/
+
+/*******************************************************************/
+
+// 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/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;
+ }
+
+ try {
+ LibraryInitializer init;
+
+ 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) + "]";
+ 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;
+ BER::decode(data, oid);
+ emit(type_name(type_tag), level, length, OIDS::lookup(oid));
+ }
+ else if(type_tag == INTEGER)
+ {
+ BigInt number;
+ BER::decode(data, 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;
+ BER::decode(data, 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;
+ BER::decode(data, 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;
+ BER::decode(data, 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;
+ BER::decode(data, str);
+ if(UTF8_TERMINAL)
+ emit(type_name(type_tag), level, length, iso2utf(str.iso_8859()));
+ else
+ emit(type_name(type_tag), level, length, str.iso_8859());
+ }
+ else if(type_tag == UTC_TIME || type_tag == GENERALIZED_TIME)
+ {
+ X509_Time time;
+ BER::decode(data, 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/base.cpp b/doc/examples/base.cpp
new file mode 100644
index 000000000..5a1328ccf
--- /dev/null
+++ b/doc/examples/base.cpp
@@ -0,0 +1,30 @@
+/*
+ A simple template for Botan applications, showing startup, etc
+*/
+#include <botan/botan.h>
+using namespace Botan;
+
+/* This is how you can do compile-time version checking */
+/*
+#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,3,9)
+ #error Your Botan installation is too old; upgrade to 1.3.9 or later
+#endif
+*/
+
+#include <iostream>
+
+int main()
+ {
+ try {
+ /* Put it inside the try block so exceptions at startup/shutdown will
+ get caught.
+ */
+ LibraryInitializer init;
+ }
+ catch(std::exception& e)
+ {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+ return 0;
+ }
diff --git a/doc/examples/base64.cpp b/doc/examples/base64.cpp
new file mode 100644
index 000000000..c1260b8f4
--- /dev/null
+++ b/doc/examples/base64.cpp
@@ -0,0 +1,81 @@
+/*
+An Botan example application which emulates a poorly written version of
+"uuencode -m"
+
+Written by Jack Lloyd ([email protected]), in maybe an hour scattered
+over 2000/2001
+
+This file is in the public domain
+*/
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <cstring>
+#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/bzip.cpp b/doc/examples/bzip.cpp
new file mode 100644
index 000000000..46ac8abce
--- /dev/null
+++ b/doc/examples/bzip.cpp
@@ -0,0 +1,102 @@
+/*
+An Botan example application which emulates a poorly written version of bzip2
+
+Written by Jack Lloyd ([email protected]), Jun 9, 2001
+
+This file is in the public domain
+*/
+#include <string>
+#include <cstring>
+#include <vector>
+#include <fstream>
+#include <iostream>
+#include <botan/botan.h>
+
+#if defined(BOTAN_EXT_COMPRESSOR_BZIP2)
+ #include <botan/bzip2.h>
+#else
+ #error "You didn't compile the bzip module into Botan"
+#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;
+ if(decompress)
+ bzip = new Botan::Bzip_Decompression(small);
+ else
+ bzip = new Botan::Bzip_Compression(level);
+
+ 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::ofstream out(outfile.c_str());
+ 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..fbc637bbc
--- /dev/null
+++ b/doc/examples/ca.cpp
@@ -0,0 +1,65 @@
+/*
+ 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
+
+ Written by Jack Lloyd, May 19, 2003
+
+ This file is in the public domain.
+*/
+
+#include <botan/botan.h>
+#include <botan/x509_ca.h>
+using namespace Botan;
+
+#include <iostream>
+
+#define DOUCH_BAG CESSATION_OF_OPERATION
+
+int main(int argc, char* argv[])
+ {
+ if(argc != 2)
+ {
+ std::cout << "Usage: " << argv[0] << " passphrase" << std::endl;
+ return 1;
+ }
+
+ try {
+ LibraryInitializer init;
+
+ // set up our CA
+ X509_Certificate ca_cert("cacert.pem");
+ std::auto_ptr<PKCS8_PrivateKey> privkey(
+ PKCS8::load_key("caprivate.pem", argv[1])
+ );
+ X509_CA ca(ca_cert, *privkey);
+
+ // got a request
+ PKCS10_Request req("req.pem");
+
+ // presumably attempt to verify the req for sanity/accuracy here, but
+ // as Verisign, etc have shown, that's not a must. :)
+
+ // now sign it
+ X509_Certificate new_cert = ca.sign_request(req);
+
+ // send the new cert back to the requestor
+ std::cout << new_cert.PEM_encode();
+
+ std::vector<CRL_Entry> revoked_certs;
+ revoked_certs.push_back(CRL_Entry(new_cert, DOUCH_BAG));
+ X509_CRL crl = ca.update_crl(ca.new_crl(), revoked_certs);
+ std::cout << crl.PEM_encode();
+ }
+ catch(std::exception& e)
+ {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+ return 0;
+ }
diff --git a/doc/examples/decrypt.cpp b/doc/examples/decrypt.cpp
new file mode 100644
index 000000000..84490cb1b
--- /dev/null
+++ b/doc/examples/decrypt.cpp
@@ -0,0 +1,158 @@
+/*
+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.
+
+Written by Jack Lloyd ([email protected]) on August 5, 2002
+
+This file is in the public domain
+*/
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <cstring>
+
+#include <botan/botan.h>
+
+#if defined(BOTAN_EXT_COMPRESSOR_ZLIB)
+ #include <botan/zlib.h>
+#else
+ #error "You didn't compile the zlib module into Botan"
+#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;
+ }
+
+ 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 {
+
+ LibraryInitializer init;
+
+ 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;
+ }
+
+ if(!have_block_cipher(algo))
+ {
+ std::cout << "Don't know about the block cipher \"" << algo << "\"\n";
+ return 1;
+ }
+
+ const u32bit key_len = max_keylength_of(algo);
+ const u32bit iv_len = block_size_of(algo);
+
+ std::auto_ptr<S2K> s2k(get_s2k("PBKDF2(SHA-1)"));
+ s2k->set_iterations(8192);
+ s2k->change_salt(b64_decode(salt_str));
+
+ SymmetricKey bc_key = s2k->derive_key(key_len, "BLK" + passphrase);
+ InitializationVector iv = s2k->derive_key(iv_len, "IVL" + passphrase);
+ SymmetricKey mac_key = s2k->derive_key(16, "MAC" + passphrase);
+
+ Pipe pipe(new Base64_Decoder,
+ get_cipher(algo + "/CBC", bc_key, iv, DECRYPTION),
+ new Zlib_Decompression,
+ 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..8dcc93f88
--- /dev/null
+++ b/doc/examples/dh.cpp
@@ -0,0 +1,54 @@
+/*
+ A simple DH example
+
+ Written by Jack Lloyd ([email protected]), on December 24, 2003
+
+ This file is in the public domain
+*/
+#include <botan/botan.h>
+#include <botan/dh.h>
+using namespace Botan;
+
+#include <iostream>
+
+int main()
+ {
+ try {
+ LibraryInitializer init;
+
+ // Alice creates a DH key and sends (the public part) to Bob
+ DH_PrivateKey private_a(DL_Group("modp/ietf/1024"));
+ DH_PublicKey public_a = private_a; // Bob gets this
+
+ // Bob creates a key with a matching group
+ DH_PrivateKey private_b(public_a.get_domain());
+
+ // Bob sends the key back to Alice
+ DH_PublicKey public_b = private_b; // Alice gets this
+
+ // Both of them create a key using their private key and the other's
+ // public key
+ SymmetricKey alice_key = private_a.derive_key(public_b);
+ SymmetricKey bob_key = private_b.derive_key(public_a);
+
+ 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!\n";
+ std::cout << "Alice's key was: " << alice_key.as_string() << "\n";
+ std::cout << "Bob's key was: " << bob_key.as_string() << "\n";
+ }
+
+ // Now Alice and Bob hash the key and use it for something
+ }
+ 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..eb3a00393
--- /dev/null
+++ b/doc/examples/dsa_kgen.cpp
@@ -0,0 +1,57 @@
+/*
+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.
+
+The domain parameters are the ones specified as the Java default DSA
+parameters. There is nothing special about these, it's just the only 1024-bit
+DSA parameter set that's included in Botan at the time of this writing. The
+application always reads/writes all of the domain parameters to/from the file,
+so a new set could be used without any problems. We could generate a new set
+for each key, or read a set of DSA params from a file and use those, but they
+mostly seem like needless complications.
+
+Written by Jack Lloyd ([email protected]), August 5, 2002
+ Updated to use X.509 and PKCS #8 formats, October 21, 2002
+
+This file is in the public domain
+*/
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <botan/botan.h>
+#include <botan/dsa.h>
+using namespace Botan;
+
+int main(int argc, char* argv[])
+ {
+ if(argc != 2)
+ {
+ std::cout << "Usage: " << argv[0] << " passphrase" << std::endl;
+ return 1;
+ }
+
+ std::string passphrase(argv[1]);
+
+ 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 {
+ LibraryInitializer init;
+
+ DSA_PrivateKey key(DL_Group("dsa/jce/1024"));
+
+ pub << X509::PEM_encode(key);
+ priv << PKCS8::PEM_encode(key, passphrase);
+ }
+ 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..26f9e9dac
--- /dev/null
+++ b/doc/examples/dsa_sign.cpp
@@ -0,0 +1,79 @@
+/*
+Decrypt an encrypted DSA private key. Then use that key to sign a message.
+
+Written by Jack Lloyd ([email protected]), August 5, 2002
+ Updated to use X.509 and PKCS #8 format keys, October 21, 2002
+
+This file is in the public domain
+*/
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <string>
+#include <memory>
+
+#include <botan/botan.h>
+#include <botan/look_pk.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;
+ }
+
+ try {
+ std::string passphrase(argv[3]);
+
+ std::ifstream message(argv[2]);
+ 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;
+ }
+
+ LibraryInitializer init;
+
+ std::auto_ptr<PKCS8_PrivateKey> key(
+ PKCS8::load_key(argv[1], 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;
+ }
+
+ Pipe pipe(new PK_Signer_Filter(get_pk_signer(*dsakey, "EMSA1(SHA-1)")),
+ new Base64_Encoder);
+
+ pipe.start_msg();
+ message >> pipe;
+ pipe.end_msg();
+
+ 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..fb6eb7079
--- /dev/null
+++ b/doc/examples/dsa_ver.cpp
@@ -0,0 +1,94 @@
+/*
+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, but it's not bad. It's simply
+the IEEE 1363 signature format, encoded into base64 with a trailing newline
+
+Written by Jack Lloyd ([email protected]), August 5, 2002
+ Updated to use X.509 format keys, October 21, 2002
+
+This file is in the public domain
+*/
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <cstdlib>
+#include <string>
+
+#include <botan/botan.h>
+#include <botan/look_pk.h>
+#include <botan/dsa.h>
+using namespace Botan;
+
+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;
+ }
+
+ std::ifstream message(argv[2]);
+ 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);
+
+ LibraryInitializer init;
+
+ 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);
+
+ Pipe pipe(new PK_Verifier_Filter(
+ get_pk_verifier(*dsakey, "EMSA1(SHA-1)"), sig
+ )
+ );
+
+ pipe.start_msg();
+ message >> pipe;
+ pipe.end_msg();
+
+ byte result = 0;
+ pipe.read(result);
+
+ if(result)
+ 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/encrypt.cpp b/doc/examples/encrypt.cpp
new file mode 100644
index 000000000..c2cf2c5ba
--- /dev/null
+++ b/doc/examples/encrypt.cpp
@@ -0,0 +1,175 @@
+/*
+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.
+
+Based on the base64 example, of all things
+
+Written by Jack Lloyd ([email protected]) on August 5, 2002
+
+This file is in the public domain
+*/
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <cstring>
+
+#include <botan/botan.h>
+
+#if defined(BOTAN_EXT_COMPRESSOR_ZLIB)
+ #include <botan/zlib.h>
+#else
+ #error "You didn't compile the zlib module into Botan"
+#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;
+ }
+
+ 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());
+ 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 {
+
+ LibraryInitializer init;
+
+ if(!have_block_cipher(algo))
+ {
+ std::cout << "Don't know about the block cipher \"" << algo << "\"\n";
+ return 1;
+ }
+
+ const u32bit key_len = max_keylength_of(algo);
+ const u32bit iv_len = block_size_of(algo);
+
+ std::auto_ptr<S2K> s2k(get_s2k("PBKDF2(SHA-1)"));
+ s2k->set_iterations(8192);
+ s2k->new_random_salt(8);
+
+ SymmetricKey bc_key = s2k->derive_key(key_len, "BLK" + passphrase);
+ InitializationVector iv = s2k->derive_key(iv_len, "IVL" + passphrase);
+ SymmetricKey mac_key = s2k->derive_key(16, "MAC" + passphrase);
+
+ // Just to be all fancy we even write a (simple) header.
+ out << "-------- ENCRYPTED FILE --------" << std::endl;
+ out << algo << std::endl;
+ out << b64_encode(s2k->current_salt()) << std::endl;
+
+ Pipe pipe(new Fork(
+ new Chain(new MAC_Filter("HMAC(SHA-1)", mac_key),
+ new Base64_Encoder
+ ),
+ new Chain(new Zlib_Compression,
+ 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/fips140.cpp b/doc/examples/fips140.cpp
new file mode 100644
index 000000000..46e0db4b0
--- /dev/null
+++ b/doc/examples/fips140.cpp
@@ -0,0 +1,59 @@
+/*
+ A minimal FIPS-140 application.
+
+ Written by Jack Lloyd ([email protected]), on December 16-19, 2003
+
+ This file is in the public domain
+*/
+
+#include <botan/botan.h>
+#include <botan/fips140.h>
+using namespace Botan;
+
+#include <iostream>
+#include <fstream>
+
+int main(int, char* argv[])
+ {
+ const std::string EDC_SUFFIX = ".edc";
+
+ try {
+ LibraryInitializer init; /* automatically does startup self tests */
+
+ // you can also do self tests on demand, like this:
+ if(!FIPS140::passes_self_tests())
+ throw Self_Test_Failure("FIPS-140 startup tests");
+
+ /*
+ Here, we just check argv[0] and assume that it works. You can use
+ various extremely nonportable APIs on some Unices (dladdr, to name one)
+ to find out the real name (I presume there are similiarly hairy ways of
+ doing it on Windows). We then assume the EDC (Error Detection Code, aka
+ a hash) is stored in argv[0].edc
+
+ Remember: argv[0] can be easily spoofed. Don't trust it for real.
+
+ You can also do various nasty things and find out the path of the
+ shared library you are linked with, and check that hash.
+ */
+ std::string exe_path = argv[0];
+ std::string edc_path = exe_path + EDC_SUFFIX;
+ std::ifstream edc_file(edc_path.c_str());
+ std::string edc;
+ std::getline(edc_file, edc);
+
+ std::cout << "Our EDC is " << edc << std::endl;
+
+ bool good = FIPS140::good_edc(exe_path, edc);
+
+ if(good)
+ std::cout << "Our EDC matches" << std::endl;
+ else
+ std::cout << "Our EDC is bad" << std::endl;
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Exception caught: " << e.what() << std::endl;
+ }
+ return 0;
+ }
diff --git a/doc/examples/hash.cpp b/doc/examples/hash.cpp
new file mode 100644
index 000000000..a97cd6082
--- /dev/null
+++ b/doc/examples/hash.cpp
@@ -0,0 +1,64 @@
+/*
+Prints the message digest of files, using an arbitrary hash function
+chosen by the user. This is less flexible that I might like, for example:
+ ./hash sha1 some_file [or md5 or sha-1 or ripemd160 or ...]
+will not work, cause the name lookup is case-sensitive. Oh well...
+
+Written by Jack Lloyd ([email protected]), on August 4, 2002
+ - December 16, 2003: "Fixed" to accept "sha1" or "md5" as a hash name
+
+This file is in the public domain
+*/
+
+#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]);
+ 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..19d744287
--- /dev/null
+++ b/doc/examples/hash_fd.cpp
@@ -0,0 +1,70 @@
+/*
+Written by Jack Lloyd ([email protected]), on Prickle-Prickle,
+the 10th of Bureaucracy, 3167.
+
+This file is in the public domain
+
+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.
+
+Note that this requires you to be on a machine running some sort of Unix. Well,
+I guess any POSIX.1 compliant OS (in theory).
+*/
+
+#include <iostream>
+#include <botan/botan.h>
+
+#if !defined(BOTAN_EXT_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/hasher.cpp b/doc/examples/hasher.cpp
new file mode 100644
index 000000000..5ba982fc0
--- /dev/null
+++ b/doc/examples/hasher.cpp
@@ -0,0 +1,58 @@
+/*
+A Botan example application which emulates a
+poorly written version of "gpg --print-md"
+
+Written by Jack Lloyd ([email protected]), quite a while ago (as of June
+2001)
+
+This file is in the public domain
+*/
+#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]);
+ 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..12d3c853d
--- /dev/null
+++ b/doc/examples/hasher2.cpp
@@ -0,0 +1,72 @@
+/*
+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.
+
+Written by Jack Lloyd ([email protected]), Feb 8 2001
+
+This file is in the public domain
+*/
+#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]);
+ 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/pkcs10.cpp b/doc/examples/pkcs10.cpp
new file mode 100644
index 000000000..4639353df
--- /dev/null
+++ b/doc/examples/pkcs10.cpp
@@ -0,0 +1,68 @@
+/*
+Generate a 1024 bit RSA key, and then create a PKCS #10 certificate request for
+that key. The private key will be stored as an encrypted PKCS #8 object, and
+stored in another file.
+
+Written by Jack Lloyd ([email protected]), April 7, 2003
+
+This file is in the public domain
+*/
+#include <botan/init.h>
+#include <botan/x509self.h>
+#include <botan/rsa.h>
+#include <botan/dsa.h>
+using namespace Botan;
+
+#include <iostream>
+#include <fstream>
+
+int main(int argc, char* argv[])
+ {
+ if(argc != 6)
+ {
+ std::cout << "Usage: " << argv[0] <<
+ " passphrase name country_code organization email" << std::endl;
+ return 1;
+ }
+
+ try {
+ LibraryInitializer init;
+
+ RSA_PrivateKey priv_key(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, 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);
+
+ 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/readme.txt b/doc/examples/readme.txt
new file mode 100644
index 000000000..48686db71
--- /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, S2K 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/rsa_dec.cpp b/doc/examples/rsa_dec.cpp
new file mode 100644
index 000000000..d50f6781a
--- /dev/null
+++ b/doc/examples/rsa_dec.cpp
@@ -0,0 +1,122 @@
+/*
+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.
+
+Written by Jack Lloyd ([email protected]), June 3-5, 2002
+
+This file is in the public domain
+*/
+
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include <botan/botan.h>
+#include <botan/look_pk.h> // for get_kdf
+#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;
+ }
+
+ try {
+
+ LibraryInitializer init;
+
+ std::auto_ptr<PKCS8_PrivateKey> key(PKCS8::load_key(argv[1], 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());
+ 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);
+
+ std::auto_ptr<PK_Decryptor> decryptor(get_pk_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..49b62989c
--- /dev/null
+++ b/doc/examples/rsa_enc.cpp
@@ -0,0 +1,149 @@
+/*
+ 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.
+
+Written by Jack Lloyd ([email protected]), June 3, 2002
+ Updated to use KDF2, September 8, 2002
+ Updated to read X.509 keys, October 21, 2002
+
+This file is in the public domain
+*/
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <memory>
+
+#include <botan/botan.h>
+#include <botan/look_pk.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]);
+ if(!message)
+ {
+ std::cout << "Couldn't read the message file." << std::endl;
+ return 1;
+ }
+
+ 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 {
+
+ LibraryInitializer init;
+
+ 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;
+ }
+
+ std::auto_ptr<PK_Encryptor> encryptor(get_pk_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(std::min(32U, 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());
+
+ 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..f2601101e
--- /dev/null
+++ b/doc/examples/rsa_kgen.cpp
@@ -0,0 +1,55 @@
+/*
+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).
+
+Written by Jack Lloyd ([email protected]), June 2-3, 2002
+ Updated to use X.509 and PKCS #8 on October 21, 2002
+
+This file is in the public domain
+*/
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <botan/botan.h>
+#include <botan/rsa.h>
+using namespace Botan;
+
+int main(int argc, char* argv[])
+ {
+ if(argc != 3)
+ {
+ std::cout << "Usage: " << argv[0] << " bitsize passphrase" << std::endl;
+ return 1;
+ }
+
+ u32bit bits = std::atoi(argv[1]);
+ if(bits < 512 || bits > 4096)
+ {
+ std::cout << "Invalid argument for bitsize" << std::endl;
+ return 1;
+ }
+
+ std::string passphrase(argv[2]);
+
+ 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 {
+ LibraryInitializer init;
+ RSA_PrivateKey key(bits);
+ pub << X509::PEM_encode(key);
+ priv << PKCS8::PEM_encode(key, passphrase);
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Exception caught: " << e.what() << std::endl;
+ }
+ return 0;
+ }
diff --git a/doc/examples/self_sig.cpp b/doc/examples/self_sig.cpp
new file mode 100644
index 000000000..c117ff3aa
--- /dev/null
+++ b/doc/examples/self_sig.cpp
@@ -0,0 +1,76 @@
+/*
+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.
+
+Written by Jack Lloyd ([email protected]), April 7, 2003
+
+This file is in the public domain
+*/
+#include <botan/botan.h>
+#include <botan/x509self.h>
+#include <botan/rsa.h>
+#include <botan/dsa.h>
+using namespace Botan;
+
+#include <iostream>
+#include <fstream>
+
+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;
+ }
+
+ 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 {
+ RSA_PrivateKey key(1024);
+ //DSA_PrivateKey key(DL_Group("dsa/jce/1024"));
+
+ std::ofstream priv_key("private.pem");
+ priv_key << PKCS8::PEM_encode(key, 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);
+
+ 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/stack.cpp b/doc/examples/stack.cpp
new file mode 100644
index 000000000..1522b05f5
--- /dev/null
+++ b/doc/examples/stack.cpp
@@ -0,0 +1,86 @@
+/*
+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.
+
+Written by Jack Lloyd ([email protected]), Feb 3, 2002
+
+This file is in the public domain
+*/
+
+#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]);
+ 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/x509info.cpp b/doc/examples/x509info.cpp
new file mode 100644
index 000000000..cbb9c0a11
--- /dev/null
+++ b/doc/examples/x509info.cpp
@@ -0,0 +1,142 @@
+/*
+ Read an X.509 certificate, and print various things about it
+
+ Written by Jack Lloyd, March 23 2003
+ - October 31, 2003: Prints the public key
+ - November 1, 2003: Removed the -d flag; it can tell automatically now
+
+ This file is in the public domain
+*/
+#include <botan/botan.h>
+#include <botan/x509cert.h>
+#include <botan/oids.h>
+using namespace Botan;
+
+#include <iostream>
+
+std::string to_hex(const SecureVector<byte>& bin)
+ {
+ Pipe pipe(new Hex_Encoder);
+ pipe.process_msg(bin);
+ if(pipe.remaining())
+ return pipe.read_all_as_string();
+ else
+ return "(none)";
+ }
+
+void do_print(const std::string& what, const std::string& val)
+ {
+ if(val == "")
+ return;
+
+ std::cout << " " << what << ": " << val << std::endl;
+ }
+
+void do_subject(const X509_Certificate& cert, const std::string& what)
+ {
+ do_print(what, cert.subject_info(what));
+ }
+
+void do_issuer(const X509_Certificate& cert, const std::string& what)
+ {
+ do_print(what, cert.issuer_info(what));
+ }
+
+int main(int argc, char* argv[])
+ {
+ if(argc != 2)
+ {
+ std::cout << "Usage: " << argv[0] << " <x509cert>\n";
+ return 1;
+ }
+
+ try {
+ LibraryInitializer init;
+
+ X509_Certificate cert(argv[1]);
+
+ std::cout << "Version: " << cert.x509_version() << std::endl;
+
+ std::cout << "Subject" << std::endl;
+ do_subject(cert, "Name");
+ do_subject(cert, "Email");
+ do_subject(cert, "Organization");
+ do_subject(cert, "Organizational Unit");
+ do_subject(cert, "Locality");
+ do_subject(cert, "State");
+ do_subject(cert, "Country");
+ do_subject(cert, "PKIX.XMPPAddr");
+
+ std::cout << "Issuer" << std::endl;
+ do_issuer(cert, "Name");
+ do_issuer(cert, "Email");
+ do_issuer(cert, "Organization");
+ do_issuer(cert, "Organizational Unit");
+ do_issuer(cert, "Locality");
+ do_issuer(cert, "State");
+ do_issuer(cert, "Country");
+
+ std::cout << "Validity" << std::endl;
+
+ std::cout << " Not before: " << cert.start_time() << std::endl;
+ std::cout << " Not after: " << cert.end_time() << std::endl;
+
+ std::cout << "Constraints" << std::endl;
+ Key_Constraints constraints = cert.constraints();
+ if(constraints == NO_CONSTRAINTS)
+ std::cout << "No constraints" << std::endl;
+ else
+ {
+ if(constraints & DIGITAL_SIGNATURE)
+ std::cout << " Digital Signature\n";
+ if(constraints & NON_REPUDIATION)
+ std::cout << " Non-Repuidation\n";
+ if(constraints & KEY_ENCIPHERMENT)
+ std::cout << " Key Encipherment\n";
+ if(constraints & DATA_ENCIPHERMENT)
+ std::cout << " Data Encipherment\n";
+ if(constraints & KEY_AGREEMENT)
+ std::cout << " Key Agreement\n";
+ if(constraints & KEY_CERT_SIGN)
+ std::cout << " Cert Sign\n";
+ if(constraints & CRL_SIGN)
+ std::cout << " CRL Sign\n";
+ }
+
+ std::vector<OID> policies = cert.policies();
+ if(policies.size())
+ {
+ std::cout << "Policies: " << std::endl;
+ for(u32bit j = 0; j != policies.size(); j++)
+ std::cout << " " << OIDS::lookup(policies[j]) << std::endl;
+ }
+
+ std::vector<OID> ex_constraints = cert.ex_constraints();
+ if(ex_constraints.size())
+ {
+ std::cout << "Extended Constraints: " << std::endl;
+ for(u32bit j = 0; j != ex_constraints.size(); j++)
+ std::cout << " " << OIDS::lookup(ex_constraints[j]) << std::endl;
+ }
+
+ std::cout << "Signature algorithm: " <<
+ OIDS::lookup(cert.signature_algorithm().oid) << std::endl;
+
+ std::cout << "Serial: "
+ << to_hex(cert.serial_number()) << std::endl;
+ std::cout << "Authority keyid: "
+ << to_hex(cert.authority_key_id()) << std::endl;
+ std::cout << "Subject keyid: "
+ << to_hex(cert.subject_key_id()) << std::endl;
+
+ X509_PublicKey* pubkey = cert.subject_public_key();
+ std::cout << "Public Key:\n" << X509::PEM_encode(*pubkey);
+ delete pubkey;
+ }
+ catch(std::exception& e)
+ {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+ return 0;
+ }
diff --git a/doc/examples/xor_ciph.cpp b/doc/examples/xor_ciph.cpp
new file mode 100644
index 000000000..b57fbfc4d
--- /dev/null
+++ b/doc/examples/xor_ciph.cpp
@@ -0,0 +1,95 @@
+/*
+ An implementation of the highly secure (not) XOR cipher. AKA, how to write
+ and use your own cipher object. DO NOT make up your own ciphers. Please.
+
+ Written by Jack Lloyd ([email protected]) on Feb 17, 2004
+
+ This file is in the public domain
+*/
+#include <botan/base.h>
+#include <botan/init.h>
+using namespace Botan;
+
+class XOR_Cipher : public StreamCipher
+ {
+ public:
+ // 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; }
+ // StreamCipher() can take a number of args, which are:
+ // min keylen, max keylen, keylength mod, iv size
+ // In this case we just pass min keylen, which means the
+ // only keysize we support is 1 byte, and don't use an IV.
+ XOR_Cipher() : StreamCipher(1) { mask = 0; }
+ private:
+ void cipher(const byte[], byte[], u32bit);
+ void key(const byte[], u32bit);
+ byte mask;
+ };
+
+void XOR_Cipher::cipher(const byte in[], byte out[], u32bit length)
+ {
+ for(u32bit j = 0; j != length; j++)
+ out[j] = in[j] ^ mask;
+ }
+
+void XOR_Cipher::key(const byte key[], u32bit)
+ {
+ /* We know length == 1 because it is checked in set_key against the
+ constraints we passed to StreamCipher's constructor. In this case,
+ we said: "All keys are of length 1 byte and no other length".
+
+ An excercise for the reader would be to extend this to support
+ arbitrary length (for arbitrary in the range 1-32) keys.
+ */
+ mask = key[0];
+ }
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <cstring>
+
+#include <botan/look_add.h>
+#include <botan/lookup.h>
+#include <botan/filters.h>
+
+int main()
+ {
+ LibraryInitializer init;
+
+ add_algorithm(new XOR_Cipher); // make it available to use
+ add_alias("Vernam", "XOR"); // make Vernam an alias for XOR
+
+ SymmetricKey key("42"); // a key of length 1, value hex 42 == dec 66
+
+ /*
+ 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("Vernam", 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;
+ }