diff options
297 files changed, 10503 insertions, 10663 deletions
diff --git a/.mtn-ignore b/.mtn-ignore index 8be5a95a8..657db91fc 100644 --- a/.mtn-ignore +++ b/.mtn-ignore @@ -1,4 +1,7 @@ ^Makefile.*$ +^libbotan.*\.so\..* +^[a-z]+\.(exp|lib)$ +^[a-z]+\.(exe|dll)(\.manifest)?$ ^botan-config$ ^botan_all\.(cpp|h)$ ^botan.pc$ @@ -9,13 +12,9 @@ callgrind.out.* ^checks/ecc_testdata/rsa_private.pkcs8.pem$ ^checks/ecc_testdata/wo_dompar_private.pkcs8.pem$ ^checks/nist_tests/x509test$ -^doc/botan.doxy$ -^doc/doxygen$ -^doc/[a-z]+\.(pdf|log|toc)$ +^doc/_static$ ^doc/examples/.*\.pem$ ^doc/examples/[a-z0-9_]+$ ^src/wrap/perl-xs/Botan.(bs|c)$ ^src/wrap/perl-xs/Makefile(\.old)?$ ^src/wrap/perl-xs/.*blib$ -^[a-z]+\.(exe|dll)(\.manifest)?$ -^[a-z]+\.(exp|lib)$ diff --git a/Attic/gtk/Makefile b/Attic/gtk/Makefile deleted file mode 100644 index 10e069bb3..000000000 --- a/Attic/gtk/Makefile +++ /dev/null @@ -1,18 +0,0 @@ - -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/Attic/gtk/dsa.cpp b/Attic/gtk/dsa.cpp deleted file mode 100644 index 2cd91b0e8..000000000 --- a/Attic/gtk/dsa.cpp +++ /dev/null @@ -1,566 +0,0 @@ -/* - 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/Attic/gtk/gtk_ui.cpp b/Attic/gtk/gtk_ui.cpp deleted file mode 100644 index d4e9cd238..000000000 --- a/Attic/gtk/gtk_ui.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* -* 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/Attic/gtk/gtk_ui.h b/Attic/gtk/gtk_ui.h deleted file mode 100644 index 065a4f76b..000000000 --- a/Attic/gtk/gtk_ui.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -* (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/Attic/gtk/readme.txt b/Attic/gtk/readme.txt deleted file mode 100644 index 4f3691166..000000000 --- a/Attic/gtk/readme.txt +++ /dev/null @@ -1,18 +0,0 @@ - -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/botan_version.py b/botan_version.py new file mode 100644 index 000000000..a03dd9da7 --- /dev/null +++ b/botan_version.py @@ -0,0 +1,8 @@ + +release_major = 1 +release_minor = 10 +release_patch = 0 + +release_so_abi_rev = 0 + +release_datestamp = 0 diff --git a/checks/check.cpp b/checks/check.cpp index e32f57ed7..4fa1160ae 100644 --- a/checks/check.cpp +++ b/checks/check.cpp @@ -100,6 +100,20 @@ void test_types() int main(int argc, char* argv[]) { + if(BOTAN_VERSION_MAJOR != version_major() || + BOTAN_VERSION_MINOR != version_minor() || + BOTAN_VERSION_PATCH != version_patch()) + { + std::cout << "Warning: linked version (" + << version_major() << '.' + << version_minor() << '.' + << version_patch() + << ") does not match version built against (" + << BOTAN_VERSION_MAJOR << '.' + << BOTAN_VERSION_MINOR << '.' + << BOTAN_VERSION_PATCH << ")\n"; + } + try { OptionParser opts("help|test|validate|dyn-load=|" diff --git a/checks/cvc_tests.cpp b/checks/cvc_tests.cpp index ecaf0c71b..1197c2d30 100644 --- a/checks/cvc_tests.cpp +++ b/checks/cvc_tests.cpp @@ -90,7 +90,7 @@ void test_enc_gen_selfsigned(RandomNumberGenerator& rng) opts.hash_alg = "SHA-256"; // creating a non sense selfsigned cert w/o dom pars - EC_Domain_Params dom_pars(OID("1.3.36.3.3.2.8.1.1.11")); + EC_Group dom_pars(OID("1.3.36.3.3.2.8.1.1.11")); ECDSA_PrivateKey key(rng, dom_pars); key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA); EAC1_1_CVC cert = CVC_EAC::create_self_signed_cert(key, opts, rng); @@ -200,7 +200,7 @@ void test_enc_gen_req(RandomNumberGenerator& rng) opts.hash_alg = "SHA-160"; // creating a non sense selfsigned cert w/o dom pars - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey key(rng, dom_pars); key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA); EAC1_1_Req req = CVC_EAC::create_cvc_req(key, opts.chr, opts.hash_alg, rng); @@ -225,7 +225,7 @@ void test_cvc_req_ext(RandomNumberGenerator&) std::cout << "." << std::flush; EAC1_1_Req req_in(TEST_DATA_DIR "/DE1_flen_chars_cvcRequest_ECDSA.der"); - EC_Domain_Params dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" + EC_Group dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" //req_in.set_domain_parameters(dom_pars); std::unique_ptr<Public_Key> p_pk(req_in.subject_public_key()); ECDSA_PublicKey* p_ecdsa_pk = dynamic_cast<ECDSA_PublicKey*>(p_pk.get()); @@ -240,7 +240,7 @@ void test_cvc_ado_ext(RandomNumberGenerator&) std::cout << "." << std::flush; EAC1_1_ADO req_in(TEST_DATA_DIR "/ado.cvcreq"); - EC_Domain_Params dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" + EC_Group dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" //cout << "car = " << req_in.get_car().value() << std::endl; //req_in.set_domain_parameters(dom_pars); } @@ -255,7 +255,7 @@ void test_cvc_ado_creation(RandomNumberGenerator& rng) opts.hash_alg = "SHA-256"; // creating a non sense selfsigned cert w/o dom pars - EC_Domain_Params dom_pars(OID("1.3.36.3.3.2.8.1.1.11")); + EC_Group dom_pars(OID("1.3.36.3.3.2.8.1.1.11")); //cout << "mod = " << hex << dom_pars.get_curve().get_p() << std::endl; ECDSA_PrivateKey req_key(rng, dom_pars); req_key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA); @@ -299,7 +299,7 @@ void test_cvc_ado_comparison(RandomNumberGenerator& rng) opts.hash_alg = "SHA-224"; // creating a non sense selfsigned cert w/o dom pars - EC_Domain_Params dom_pars(OID("1.3.36.3.3.2.8.1.1.11")); + EC_Group dom_pars(OID("1.3.36.3.3.2.8.1.1.11")); ECDSA_PrivateKey req_key(rng, dom_pars); req_key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA); //EAC1_1_Req req = CVC_EAC::create_cvc_req(req_key, opts); @@ -417,14 +417,14 @@ void test_copy_and_assignment(RandomNumberGenerator&) CHECK(cert_in == cert_ass); EAC1_1_ADO ado_in(TEST_DATA_DIR "/ado.cvcreq"); - //EC_Domain_Params dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" + //EC_Group dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" EAC1_1_ADO ado_cp(ado_in); EAC1_1_ADO ado_ass = ado_in; CHECK(ado_in == ado_cp); CHECK(ado_in == ado_ass); EAC1_1_Req req_in(TEST_DATA_DIR "/DE1_flen_chars_cvcRequest_ECDSA.der"); - //EC_Domain_Params dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" + //EC_Group dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" EAC1_1_Req req_cp(req_in); EAC1_1_Req req_ass = req_in; CHECK(req_in == req_cp); @@ -485,7 +485,7 @@ void test_cvc_chain(RandomNumberGenerator& rng) { std::cout << "." << std::flush; - EC_Domain_Params dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" + EC_Group dom_pars(OID("1.3.36.3.3.2.8.1.1.5")); // "german curve" ECDSA_PrivateKey cvca_privk(rng, dom_pars); std::string hash("SHA-224"); ASN1_Car car("DECVCA00001"); diff --git a/checks/dolook.cpp b/checks/dolook.cpp index 1015f4240..a8e08a96b 100644 --- a/checks/dolook.cpp +++ b/checks/dolook.cpp @@ -55,6 +55,8 @@ using namespace Botan; #include "common.h" +namespace { + /* A weird little hack to fit PBKDF algorithms into the validation * suite You probably wouldn't ever want to actually use the PBKDF * algorithms like this, the raw PBKDF interface is more convenient @@ -279,6 +281,8 @@ Filter* lookup_encoder(const std::string& algname) return 0; } +} + Filter* lookup(const std::string& algname, const std::vector<std::string>& params) { diff --git a/checks/ec_tests.cpp b/checks/ec_tests.cpp index ab9dfe3f8..e308a5291 100644 --- a/checks/ec_tests.cpp +++ b/checks/ec_tests.cpp @@ -5,12 +5,16 @@ */ -#include <botan/build.h> +#include <botan/rng.h> + +#if defined(BOTAN_HAS_ECC_GROUP) + #include <botan/bigint.h> #include <botan/numthry.h> #include <botan/curve_gfp.h> #include <botan/point_gfp.h> -#include <botan/ecdsa.h> +#include <botan/ec_group.h> +#include <botan/reducer.h> #include <botan/oids.h> using namespace Botan; @@ -22,6 +26,7 @@ using namespace Botan; #include "validate.h" #include "common.h" + #define CHECK_MESSAGE(expr, print) try { if(!(expr)) std::cout << print << "\n"; } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; } #define CHECK(expr) try { if(!(expr)) std::cout << #expr << "\n"; } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; } @@ -38,7 +43,7 @@ PointGFp create_random_point(RandomNumberGenerator& rng, { const BigInt& p = curve.get_p(); - const Modular_Reducer& mod_p = curve.mod_p(); + Modular_Reducer mod_p(p); while(true) { @@ -172,7 +177,7 @@ void test_point_transformation () std::cout << "." << std::flush; // get a vailid point - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); PointGFp p = dom_pars.get_base_point(); // get a copy @@ -186,7 +191,7 @@ void test_point_mult () { std::cout << "." << std::flush; - EC_Domain_Params secp160r1(OIDS::lookup("secp160r1")); + EC_Group secp160r1(OIDS::lookup("secp160r1")); const CurveGFp& curve = secp160r1.get_curve(); @@ -637,9 +642,9 @@ void test_gfp_store_restore() std::cout << "." << std::flush; // generate point - //EC_Domain_Params dom_pars = global_config().get_ec_dompar("1.3.132.0.8"); - //EC_Domain_Params dom_pars("1.3.132.0.8"); - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + //EC_Group dom_pars = global_config().get_ec_dompar("1.3.132.0.8"); + //EC_Group dom_pars("1.3.132.0.8"); + EC_Group dom_pars(OID("1.3.132.0.8")); PointGFp p = dom_pars.get_base_point(); //store point (to std::string) @@ -724,7 +729,7 @@ void test_mult_by_order() std::cout << "." << std::flush; // generate point - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); PointGFp p = dom_pars.get_base_point(); PointGFp shouldBeZero = p * dom_pars.get_order(); @@ -735,7 +740,7 @@ void test_point_swap(RandomNumberGenerator& rng) { std::cout << "." << std::flush; - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); PointGFp a(create_random_point(rng, dom_pars.get_curve())); PointGFp b(create_random_point(rng, dom_pars.get_curve())); @@ -756,7 +761,7 @@ void test_point_swap(RandomNumberGenerator& rng) void test_mult_sec_mass(RandomNumberGenerator& rng) { - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); for(int i = 0; i<50; i++) { std::cout << "." << std::flush; @@ -775,7 +780,7 @@ void test_curve_cp_ctor() { std::cout << "." << std::flush; - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); CurveGFp curve(dom_pars.get_curve()); } @@ -813,3 +818,10 @@ void do_ec_tests(RandomNumberGenerator& rng) std::cout << std::endl; } +#else + +void do_ec_tests(Botan::RandomNumberGenerator& rng) + { + } + +#endif diff --git a/checks/ecdh.cpp b/checks/ecdh.cpp index a63742f2f..c641796d6 100644 --- a/checks/ecdh.cpp +++ b/checks/ecdh.cpp @@ -33,7 +33,7 @@ void test_ecdh_normal_derivation(RandomNumberGenerator& rng) { std::cout << "." << std::flush; - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); ECDH_PrivateKey private_a(rng, dom_pars); @@ -65,7 +65,7 @@ void test_ecdh_some_dp(RandomNumberGenerator& rng) std::cout << "." << std::flush; OID oid(oids[i]); - EC_Domain_Params dom_pars(oid); + EC_Group dom_pars(oid); ECDH_PrivateKey private_a(rng, dom_pars); ECDH_PrivateKey private_b(rng, dom_pars); @@ -91,7 +91,7 @@ void test_ecdh_der_derivation(RandomNumberGenerator& rng) for(u32bit i = 0; i< oids.size(); i++) { OID oid(oids[i]); - EC_Domain_Params dom_pars(oid); + EC_Group dom_pars(oid); ECDH_PrivateKey private_a(rng, dom_pars); ECDH_PrivateKey private_b(rng, dom_pars); diff --git a/checks/ecdsa.cpp b/checks/ecdsa.cpp index 346c0441c..3110bf0fe 100644 --- a/checks/ecdsa.cpp +++ b/checks/ecdsa.cpp @@ -48,7 +48,7 @@ void test_hash_larger_than_n(RandomNumberGenerator& rng) { std::cout << "." << std::flush; - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); // secp160r1 + EC_Group dom_pars(OID("1.3.132.0.8")); // secp160r1 // n = 0x0100000000000000000001f4c8f927aed3ca752257 (21 bytes) // -> shouldn't work with SHA224 which outputs 28 bytes @@ -137,7 +137,7 @@ void test_sign_then_ver(RandomNumberGenerator& rng) { std::cout << '.' << std::flush; - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey ecdsa(rng, dom_pars); PK_Signer signer(ecdsa, "EMSA1(SHA-1)"); @@ -165,19 +165,19 @@ bool test_ec_sign(RandomNumberGenerator& rng) try { - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey priv_key(rng, dom_pars); std::string pem_encoded_key = PKCS8::PEM_encode(priv_key); PK_Signer signer(priv_key, "EMSA1(SHA-224)"); PK_Verifier verifier(priv_key, "EMSA1(SHA-224)"); - for(u32bit i = 0; i != 256; ++i) - signer.update((byte)i); + for(size_t i = 0; i != 256; ++i) + signer.update(static_cast<byte>(i)); SecureVector<byte> sig = signer.signature(rng); for(u32bit i = 0; i != 256; ++i) - verifier.update((byte)i); + verifier.update(static_cast<byte>(i)); if(!verifier.check_signature(sig)) { std::cout << "ECDSA self-test failed!"; @@ -186,7 +186,7 @@ bool test_ec_sign(RandomNumberGenerator& rng) // now check valid signature, different input for(u32bit i = 1; i != 256; ++i) //starting from 1 - verifier.update((byte)i); + verifier.update(static_cast<byte>(i)); if(verifier.check_signature(sig)) { @@ -198,7 +198,7 @@ bool test_ec_sign(RandomNumberGenerator& rng) sig[sig.size()/2]++; for(u32bit i = 0; i != 256; ++i) - verifier.update((byte)i); + verifier.update(static_cast<byte>(i)); if(verifier.check_signature(sig)) { @@ -229,7 +229,7 @@ void test_create_pkcs8(RandomNumberGenerator& rng) std::ofstream rsa_priv_key(TEST_DATA_DIR "/rsa_private.pkcs8.pem"); rsa_priv_key << PKCS8::PEM_encode(rsa_key); - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey key(rng, dom_pars); // later used by other tests :( @@ -246,7 +246,7 @@ void test_create_and_verify(RandomNumberGenerator& rng) { std::cout << "." << std::flush; - EC_Domain_Params dom_pars(OID("1.3.132.0.8")); + EC_Group dom_pars(OID("1.3.132.0.8")); ECDSA_PrivateKey key(rng, dom_pars); std::ofstream priv_key(TEST_DATA_DIR "/dompar_private.pkcs8.pem"); priv_key << PKCS8::PEM_encode(key); @@ -281,7 +281,7 @@ void test_create_and_verify(RandomNumberGenerator& rng) CurveGFp curve(bi_p_secp, bi_a_secp, bi_b_secp); PointGFp p_G = OS2ECP ( sv_G_secp_comp, curve ); - EC_Domain_Params dom_params(curve, p_G, bi_order_g, BigInt(1)); + EC_Group dom_params(curve, p_G, bi_order_g, BigInt(1)); if(!p_G.on_the_curve()) throw Internal_Error("Point not on the curve"); @@ -337,7 +337,7 @@ void test_curve_registry(RandomNumberGenerator& rng) try { OID oid(oids[i]); - EC_Domain_Params dom_pars(oid); + EC_Group dom_pars(oid); ECDSA_PrivateKey ecdsa(rng, dom_pars); PK_Signer signer(ecdsa, "EMSA1(SHA-1)"); diff --git a/checks/nist_tests/Makefile b/checks/nist_tests/Makefile index 6d0ebb78f..3fcdf212b 100644 --- a/checks/nist_tests/Makefile +++ b/checks/nist_tests/Makefile @@ -1,10 +1,8 @@ -BOTAN_CONFIG=botan-config - CC=g++ FLAGS=-g -Os -W -Wall -ansi -LDFLAGS=$(shell $(BOTAN_CONFIG) --libs) -CFLAGS=$(shell $(BOTAN_CONFIG) --cflags) +LDFLAGS=-L../.. -lbotan-1.9 +CFLAGS=-I../../build/include x509test: x509test.cpp $(CC) $(FLAGS) $(CFLAGS) x509test.cpp $(LDFLAGS) -o x509test diff --git a/checks/nist_tests/x509test.cpp b/checks/nist_tests/x509test.cpp index 7f4fe94ee..0c4c04029 100644 --- a/checks/nist_tests/x509test.cpp +++ b/checks/nist_tests/x509test.cpp @@ -1,7 +1,7 @@ /* - Code to run the X.509v3 processing tests described in "Conformance Testing of - Relying Party Client Certificate Path Proccessing Logic", which is available - on NIST's web site. + Code to run the X.509v3 processing tests described in "Conformance + Testing of Relying Party Client Certificate Path Proccessing Logic", + which is available on NIST's web site. */ #include <botan/x509stor.h> @@ -18,10 +18,6 @@ using namespace Botan; #include <dirent.h> -#define POLICY_TEST1 1000 -#define POLICY_TEST2 2000 -#define POLICY_TEST3 3000 - std::vector<std::string> dir_listing(const std::string&); void run_one_test(u32bit, X509_Code, @@ -265,13 +261,14 @@ void populate_expected_results() expected_results[33] = VERIFIED; /* - Policy tests: a little trickier because there are other inputs which - affect the result. + Policy tests: a little trickier because there are other inputs + which affect the result. - In the case of the tests currently in the suite, the default method (with - acceptable policy being "any-policy" and with no explict policy required), - will almost always result in a verified status. This is not particularly - helpful. So, we do several different tests for each test set: + In the case of the tests currently in the suite, the default + method (with acceptable policy being "any-policy" and with no + explict policy required), will almost always result in a verified + status. This is not particularly helpful. So, we should do several + different tests for each test set: 1) With the user policy as any-policy and no explicit policy 2) With the user policy as any-policy and an explicit policy required @@ -283,88 +280,28 @@ void populate_expected_results() This provides reasonably good coverage of the possible outcomes. */ - /* expected_results[34] = VERIFIED; - expected_results[34+POLICY_TEST1] = ; - expected_results[34+POLICY_TEST2] = ; - expected_results[34+POLICY_TEST3] = ; expected_results[35] = VERIFIED; - expected_results[35+POLICY_TEST1] = ; - expected_results[35+POLICY_TEST2] = ; - expected_results[35+POLICY_TEST3] = ; expected_results[36] = VERIFIED; - expected_results[36+POLICY_TEST1] = ; - expected_results[36+POLICY_TEST2] = ; - expected_results[36+POLICY_TEST3] = ; expected_results[37] = VERIFIED; - expected_results[37+POLICY_TEST1] = ; - expected_results[37+POLICY_TEST2] = ; - expected_results[37+POLICY_TEST3] = ; expected_results[38] = VERIFIED; - expected_results[38+POLICY_TEST1] = ; - expected_results[38+POLICY_TEST2] = ; - expected_results[38+POLICY_TEST3] = ; expected_results[39] = VERIFIED; - expected_results[39+POLICY_TEST1] = ; - expected_results[39+POLICY_TEST2] = ; - expected_results[39+POLICY_TEST3] = ; expected_results[40] = VERIFIED; - expected_results[40+POLICY_TEST1] = ; - expected_results[40+POLICY_TEST2] = ; - expected_results[40+POLICY_TEST3] = ; expected_results[41] = VERIFIED; - expected_results[41+POLICY_TEST1] = ; - expected_results[41+POLICY_TEST2] = ; - expected_results[41+POLICY_TEST3] = ; expected_results[42] = VERIFIED; - expected_results[42+POLICY_TEST1] = ; - expected_results[42+POLICY_TEST2] = ; - expected_results[42+POLICY_TEST3] = ; expected_results[43] = VERIFIED; - expected_results[43+POLICY_TEST1] = ; - expected_results[43+POLICY_TEST2] = ; - expected_results[43+POLICY_TEST3] = ; expected_results[44] = VERIFIED; - expected_results[44+POLICY_TEST1] = ; - expected_results[44+POLICY_TEST2] = ; - expected_results[44+POLICY_TEST3] = ; - expected_results[45] = EXPLICT_POLICY_REQUIRED; - expected_results[45+POLICY_TEST1] = ; - expected_results[45+POLICY_TEST2] = ; - expected_results[45+POLICY_TEST3] = ; - expected_results[46] = ACCEPT; - expected_results[46+POLICY_TEST1] = ; - expected_results[46+POLICY_TEST2] = ; - expected_results[46+POLICY_TEST3] = ; - expected_results[47] = EXPLICT_POLICY_REQUIRED; - expected_results[47+POLICY_TEST1] = ; - expected_results[47+POLICY_TEST2] = ; - expected_results[47+POLICY_TEST3] = ; + + //expected_results[45] = EXPLICT_POLICY_REQUIRED; + //expected_results[46] = ACCEPT; + //expected_results[47] = EXPLICT_POLICY_REQUIRED; + expected_results[48] = VERIFIED; - expected_results[48+POLICY_TEST1] = ; - expected_results[48+POLICY_TEST2] = ; - expected_results[48+POLICY_TEST3] = ; expected_results[49] = VERIFIED; - expected_results[49+POLICY_TEST1] = ; - expected_results[49+POLICY_TEST2] = ; - expected_results[49+POLICY_TEST3] = ; expected_results[50] = VERIFIED; - expected_results[50+POLICY_TEST1] = ; - expected_results[50+POLICY_TEST2] = ; - expected_results[50+POLICY_TEST3] = ; expected_results[51] = VERIFIED; - expected_results[51+POLICY_TEST1] = ; - expected_results[51+POLICY_TEST2] = ; - expected_results[51+POLICY_TEST3] = ; expected_results[52] = VERIFIED; - expected_results[52+POLICY_TEST1] = ; - expected_results[52+POLICY_TEST2] = ; - expected_results[52+POLICY_TEST3] = ; expected_results[53] = VERIFIED; - expected_results[53+POLICY_TEST1] = ; - expected_results[53+POLICY_TEST2] = ; - expected_results[53+POLICY_TEST3] = ; - */ expected_results[54] = CERT_CHAIN_TOO_LONG; expected_results[55] = CERT_CHAIN_TOO_LONG; diff --git a/checks/pk.cpp b/checks/pk.cpp index 18cbb9f70..e11578523 100644 --- a/checks/pk.cpp +++ b/checks/pk.cpp @@ -498,15 +498,16 @@ u32bit validate_dsa_sig(const std::string& algo, } u32bit validate_ecdsa_sig(const std::string& algo, - const std::vector<std::string>& str) + const std::vector<std::string>& str, + RandomNumberGenerator& rng) { if(str.size() != 5) throw std::runtime_error("Invalid input from pk_valid.dat"); #if defined(BOTAN_HAS_ECDSA) - EC_Domain_Params group(OIDS::lookup(str[0])); - ECDSA_PrivateKey ecdsa(group, to_bigint(str[1])); + EC_Group group(OIDS::lookup(str[0])); + ECDSA_PrivateKey ecdsa(rng, group, to_bigint(str[1])); std::string emsa = algo.substr(6, std::string::npos); @@ -529,7 +530,7 @@ u32bit validate_gost_ver(const std::string& algo, #if defined(BOTAN_HAS_GOST_34_10_2001) - EC_Domain_Params group(OIDS::lookup(str[0])); + EC_Group group(OIDS::lookup(str[0])); PointGFp public_point = OS2ECP(hex_decode(str[1]), group.get_curve()); @@ -696,7 +697,7 @@ void do_pk_keygen_tests(RandomNumberGenerator& rng) #define EC_KEY(TYPE, GROUP) \ { \ - TYPE key(rng, EC_Domain_Params(OIDS::lookup(GROUP))); \ + TYPE key(rng, EC_Group(OIDS::lookup(GROUP))); \ key.check_key(rng, true); \ validate_save_and_load(&key, rng); \ std::cout << '.' << std::flush; \ @@ -855,7 +856,7 @@ u32bit do_pk_validation_tests(const std::string& filename, new_errors = validate_dsa_ver(algorithm, substr); else if(algorithm.find("ECDSA/") == 0) - new_errors = validate_ecdsa_sig(algorithm, substr); + new_errors = validate_ecdsa_sig(algorithm, substr, rng); else if(algorithm.find("GOST_3410_VA/") == 0) new_errors = validate_gost_ver(algorithm, substr); diff --git a/checks/pk_bench.cpp b/checks/pk_bench.cpp index 8e7c35763..449ff7730 100644 --- a/checks/pk_bench.cpp +++ b/checks/pk_bench.cpp @@ -65,6 +65,9 @@ using namespace Botan; #include <memory> #include <set> +#define BENCH_FAULT_PROT DISABLE_FAULT_PROTECTION +//#define BENCH_FAULT_PROT ENABLE_FAULT_PROTECTION + namespace { const char* ec_domains[] = { @@ -305,7 +308,7 @@ void benchmark_ecdsa(RandomNumberGenerator& rng, { for(size_t j = 0; ec_domains[j]; j++) { - EC_Domain_Params params(OIDS::lookup(ec_domains[j])); + EC_Group params(ec_domains[j]); const size_t pbits = params.get_curve().get_p().bits(); @@ -329,7 +332,7 @@ void benchmark_ecdsa(RandomNumberGenerator& rng, ECDSA_PrivateKey key(rng, params); keygen_timer.stop(); - PK_Signer sig(key, padding, IEEE_1363, DISABLE_FAULT_PROTECTION); + PK_Signer sig(key, padding, IEEE_1363, BENCH_FAULT_PROT); PK_Verifier ver(key, padding); benchmark_sig_ver(ver, sig, verify_timer, @@ -354,7 +357,7 @@ void benchmark_gost_3410(RandomNumberGenerator& rng, { for(size_t j = 0; ec_domains[j]; j++) { - EC_Domain_Params params(OIDS::lookup(ec_domains[j])); + EC_Group params(ec_domains[j]); const size_t pbits = params.get_curve().get_p().bits(); @@ -371,7 +374,7 @@ void benchmark_gost_3410(RandomNumberGenerator& rng, GOST_3410_PrivateKey key(rng, params); keygen_timer.stop(); - PK_Signer sig(key, padding, IEEE_1363, DISABLE_FAULT_PROTECTION); + PK_Signer sig(key, padding, IEEE_1363, BENCH_FAULT_PROT); PK_Verifier ver(key, padding); benchmark_sig_ver(ver, sig, verify_timer, @@ -396,7 +399,7 @@ void benchmark_ecdh(RandomNumberGenerator& rng, { for(size_t j = 0; ec_domains[j]; j++) { - EC_Domain_Params params(OIDS::lookup(ec_domains[j])); + EC_Group params(ec_domains[j]); size_t pbits = params.get_curve().get_p().bits(); @@ -478,7 +481,7 @@ void benchmark_dsa_nr(RandomNumberGenerator& rng, algo_name = key.algo_name(); keygen_timer.stop(); - PK_Signer sig(key, padding, IEEE_1363, DISABLE_FAULT_PROTECTION); + PK_Signer sig(key, padding, IEEE_1363, BENCH_FAULT_PROT); PK_Verifier ver(key, padding); benchmark_sig_ver(ver, sig, verify_timer, diff --git a/checks/validate.cpp b/checks/validate.cpp index 9acf73419..d79f9783a 100644 --- a/checks/validate.cpp +++ b/checks/validate.cpp @@ -239,7 +239,7 @@ bool test_passhash(RandomNumberGenerator& rng) for(byte alg_id = 0; alg_id <= 2; ++alg_id) { - std::string gen_hash = generate_passhash9(input, alg_id, rng, 1); + std::string gen_hash = generate_passhash9(input, rng, 2, alg_id); if(!check_passhash9(input, gen_hash)) return false; diff --git a/checks/validate.dat b/checks/validate.dat index a7744af9b..6f264ea74 100644 --- a/checks/validate.dat +++ b/checks/validate.dat @@ -4406,6 +4406,61 @@ D2FD8867D50D2DFE:0000000000000004:0101010101010101 0000000000000000:E2F5728F0995013C:1002911598100201 0000000000000000:1AEAC39A61F0A464:1002911698100101 +# Tests all sboxes +01A1D6D039776742:690F5B0D9A26939B:7CA110454A1A6E57 +5CD54CA83DEF57DA:7A389D10354BD271:0131D9619DC1376E +0248D43806F67172:868EBB51CAB4599A:07A1133E4A0B2686 +51454B582DDF440A:7178876E01F19B2A:3849674C2602319E +42FD443059577FA2:AF37FB421F8C4095:04B915BA43FEB5B6 +059B5E0851CF143A:86A560F10EC6D85B:0113B970FD34F2CE +0756D8E0774761D2:0CD3DA020021DC09:0170F175468FB5E6 +762514B829BF486A:EA676B2CB7DB2B7A:43297FAD38E373FE +3BDD119049372802:DFD64A815CAF1A0F:07A7137045DA2A16 +26955F6835AF609A:5C513C9C4886C088:04689104C2FD3B2F +164D5E404F275232:0A2AEEAE3FF4AB77:37D06BB516CB7546 +6B056E18759F5CCA:EF1BF03E5DFA575A:1F08260D1AC2465E +004BD6EF09176062:88BF0DB6D70DEE56:584023641ABA6176 +480D39006EE762F2:A1F9915541020B56:025816164629B007 +437540C8698F3CFA:6FBF1CAFCFFD0556:49793EBC79B3258F +072D43A077075292:2F22E49BAB7CA1AC:4FB05E1515AB73A7 +02FE55778117F12A:5A6B612CC26CCE4A:49E95D6D4CA229BF +1D9D5C5018F728C2:5F4C038ED12B2E41:018310DC409B26D6 +305532286D6F295A:63FAC0D034D9F793:1C587F1C13924FEF + +# Tests the permutation +0000000000000000:88D55E54F54C97B4:1046913489980131 +0000000000000000:0C0CC00C83EA48FD:1007103489988020 +0000000000000000:83BC8EF3A6570183:10071034C8980120 +0000000000000000:DF725DCAD94EA2E9:1046103489988020 +0000000000000000:E652B53B550BE8B0:1086911519190101 +0000000000000000:AF527120C485CBB0:1086911519580101 +0000000000000000:0F04CE393DB926D5:5107B01519580101 +0000000000000000:C9F00FFC74079067:1007B01519190101 +0000000000000000:7CFD82A593252B4E:3107915498080101 +0000000000000000:CB49A2F9E91363E3:3107919498080101 +0000000000000000:00B588BE70D23F56:10079115B9080140 +0000000000000000:406A9A6AB43399AE:3107911598080140 +0000000000000000:6CB773611DCA9ADA:1007D01589980101 +0000000000000000:67FD21C17DBB5D70:9107911589980101 +0000000000000000:9592CB4110430787:9107D01589190101 +0000000000000000:A6B7FF68A318DDD3:1007D01598980120 +0000000000000000:4D102196C914CA16:1007940498190101 +0000000000000000:2DFA9F4573594965:0107910491190401 +0000000000000000:B46604816C0E0774:0107910491190101 +0000000000000000:6E7E6221A4F34E87:0107940491190401 +0000000000000000:AA85E74643233199:19079210981A0101 +0000000000000000:2E5A19DB4D1962D6:1007911998190801 +0000000000000000:23A866A809D30894:10079119981A0801 +0000000000000000:D812D961F017D320:1007921098190101 +0000000000000000:055605816E58608F:100791159819010B +0000000000000000:ABD88E8B1B7716F1:1004801598190101 +0000000000000000:537AC95BE69DA1E1:1004801598190102 +0000000000000000:AED0F6AE3C25CDD8:1004801598190108 +0000000000000000:B3E35A5EE53E7B8D:1002911598100104 +0000000000000000:61C79C71921A2EF8:1002911598190104 +0000000000000000:E2F5728F0995013C:1002911598100201 +0000000000000000:1AEAC39A61F0A464:1002911698100101 + # Vectors randomly generated using OpenSSL 0CEB1136A85AD37A:9CE3A1058A483F55:309A4B21A2067196 @@ -4693,6 +4748,8 @@ D6A025B07C037A6E1E0653E828FB9E3A3587CDDA5325D4DAA743D113D995D6AF E07306086FA442A42B107F7F355359DD972BF070C0C71FF5C37FA7C259C7E039 [IDEA] +7409000000000000:E18315C171B83765:ED1BCC9E9267925F3132BA3A8CF9B764 + D53FABBF94FF8B5F:1D0CB2AF1654820A:729A27ED8F5C3E8BAF16560D14C90B43 848F836780938169:D7E0468226D0FC56:729A27ED8F5C3E8BAF16560D14C90B43 819440CA2065D112:264A8BBA66959075:729A27ED8F5C3E8BAF16560D14C90B43 @@ -4720,6 +4777,86 @@ FAE6D2BEAA96826E0A141E28323C4650050A0F14191E2328050A0F14191E2328:\ 85DF52005608193D2F7DE750212FB7347B7314925DE59C097B7314925DE59C09:\ 00010002000300040005000600070008 +C309000000000000A02A000000000000B03D000000000000C942000000000000\ +2B4C000000000000A04E0000000000009857000000000000C860000000000000\ +0063000000000000F2660000000000008698000000000000729D000000000000\ +34A000000000000023A500000000000010AE00000000000025AE000000000000\ +30D600000000000064DB000000000000BCE1000000000000F6E7000000000000\ +4AEC00000000000080F9000000000000E0FE00000000000061FF000000000000:\ +9C3C4F44BB50DF7367DAD70E6FED04E0AEB0344116C6E41F66A1A304E822132D\ +8AFCC1727259D93DD6E742EAEF2FD8C03EAD7890DC4EFACBB8776F3439A3DB1B\ +55D47DC6BC4A43349BA9E85FE178CD1ADBDD4E9D19CA1E7659341251586E1386\ +4A8C4E93A2616A0C18890A622452AD9FD09CB1A9CDC83ABF2FCFA325FA011731\ +9C924852D426132D05DA82EEBC3C261A6036C6477FBE3F65C40B8B02C2F9D8C8\ +B3084034AB3873CF22F20759C145ECCE92CE6B557D6DB959DA0B8AD4E0DFBCEA:\ +F2022315280960F16FD09741D13F693A + +7CC254F81BE8E78D765A2E63339FC99A66320DB73158A35A255D051758E95ED4\ +ABB2CDC69BB454110E827441213DDC8770E93EA141E1FC673E017E97EADC6B96\ +8F385C2AECB03BFB32AF3C54EC18DB5C021AFE43FBFAAA3AFB29D1E6053C7C94\ +75D8BE6189F95CBBA8990F95B1EBF1B305EFF700E9A13AE5CA0BCBD0484764BD\ +1F231EA81C7B64C514735AC55E4B79633B706424119E09DCAAD4ACF21B10AF3B\ +33CDE3504847155CBB6F2219BA9B7DF50BE11A1C7F23F829F8A41B13B5CA4EE8\ +983238E0794D3D34BC5F4E77FACB6C05AC86212BAA1A55A2BE70B5733B045CD3\ +3694B3AFE2F0E49E4F321549FD824EA90870D4B28A2954489A0ABCD50E18A844\ +AC5BF38E4CD72D9B0942E506C433AFCDA3847F2DADD47647DE321CEC4AC430F6\ +2023856CFBB20704F4EC0BB920BA86C33E05F1ECD96733B79950A3E314D3D934\ +F75EA0F210A8F6059401BEB4BC4478FA4969E623D01ADA696A7E4C7E5125B348\ +84533A94FB319990325744EE9BBCE9E525CF08F5E9E25E5360AAD2B2D085FA54\ +D835E8D466826498D9A8877565705A8A3F62802944DE7CA5894E5759D351ADAC\ +869580EC17E485F18C0C66F17CC07CBB22FCE466DA610B63AF62BC83B4692F3A\ +FFAF271693AC071FB86D11342D8DEF4F89D4B66335C1C7E4248367D8ED9612EC\ +453902D8E50AF89D7709D1A596C1F41F95AA82CA6C49AE90CD1668BAAC7AA6F2\ +B4A8CA99B2C2372ACB08CF61C9C3805E6E0328DA4CD76A19EDD2D3994C798B00\ +22569AD418D1FEE4D9CD45A391C601FFC92AD91501432FEE150287617C13629E\ +69FC7281CD7165A63EAB49CF714BCE3A75A74F76EA7E64FF81EB61FDFEC39B67\ +BF0DE98C7E4E32BDF97C8C6AC75BA43C02F4B2ED7216ECF3014DF000108B67CF\ +99505B179F8ED4980A6103D1BCA70DBE9BBFAB0ED59801D6E5F2D6F67D3EC516\ +8E212E2DAF02C6B963C98A1F7097DE0C56891A2B211B01070DD8FD8B16C2A1A4\ +E3CFD292D2984B3561D555D16C33DDC2BCF7EDDE13EFE520C7E2ABDDA44D8188\ +1C531AEEEB66244C3B791EA8ACFB6A68F3584606472B260E0DD2EBB21F6C3A3B\ +C0542AABBA4EF8F6C7169E731108DB0460220AA74D31B55B03A00D220D475DCD\ +9B877856D5704C9C86EA0F98F2EB9C530DA7FA5AD8B0B5DB50C2FD5D095A2AA5\ +E2A3FBB71347549A316332234ECE765B7571B64D216B28712E25CF3780F9DC62\ +9CD719B01E6D4A4FD17C731F4AE97BC05A310D7B9C36EDCA5BBC02DBB5DE3D52\ +B65702D4C44C2495C897B5128030D2DB61E056FD1643C871FFCA4DB5A88A075E\ +E10933A655573B1DEEF02F6E20024981E2A07FF8E34769E311B698B9419F1822\ +A84BC8FDA2041A90F449FE154B48962DE81525CB5C8FAE6D45462786E53FA98D\ +8A718A2C75A4BC6AEEBA7F39021567EA2B8CB6871B64F561AB1CE7905B901EE5:\ +9C142A22EDF81444F47272B80A037C169E304393537CECE8003BD80F7B054406\ +3B4A141F9A99D3C6820BAD98BECD914804F389EB2A50E1E2CF22161FC78B9366\ +0E07E2686E70AC0715299C4796F3559FDA802E61CB4ABBF42BAE516BD09FA410\ +085A0A92C6F32A3797D19808D3B3D049B605852E970E5A1B8031D3DC34B5A273\ +F54ED35E21D780204F4B3C512596237153BE9FAF74A44E9A9DCBE96D628AA58B\ +1E3363A94DF540230B38A1ACA440432640E5387D92F1CC1A16F8628A4CB6229F\ +513AB926300668CF97B27643C9C9D0C3030D0CDFBBCB69C3DB199E5D392A97A5\ +1DE6C9881AE5612A69FA0EA026F2F254B929201AFB3AFC8D977C3ED6E12F0118\ +92037D0F49B0144E07A0F0556F0BAC9B3F829C233265439AF711E0B5DD6EC813\ +FD51281E8AA6F031B096C64EE8F03E041FE4DC6B5441141F2D4A308CE8EA77C6\ +483E3CF565EC49CF27A0B13F28D3C63AD7FB6B3A96579D30C9D65F7BA86E56DA\ +6D14AF3C7D170CB5BF5F21C70C1771354DA2850CFF8D9250273828C1FE60C4AC\ +086049404E3D63E04935F03B057B4783B13CF49757A8B5ABB3D2E37E54B881D2\ +36F7DF7FE80E4AE33E9125F54AA96D96BFB15607F0800B215CBF9BB0F7E29080\ +D8504E9BC1F78256593B9565E5AA5FA22032A47041B453D1B154A8D24CD59CF9\ +AA6A8E55363F3DF2B6307ABA5134D67B0DF0AE4FE77F23BF7DF8504FE9DC7F32\ +A8562E2DF585E639847DD624E55B0D0DCCDA72D0F1E072D82D4BC135DC5F7F91\ +30956D401FAB1456527FE087A436C1511CDFEA58202D200E1817E360E8400AAE\ +83B073A63596B033D7E83C6CAB7FDD7069C3B1718EAF60B937CD2458255E68FC\ +D9514FD14AA6E27EC76E75F95F0A678A0F64D49C1B9B8F8DA56DDB8CE640FF6E\ +7195F4A679165F9996F3DDF992E3CB4ED9E9084AFC0038E4BEFB467CC8170AF8\ +F004082BBCB137BBD45C124BE8CEDC89DD565A24830889CE4B9781FC18803BDA\ +1A0A4EB70DA35887B02F18CFF9329E2B7C31B0F5F0648E0508379B52C8FF91CE\ +F939A040A8C20F2F27ED65553680729A2181B3B3C4AA02BFF8DF0A9228A87BBF\ +52B48F473D0F9070C76E4DB6F09FFDFEB629BD0E1944B7016AF34187E2985AEA\ +E30D6480A58F649A0C858E1F1458388A9E822A306AC1AA7465882DE78F242EF7\ +B0CB45D68A057F00D8609587922C8FAD6F1A7FFA34BF2175FC516730A61CF82C\ +6F866C978CC292BCC1F91E6AF1785FCDAA9A43A01E6AEE91E222F8AF8C989F2A\ +4C50B7A1D45BC15E11E5E6E6EF720506B8DF564648BEBFE272C0A77D41295865\ +108150CDB3620970A37DB94F1CC35E434DC33434D99871F6141EB57C9E648AD1\ +BF70E2B7FCEB81EA871DD92F19C366EA532CA4A7BEF9242128B7ADDD308B58FF\ +F5594CB4156A03C6A6ED3F27E8DB20FB2F4208422B7E9E0A4E63A0122560CFBC:\ +67C6697351FF4AEC29CDBAABF2FBE346 + # Randomly generated by OpenSSL A1F4C5FC0AF894FB:1F88AD254A1653CB:69E2F555209FCA21ED36E0243F043537 55E31A38B2C91116:8D57CB7AFB401E55:BC0ED7C4A90FE4760B3D971F0F2589F6 @@ -25242,6 +25379,521 @@ B7EC0258A9AF125F2DDC80B9877EFE0F372D9B832C786770A84EA1A07CB6E1A9\ 2B7E151628AED2A6ABF7158809CF4F3C:\ F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF\ +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F\ +202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F\ +404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F\ +606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F\ +808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F\ +A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF\ +C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF\ +E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF:\ +900BF2352D973046F4128A1489F84DB204C552D2E59FFD58844B2BEA8DC04B46\ +B1212433EA1D3704673C45222C77D3D7CF7D21199BCC1464393853EA9FE5976D\ +D8612F828173D82EAB52C10A863FA549911F9B4CD0644766BDE8412F0458C620\ +EB63CD699CFFAEB948BBE360FDC541F0912B683B72A13306E0203F444E378458\ +164F461290E3F934DA40540945D8FB455EB86271F4D55DEBF1CEDEEA08B7917C\ +2247B1261C3710D949B678CDD4D5DE857A2BCD4751F2D4C49C75D52B33A0B761\ +943CF6258DB7C13C321F2E3C43C680CADA039E3F177B88C993464EBE82732229\ +784D929235FB7E4984F1DBC72A2E0431E7BD976A2CE09931DF2C80B7B7405E8D\ +AEF482E4AC7A0E33C52EBAD9C4F854A061B047F37CF70571FACB6D2CFE6EC0CC\ +64933965D74B871150214A009E998BB078E8799E1B43232F9709F1E5602D2DA4\ +D9725D2EA8557374809285A1B48D489FF3A8A50CDA1E0920035E6924272FA194\ +2022D71C9984278B4112253349D916B17FCB93A59FBC2641EEF4DFAD6FB83AEC\ +D25A6F55F06A95CEBA94557EE07220C51D0DE32969D70DF310B8DB0E7C8B65F9\ +5BB7B14098575CAA8EE472726FF5C87E31E94664FF009793D3230A528E9FE289\ +3210E01870D0B60B1C55A6C49079BC3D97EBA815ECB8DE148A000C310DC372C6\ +F0627EBB1F0CBDB36A79A9DDADACD157B561EFD24FD523067AD3E1DF7370DD78\ +19347C5FCDD7296BD9DD9D940C7956CB8A4ABA3359538474E81613E4BEB346B7\ +4F05C66BC19594C12920CBFC145ADEBBC0511E710A490708B6DF67D8F5C5A3A8\ +09C9C256CD3A4056019E04C27D773A08BFFF86C6F5E9663DE4369AA4612EA265\ +53F5DF2314A8FDFCA42B897B5EEE64FFBB16F67BB1BFB1E5408C850848978645\ +087CDF026C9D8CB24494E42867D5010B66DE211C5E10F92D6E88784E9F423958\ +D0E50E6F153FC9D7B07894D5888B3CD0AEAEA0ADDC058083E84EBE2CA55E4916\ +79BB9476674E8B2D01E17AB60DB86CFFE48AD3C171F427EB57247A5E34970EEE\ +3A4FD9D9FBE9C5F39D326D6FFA45398F822532B8620337EC1846184BB684478E\ +A59D803BFF5F55B4B15F3DEAA58FFB550AC480876DBB16C0FB72E0C224D2FA47\ +BE2A33736208E9DC38EE0E5D050596D692718D9CD90DE7CF9203A6D1FFCD5F09\ +AF6BAD40F006313C7916AFAB0D09220B9F6C7E020EC12D4982A809193EE65DB7\ +EC04B94F580DDF15D6349279FEB9679FC9083ECD1FB1D9B58E2F81D07E586573\ +AF0C61BAFC811BA0D15186F408760314724742143B1A01AA0038EE1BF4DBAF4E\ +85CCD3412B4F17629F069E6F4F24CFB28B4DAC1B7ADF3F2AB621B62D4239C842\ +5B93CB597D2C91FD9F4E3FFC6DD70CCFDF5CD8F42E29344B6D1ECFA073C853D7\ +EB1FCB34EFF9111D90557E15B438D8AEED879991167D04BDFFD42014BD12631A\ +D879A98BA029DF7441C7242F0FFC0EF25E36391EF4D151BE45C6D6DD10B5C591\ +AA039507BF3513BFB36BAC155564B9CA65DB8B2EB74E10C7371090C1DCB54B65\ +F9427E830CF1EC7B43FDD5E7AF72C8FDF19B709A41F9458A1A69D8FE8332442F\ +5D1326597B429D065F17005C90DCBA83833369AA2F8CFE860C7B25269049425B\ +1AAAEEBF873D32246A4EDDE5C42D88DDB5EA5DA95BF7DB2B97B3C37F4593D4F8\ +BDDD2EDA804337307E6C68952FD7FC0A55E2673C08F028522CBF7000CDA1E335\ +23AB0C607CB8361E95CBEB06025636D94E945CA9E911FEA1CB37728F76D2BF77\ +6875181EABEFD2841EA068EEAD02A945AA68FB64ECAC7EBFFA9EF739D534B7BC\ +06F9B57ECE9CB9CB8D7977128567293C51E79A8126669925214AB99577019512\ +A72A537429CF5B10FE5B39AA2566AFA490C6FA42916D414173BFAEE8BAA851A7\ +3D6E55D0A48A9F47BFE67EC5D27BCE42D7DE7BF52DCE4ACBED91C5E52414D09C\ +8119A3270709EFDF1AC93598EE5D3FD58436465C65C10FBC7E5E830B9E0131D0\ +A406777FC79362F660F8D9D173499326D8D87B1A64952688D72C83ABBC5528A7\ +8F57E38E54FF82CF826878D73F7F374284181D467CBC0C1CB980BC3CD3179542\ +663B35EBDCFC45F2810A2CD83F3E8EEE11C7550C3F105153886FD0228C4368DF\ +22B3483905C4EB8CB841626CBDB46010FF6FAD1783D518E9030E0D01C1A28470\ +9E56CBB29B18E269BF32CB310AF67FDE673AAAB9D5D05FF067650E9C2320BD29\ +4AF308F97547FA907561C6759957E19727BCB6AA81B0668AA891B524A44A9747\ +188806005F497B0F06C8F29277F0532CE48306CB2AB1F4AC69189E48E958CDB2\ +52BEAC88343FD10F61D1BF2DCD2347407C4F449738D29FDB3C40BCE2381154DB\ +9B3CB1241BC1E682EF2C7845ADEDBACE1DE98218F967C058CD6861CD66FAF98A\ +D2BFE088DB945EFA1A5EC31C63F4AF18A7E26DAB81333B2D1D1B64ADB0F0B628\ +941712AC56D651AAE05C5D4C5ACB7FA3AC16A1A3D22395B76371ACC9D4CC0472\ +59B1BD1659AB6987E4CBB363B2E2378D5CCB15C41ABE14B65B920F58356653E0\ +240181B2192107884699352634712003815BEB662F3D31F1EE213E43637738F9\ +DBDDA96524CBB76FF388C93CF540968D41CD79D6F575B47E8A4C8576A34D864F\ +CF15DE44929682C7024F5B96250449649697EE056F1FDA1A0D35953F03E88DC3\ +B35913024218DF877B75BECE027A2A7EF7C76BD650E0586D404934E344B8C737\ +6A601998294C196D0D221CCBB59AE05F7DED4E355B3FAF1D0C51DAA055F92544\ +0C272D41911D83AABEB3638316F1AFBF7BFFDAD1E800F296323AA33A7853644C\ +EBF3733BA2748DE7D37B9AF8A5A4C05B74211B359B0E6B518B10A012B4F71888\ +65AFDBAC2CE1D53B9F3E8F7F80BA15D11CF2967C42662FC4177D2E3C00D3DDCF\ +581B8FF5E6544F312AC52D93B7A0789C2DFB187E10EDEAB3BA6E74B9B685F1FC\ +924974A4D0302C89C6709CFDAFDD6B235AE0326D8E22D164390620DB012B85A8\ +1560896F2C085307D07F3470887541EB5ED2065261C87ACA522E83C2CA77D9A9\ +751DF6DE35EDF82E04F55CC9A50F5646254EFF10612AE8B5010B4F1886262666\ +B997005F452CDDAD9E7FA8185F64B601171879FDDE907F8C35F8F100B942FADC\ +0D9F4FD734B462866E42CFDDE56DE0539EF8F71F0AA72DCD8DAC6BB031B89C8F\ +0A88C051C5E4E28EA5E95A925A88611EFD7EBEBE524F60A9EA32A41FE3477709\ +1D401429EE7F185EE61DA6486CE491F09A97062BE1A357DF998775143C7D1FF3\ +3A1EA9041241495473661FDF3E908AC9F5811FF83EFD6E331FF17097109FC662\ +20B989428D078263FF696CA376663888819F3AC66F0BEBDC5EE5BD48C347C124\ +FF427A47C80B92761A90664BABFAAC275A3069B13890B79E9513A935823FB608\ +23D6C76A9F88DCE6A7C1F11E3DA5068F454AA317FCF92C4BDFF500A2BEA63BB7\ +D4939F4440AE335C1E165769C5D041B31873BECA28648D44DB6628FCC0705B5E\ +4CC838C1DC8022D9B890FCD54CBA42B372610E9CE351E5FDFBE46621768A30CF\ +70969FCB37C484B2595B5291FE7E8B597DE9986271AFCD2DEE3029DADD330FD5\ +EB38D7BB5276423DEBF31DFE3BB97E36D09FC62823060A0D2636CAB111C7C9D2\ +7DE3D2436996F6CBCDADA9BF7AD9B4EFF7EED2459DAAEE42AF414BDB2C799500\ +3B2DF8474EA76BF08870317EB29AC6B46D19DFB471A8FD58EEFD58BD4436C30E\ +4A695A30B83E53854AB12D4F0CB6290385570484CD78128782C55783E73DEDD0\ +EF8330690D2CCC67A6C3A5C0E5824A4C68ED1E9DE7C047C3A27D838677EC1CA6\ +4EA21D7F51BA404CDB61F09CE2F3CAE82E68BEF8EB0BFB6F51F1D711E68BC700\ +0C57170BCE6E6CB583CDD384B031552B471DA6E4AEDFC6E696EEA1D4E48CEAC0\ +8202D8C0626D957C1BA8D367C647C95BEC5C97448F0B0DED70E3DE200ECDBC2E\ +2BF76600E838C2D52DC2799C55ACD450C5C33089485F65219B57A09756792353\ +A80184B1FEBF9F40E7C31150C35BC9ACC208693A30594CEB60FE53D4EF4852AE\ +CEF9CD128A0DAC72A323396AE9DF8406223E554CDC0D3DD2EC641FB19094239D\ +186BBCBCDB685A5ECA4945C0FA7B2F0CF0D42ABA7F5983D5B765168197B0556A\ +235AC452CC42D59BB9F27D186E1640E447AA00E3005CF5FA24BC7CD4873CFB2A\ +A4B47528F9813E1881FECB1C072288D8CFA45E2D0C52F17C49E7D73040ED49F0\ +E71B427189A9A038D6F7039B7872A41E2C55E6A95834E9BECE5C70C18F89E270\ +A2D24286EF6C027DEAC450A852804BCFBA92DFD52E7900F7F3E4A957AA4D5943\ +90CD47ED3072961B5D024AA9EFE854E692D64F3CC3123EA52F49A6F61D2316A5\ +A17374EC9FF6F043076C07D597942D25BB0BA1BD71E971C42AA5CE9BB1751134\ +2A3EB35C6DCAF8DC36F762F8B1856E5E7BF492B8A6FA8F1D8AE461515462871B\ +255966F0F5BAA52E73CAAC894C2CB56320155D4E5DBCFA84A0FEE3082D92EBEA\ +98808406E736BE2EC8F41BBE90F07919682183DBB287D7004D2C2622C4FAFCAF\ +A19A766DA033DA12E4BDF7855A08759C9FC6CA0F61B6CF96C492CA8CC168B3CB\ +F7F587B53A7EF630B5374690000D9E7B84C3AE7832F4BBDC1943378F83007660\ +DC83CB4F05E7A93BC6EA39EAF13CAB2E61C852A60A343247CDCBFD757B247539\ +9051924A93731400EB91791C5E2DA5D03F43A39CCA44F3124DEC80D433AFBACE\ +19660D0D32BEC383C1567549C112CA8055D3A1A7811A7F4F036AAE719762F98A\ +3BD8CF5FB2D9673BC163ECCCC72328F13B03CC3C249C7AFA4041C0DC76E9A809\ +4462CB41E9711A6F5E50E5D5473143F1E9AEE421D6FD88FAC95BCD75E46E25D2\ +588F7E3D7489DEE5E7AFE73AB038D4C845A92B1C0C399B698F8E532AAC023CD1\ +489B986BE46B7DA2A4B76AA76DF5F7FE1F66C282AB30ACEF5A7FD59B71AE64DF\ +858D0E0425089290913B3C4CC82DF6219DE24ABC8703ED475D8373402EF46526\ +416F2ED77AFC236C4F3EA0DAA5AD9AB949B024F340C6F1505B399FA703B6464C\ +0098FAB1A3DEDAB5BE68C2FD030DEF738CD027FAE6CD4B03A2354D20ACE3F69B\ +EDBB90A5FFC390BFD90D53695CDC136B85FA6B9649CB4841C43D5C9F649E32C4\ +10419B5EADF4D26AC0D36006D3CF4677FDD2FBFAAE156F2DA1587FFE4CEA0392\ +AE804420E2FFED43935135F441CE90B7077D8E0B0F77706AAC6A9E23DCFE15F5\ +635A0A1E1A315D8AE0489BA6DD88A1C8EB29BEC076F2E95627CD12FF4D6784FE\ +F2DBA9F5BAC6F1895E5F15AE2E51A1D65B7835CCCA3B2AC7D4AFB05E00D21051\ +9F932D184340625647DE20BFB32329C238AC096CA68E159F90CEA319683F1C0D\ +9DE2380438BB4E6DCFD358AA655D0F78C9E93B23C0F1BF13C128587E65B23C7B\ +87350F1A5B8C37B5BB5971F4A160C9A7FC3E920F050353739B4C2523F1F628E8\ +B4988047EC59E13F120CC557E14EF259CB15BEBE470008D1C0BAB2B6B50AA6FA\ +379488B3553979BE4841441F971299C46BCEB73BCFF4ABE0B2B003C7E5C110FD\ +A68D63D264F95D5E9C194B4B869F420EB9B93531396512AFBB6FED334FDBFC97\ +2E9BA42F3E3D774A7C6F1685DC8805DA4E10A150D90E79828A600F242BC2B7FC\ +2EE22BE0EA362D687E6B2E4191C268EAB6189F58968CACA413F2E6D1A413E37A\ +C4E93E8A7C3E13D992D09E7025D48E21F658F54B2354A1182F1203C21F05831B\ +7B83308DC2A8F6F2E3C97592B252E66CDF43529068D9DC78465F66CA6B29AAD0\ +C3922947EA98CCE6630EB581FB75F421D59E36DE1F4BE9D7BEEA0C75218C574F\ +B70E5927162DF36AA1DDAE51428092B8A733C8D65E884FA48B6A4A6F2D386883\ +D3BE615EEC10B3488DE1D54908AFDBDA76CC54BC71A7131DA141ECFBBFAECA0C\ +193B83E8DE2ABCDA150629D8BD1706D16E4B2BBA4FB95A4DBD1B2E73071682B7\ +B38142699C998631B31F53DE66B0C3AF8C799FE21E617F49EACCBAD64B76EAA4\ +A21E7ECDCA1114B1C64C2B2A71B5BC764EC880E866AF3EC6E3801213341C998D\ +0F00B9AD7B7DEEF21C0033247DCE567FECF294B16DDDC3346725677442A6F6FE\ +C62627521EFACD02E16123623ECDF970493B9C8B9E10156A9B2439F03096B170\ +93E5DAC3C9048EAF05CE92B8C2FB2B671AB886E5988288914B5A8DAB05909181\ +A5F9142EC46D5FA71816CD944642D0568520EB87A4307FB4B608D4EAC1EBE88D\ +D52F6549895F732CB75D495F5F2325D2B0FFFE0FB702045188BA98D603E546F0\ +9F44BB40804F4670BA22F9D188F986F00FC2BE3BC29E0D387985F564599DB2B0\ +F9149BBA7225F00D6316455E2713E43E173A9418C5C4EAF5D3CF2CA4FDA77DE4\ +66ADAB5BF8A2FE395E9DCCDF040ACD903F13F1807817251B4844B12F7723627E\ +3B66211258BAC1F45B26AF3303D1BB55241BB4EE3EB9F00050AA44DE7A81AE55\ +01EC7ABF1A1692F3CE17267A1A83E6B870777C6249780B655008FF69C6EF3A32\ +AACC1E4A8CD2CD50115EABE08E4A085AD93351DA04E5AC71C5FB74FAD7864324\ +C070765C32ADF07071632767C5D0612B4B9407EBFC3141D6D8B202DFE164CB8F\ +7112E3AE5176AA55779441B1352CF4838395A65ED5261FCD8C596CBA3684A56D\ +C2FD5E440CACB2033C945E65EB9EC0E475A7CB3E67C8D5F627F506F6CB1D5A1F\ +26F75A395056A1D8D70420B13F63834201AAEA6C11CC6E55BDE40A0ACC75255D\ +06C5921A85D621B1C32434AE8CDA7925BED56718BA59CEE88896139381809548\ +A0AF81502DB88439A48999A3B40C6FA62EBFBBB1DCB03409C73CECC4509BC4F2\ +D45E7382D4AB7F69386FBE6377876D0D30D5F4DCC6BA7330987B48C977241094\ +2B114D6F0D46AE5F3FDDA09618BCD78F0D9972DDD71DAC9801CDEB80676BBB32\ +315888E008DA9471855C2B299927FFA73EB7A4754A2F9A80500629959830BC31\ +41A6A3FCF3F529DAF588B0C415A6D237145BC3475724072D543D78F69E1F1530\ +86ADC5E28B420A3B1B81E139CE9B81F532FF557DC23BDE406373B10F5C03E230\ +8C9F51D5E0150D6128A1BF82FFE1069849CDF84FDE7E3DF994608C5E0B242088\ +9408D8DEF8DFACF31B539D3429470785FEA4E5480AA0C93B5C8225901F3177DB\ +948DE7352882A9915B8D2332A85F16A4D1CB55EEF211E3190FB718D1D302A171\ +EB57C234A5B1E5A6A297E7AE4BC65752ECAA27412D2A6835BC69229E7593A23E\ +B1224E97419BA6A17BD77F9FDBE30BE2BCCF0BEACE22576C0570DBE4FC885192\ +C11998620066D8CD92DAFD200B3D483FB825523F490CA75971D066647A885543\ +6084B047C78D6581C1FBA6276B0A7729668B3B0D7D358FFB92332C57436F2F59\ +873A1CDD128AD11341B5F256251B61C90C365D5F0768F441562B3FCD9E27A713\ +06B7C940983560461889455560D32532DCF45E9DEE3E2B3C5514E249344B4DDF\ +105774935D5AAD836B04B5E979E61E3ED7909A8384CB0C866352E7A1C7068B73\ +68BEC60EAFB4A081E553F51B09C4CE8664964F64A4031CF8934382C0EBA040C0\ +F0B2D3C1F5F3ABC3D30785E53F5F081248CC7A6A3664BAD836C1E6CCC91BA1B0\ +37B4F0F2C43AEAF9F749268D47E11F7188BC7264960AE26DB142C9801D084E0B\ +691648AE83E85AD51A0A17081F978A434C82F6572AE0AF94B4A04A5686FF61AD\ +FDDF73E6FD22F6434F3FDA4F0B2A838DF375D3FF92C9192462E8CF44F43AF70F\ +154EFB12D84EBFE48264E55769E997D6F3D200E223DC104987B9786417F3296D\ +732FD45EC48033F00688F92C7B5CDCE46E4BC8064F499F9B06EFF82B70D6ECD8\ +C5A1EB5FFE1D6C605A54DC621D6544322911E827CE798CB0A8CE73C82F863F97\ +934CABBE2CBBB2D2A2A6EBD553E8A09D8B49D87F79F29E3161DFB3EF37D5D0D9\ +A93F7C13C2A75CEDB3E61121E85273545E85942EE1C6BCC698515CB8E88E76AD\ +57BBF0FC85B10F10883AC4682A86D29CDD56E5A63751D47F06673F7891CAC946\ +0B4AA9547DFAD60374AF982423D332BE9D7EF16759FB095A698B0DA5D7B51278\ +61A8B39911F717A212C17A9368D2C1E57CDA3032C61C56B84529677905B3E351\ +D71D06D46B8D69CFF8E10D175E084ABD4B36A0A3BA424F6641E917CA1B64A2FF\ +62C6AD6DDE35A51556FDCCCF5428892E8FA6DD45626AAA1551EC7D7E8A89CC86\ +3E5AFD53A0D01ECAFB2A6268B7E0370C376F7A724B1023FFD184D900AA2C909C\ +E156458C7F2504E32FE615A90DDF360C7F0B7708399AEA3BF3549A401BEE0CA1\ +FC0D22F1871967DFEB0B740FB93151B7EDD2D807DEFDE734BD1C22A19E1D0A01\ +01071A8DE3FF8007068E2E5CC43EB334055E292F88EA02D52B9771ABD3577B22\ +E7236AA3B511C5E914AEFAE9C5B015F8AD013C109849CB5150298FD56E9CCB1D\ +B84CE6A34219303322FBF38F9735414DFFE395ABFB19F1798894EDBD1FF77530\ +741933847484965C3E25509BD31E6E6DC247E9B17AF7EE350B00816DC1DD0EA4\ +4792C6EE83541153208E0104BE27F055335718B2BA1AAFAD3EC4D62B952ABEEA\ +D95B857EFA8F26AEA3E9FCB087A80D7DDF3BF29D63BEBF3A248A8D86A4C208BB\ +7A3EE0836869074438C418254BDFC5A2A04C5FB21606B21AF22BC2631A46BD55\ +5BE9803EF4330B9F6C8C7C93478819EE8D2A0C5651C0C5AFCE5F20EDF72DBE83\ +15E0BC8BDE40F09C80E760A804DB197977217F10BDABB3A14A23B30DBF3CDB2B\ +BE9DDB141A9B115D16CE0CEED99E120514BCBD0DDD934379B9C48016A0101512\ +84377FB6B8E08A703CA401CE018F61D6D516C83F95499943EA2C818E315769C2\ +A45172DD344ED15DA05D8AB1C32E4F2E7DE3ED5BD46E956878F266E27CBD65FD\ +775B13FBE330B01C31AC5C27C8DD30F0240F5B9C024A6984FB7131C8CA04A608\ +7091292D53AF14ADE0F2190E0F427029D0F27765BBD746DE5E2A9B8933DD0CC3\ +B1CD1126551378372AB4C16AC49ECCBB107F71D7DD4175ABB0DC477E1B4FCCC4\ +2F868D7D8D737BEC4B5CE078017352D36A45CBE6E9CB676ECB84F5703445D429\ +70D99F5744A008E21A6EB7A7A699C2435FC669DA5A8DE38BA98E6611DD8DE454\ +82273C7DF9702BB10D345B826518F38789E66C62E0465D3874209350890EBBC5\ +A3F8F132341CD58E7CC9E43B22C579BD938792C8B158ADA14D94F8179DC180CB\ +B0280A6101D7BF2D17C0557F920307155E8DF1D95AE124FF9B91F9F2B9D4CE3D\ +131D6DA313EDE0F09ACC122CAD8A296B5F806BFC2CBE5D8E526F020BC5BF5D5E\ +D4728F818210F5E2A570B534DC39890CCD1FC48AB7AF86888E9453F3607401CE\ +B4C22E3F960E7A8A5C80EBA5DD3717FC1224D190D4351E4944B4C23A949614D8\ +84D2AE59D989FD53302C83D66B26088C37EDC61207234F9B8EABEF6BF457BD61\ +EF4B77D198B7A56B00FA723B4CFBB6E2CB116DAB87DE542FACC26A8A9F2B841B\ +2F26B1C0B6D22172CD5C1AC70E5C5C1288BE1BB0EFC9F2EF68E0F88B8A6DD467\ +F8C21FD4AA5C467C5D2ADBE9A72BB6F44262BBF4D23525D0D2527A06D740BC2B\ +D45A3B8CB96CD66307242351D6B6A7C1B6E67C7A84E2FBF61AAB52E5701F51C4\ +480093AEB29168AF847B48254CF04D1418C77AE1680BC564C5DF597308AFFB21\ +1B3CAB194D8AD0427AF89E0B55F65C2827CA704BE1B854A819FF87E4A6DF735D\ +107422890DA141915D1687B56D2F1C5F007684331C7C17890E887390822AED10\ +377F271A36855DD8687D9F476F3B1642F1388F121814C474778291202B97333C\ +1AC5D6E1818FAD8AA2B9446840CC0D29EEDF118D53A15763ECCD692A0A92611B\ +CC49F3A50C03A4E7C39BF3C545D9B2C2A08D3CFECBFEEC8D846D325396CE3027\ +5629AA3914B7CDDB05959A5EDB2DC952B28ADEB6B16197DC22D0F6BEB17126A1\ +E2E0C66BE205E37E4AD7FEA34DCD7B406A87A155216009AC43AE89CB0C036433\ +D736F5D9F2FE2FA091C28781602A59EDF96127C31265144B20360BD64DBDE811\ +6E84A9E41F8259D9A6CB4E3368A646413FC23D76F55B4083F4420C1157A1D9B5\ +EFC27BDF72B1FCB6617BF40CD8FFD2FCD645284321390BBB6707CE8442ED8116\ +3CA30A924CC9B5BD8BADB02CD15847F1893A7E94F82C06C19BBEC9E46B769DC8\ +53A2B9EDB14BCE4BDE8C6EA26A9510B6A8ACC62DCD55DCCC73DD962BAB314CDC\ +65F9AE4BAA7FB4563CD38CFC6A6AA7A60E6D9C9FAAFADC55A8A207E9C2ECF21C\ +343ED29113DA4E6E2EBAD2ACB1DBDA9652EBF1D20E8FA79533670DE60CFE73BC\ +F469A8D89B5D6B2DCA831CEAB441F5540B4C4EDCEFD246478BD068FFDEB22F69\ +2DE4D814CEB4C105CA55AB82398D21CF7C2F992161B7D961F2FF91DE1C0ECA85\ +4036660BBB67071690C8E2DE999C809190D8DB16CCBDD971F4A0068F98129EDD\ +0453ED31BC5724BEC70FC5CC79373CF6FA5D87562456538735D50674863F219C\ +E5B3E61B1ED02564644DAE69BC0CEFD6302464042ED1CB8B741863FE00911729\ +A0FBDEEDDD00FCAD9A80C88077750ADFFDBD921E2DB19070A41444FFEC61DC8B\ +3D0221D336A5ED40A9C7BC7461AB8121CD4E9BEFB4755EEE92B8B3EDB2751D05\ +028E5279233A44E0D4A205BA1F864FD5A0115272B4B2C7AA8E8D3D202390DCE8\ +5A47DF27909DB1CB7BDC29DF6FEEDECCC6814068F0C87513AB975977C7563E41\ +F7E0FA1864F9CC9B5778F23A11B7D67D15E7D1711F2A6CFA4AA7DB1996B73259\ +F791BB8FA73C99CA04BD837C8E7235624E6AF48EA30391B32B55EC08DF2F25B5\ +4BF663871D439C57A9400E6973B723CEAC8D55E01BE30841061CDE175DDEF36A\ +E57DFD000B38155349703E2C9D10549890B7846C61ED62A6193AD3DE03A3F242\ +75DE3FEDFAF9C384B601F0C1213F46A90BE8E3B97EA11C31880C9F905221064E\ +6A7C297E300FFFBDFC0FC6A1C05ABB0D56F9918501E3EBBE84F986CFF4E94FBC\ +1E71B98B315026E4EAB1C22634EE50BEFE7426FF41ECD53152344EA558FA9E9E\ +CF80FF1C01335021C06BC46ADB15707A025CAC95D564016EEB1D192D93B94900\ +CB346169BB1A18F91D88266D312A4BF5F050801C60FC681E3ACF1B1364422E07\ +08120AF483A664D067273293687B3E321508D59BC60B78D0C9B46D3E4E5751ED\ +038C228899BB3CC32239E5AA653012C656423222F2D04C213A5DC78005B739FA\ +F522B17AED99542BD9B6543E4E9EC1A536667B484B412802F17704B99DC3246E\ +F9180A0FFA1C269F0BAFAF79B1BE323F3F2D045A979A46A6B45EC9609C8BF2DA\ +5BD40A2454D80DA1CFF9FA75965FFACEA20CB0F8ADC881EC8360F82BB297A657\ +0BE1F8FAF0F10AE84645591974F7C246338A45443AC2B9DD7B8151A6351A001F\ +520E4C6EEC800283609F16DA88396852BBD27C4FEA4EA0C2FAC4FB6B3A8E993F\ +6E91DD06D461828F687FBB061A57E118D5B6D8EE5CFC6D453D48DBAA7CDE2C4B\ +9CC226416A0B1D3B1BC6C1F429C481C187E0F6D022ED4110A7916D891E98600E\ +A01263FBFDE28265F924F1E95F7B68C95DB4DA20EE37171BBB05637A883637D5\ +36ECDD9D7B6D36C15E255C1C024CB26BF5092A631A29B78454FDA73029266284\ +9E7B83F71D419B099E31A2420699F4F37378AC5C1985194C44A6F38A2F0D2CDF:\ +FDCD25C05C5D2EEC19F325924BF2F7AB:\ +D3BFFE7D9A480362532B542007577EC6 + [AES-192/CTR-BE] 6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E51\ 30C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710:\ diff --git a/checks/x509.cpp b/checks/x509.cpp index 43d374411..8c6cd8187 100644 --- a/checks/x509.cpp +++ b/checks/x509.cpp @@ -159,7 +159,7 @@ void do_x509_tests(RandomNumberGenerator& rng) /* Create user #2's key and cert request */ std::cout << '.' << std::flush; #if defined(BOTAN_HAS_ECDSA) - EC_Domain_Params ecc_domain(OID("1.2.840.10045.3.1.7")); + EC_Group ecc_domain(OID("1.2.840.10045.3.1.7")); ECDSA_PrivateKey user2_key(rng, ecc_domain); #else RSA_PrivateKey user2_key(rng, 1024); diff --git a/configure.py b/configure.py index fee244592..50dc246db 100755 --- a/configure.py +++ b/configure.py @@ -6,7 +6,7 @@ Configuration program for botan (http://botan.randombit.net/) Distributed under the terms of the Botan license Tested with - CPython 2.5, 2.6 - OK + CPython 2.5, 2.6, 2.7 - OK Jython 2.5 - Target detection does not work (use --os and --cpu) CPython 2.4 and earlier are not supported @@ -29,9 +29,13 @@ import logging import getpass import time import errno +import optparse -from optparse import (OptionParser, OptionGroup, - IndentedHelpFormatter, SUPPRESS_HELP) +# Avoid useless botan_version.pyc (Python 2.6 or higher) +if 'dont_write_bytecode' in sys.__dict__: + sys.dont_write_bytecode = True + +import botan_version def flatten(l): return sum(l, []) @@ -41,18 +45,14 @@ class BuildConfigurationInformation(object): """ Version information """ - version_major = 1 - version_minor = 9 - version_patch = 15 - version_so_patch = 15 - version_suffix = '' + version_major = botan_version.release_major + version_minor = botan_version.release_minor + version_patch = botan_version.release_patch + version_so_rev = botan_version.release_so_abi_rev - version_datestamp = 0 + version_datestamp = botan_version.release_datestamp - version_string = '%d.%d.%d%s' % ( - version_major, version_minor, version_patch, version_suffix) - soversion_string = '%d.%d.%d%s' % ( - version_major, version_minor, version_so_patch, version_suffix) + version_string = '%d.%d.%d' % (version_major, version_minor, version_patch) """ Constructor @@ -66,7 +66,9 @@ class BuildConfigurationInformation(object): self.python_dir = os.path.join(options.src_dir, 'wrap', 'python') - self.use_boost_python = options.boost_python + self.boost_python = options.boost_python + + self.doc_output_dir = os.path.join(self.build_dir, 'docs') self.pyobject_dir = os.path.join(self.build_dir, 'python') @@ -75,9 +77,17 @@ class BuildConfigurationInformation(object): self.internal_include_dir = os.path.join(self.botan_include_dir, 'internal') self.sources = sorted(flatten([mod.sources() for mod in modules])) - self.public_headers = sorted(flatten([m.public_headers() for m in modules])) self.internal_headers = sorted(flatten([m.internal_headers() for m in modules])) + if options.via_amalgamation: + self.build_sources = ['botan_all.cpp'] + self.build_internal_headers = [] + else: + self.build_sources = self.sources + self.build_internal_headers = self.internal_headers + + self.public_headers = sorted(flatten([m.public_headers() for m in modules])) + checks_dir = os.path.join(options.base_dir, 'checks') self.check_sources = sorted( @@ -89,30 +99,43 @@ class BuildConfigurationInformation(object): for file in os.listdir(self.python_dir) if file.endswith('.cpp')]) - def doc_files(self): - docs = ['readme.txt'] + self.manual_dir = os.path.join(self. doc_output_dir, 'manual') + + def build_doc_commands(): + yield '$(COPY) readme.txt %s' % (self.doc_output_dir) + + if options.with_sphinx: + yield 'sphinx-build $(SPHINX_OPTS) -b html doc %s' % ( + self.manual_dir) + else: + yield '$(COPY) doc/*.txt %s' % (self.manual_dir) + + if options.with_doxygen: + yield 'doxygen %s/botan.doxy' % (self.build_dir) + + self.build_doc_commands = '\n'.join(['\t' + s for s in build_doc_commands()]) + + def build_dirs(): + yield self.checkobj_dir + yield self.libobj_dir + yield self.botan_include_dir + yield self.internal_include_dir + yield os.path.join(self.doc_output_dir, 'manual') + if options.with_doxygen: + yield os.path.join(self.doc_output_dir, 'doxygen') - for docfile in ['api.pdf', 'tutorial.pdf', 'fips140.pdf', - 'api.tex', 'tutorial.tex', 'fips140.tex', - 'credits.txt', 'license.txt', 'log.txt', - 'thanks.txt', 'todo.txt', 'pgpkeys.asc']: - filename = os.path.join('doc', docfile) - if os.access(filename, os.R_OK): - docs.append(filename) - return docs + if self.boost_python: + yield self.pyobject_dir + + self.build_dirs = list(build_dirs()) def pkg_config_file(self): return 'botan-%d.%d.pc' % (self.version_major, self.version_minor) - def build_dirs(self): - dirs = [self.checkobj_dir, - self.libobj_dir, - self.botan_include_dir, - self.internal_include_dir] - if self.use_boost_python: - dirs.append(self.pyobject_dir) - return dirs + def config_shell_script(self): + return 'botan-config-%d.%d' % (self.version_major, + self.version_minor) def username(self): return getpass.getuser() @@ -128,8 +151,8 @@ Handle command line options """ def process_command_line(args): - parser = OptionParser( - formatter = IndentedHelpFormatter(max_help_position = 50), + parser = optparse.OptionParser( + formatter = optparse.IndentedHelpFormatter(max_help_position = 50), version = BuildConfigurationInformation.version_string) parser.add_option('--verbose', action='store_true', default=False, @@ -137,14 +160,21 @@ def process_command_line(args): parser.add_option('--quiet', action='store_true', default=False, help='Show only warnings and errors') - target_group = OptionGroup(parser, 'Target options') + target_group = optparse.OptionGroup(parser, 'Target options') - target_group.add_option('--cc', dest='compiler', - help='set the desired build compiler') - target_group.add_option('--os', - help='set the target operating system') target_group.add_option('--cpu', help='set the target processor type/model') + + target_group.add_option('--os', + help='set the target operating system') + + target_group.add_option('--cc', dest='compiler', + help='set the desired build compiler') + + target_group.add_option('--cc-bin', dest='compiler_binary', + metavar='BINARY', + help='set the name of the compiler binary') + target_group.add_option('--with-endian', metavar='ORDER', default=None, help='override guess of CPU byte order') @@ -155,7 +185,7 @@ def process_command_line(args): target_group.add_option('--without-unaligned-mem', dest='unaligned_mem', action='store_false', - help=SUPPRESS_HELP) + help=optparse.SUPPRESS_HELP) for isa_extn_name in ['SSE2', 'SSSE3', 'AltiVec', 'AES-NI', 'movbe']: isa_extn = isa_extn_name.lower() @@ -167,23 +197,23 @@ def process_command_line(args): dest='enable_isa_extns') target_group.add_option('--disable-%s' % (isa_extn), - help=SUPPRESS_HELP, + help=optparse.SUPPRESS_HELP, action='append_const', const=isa_extn, dest='disable_isa_extns') - build_group = OptionGroup(parser, 'Build options') + build_group = optparse.OptionGroup(parser, 'Build options') build_group.add_option('--enable-shared', dest='build_shared_lib', action='store_true', default=True, - help=SUPPRESS_HELP) + help=optparse.SUPPRESS_HELP) build_group.add_option('--disable-shared', dest='build_shared_lib', action='store_false', help='disable building a shared library') build_group.add_option('--enable-asm', dest='asm_ok', action='store_true', default=True, - help=SUPPRESS_HELP) + help=optparse.SUPPRESS_HELP) build_group.add_option('--disable-asm', dest='asm_ok', action='store_false', help='disallow use of assembler') @@ -192,12 +222,20 @@ def process_command_line(args): action='store_true', default=False, help='enable debug build') build_group.add_option('--disable-debug', dest='debug_build', - action='store_false', help=SUPPRESS_HELP) + action='store_false', help=optparse.SUPPRESS_HELP) + + build_group.add_option('--no-optimizations', dest='no_optimizations', + action='store_true', default=False, + help=optparse.SUPPRESS_HELP) build_group.add_option('--gen-amalgamation', dest='gen_amalgamation', default=False, action='store_true', help='generate amalgamation files') + build_group.add_option('--via-amalgamation', dest='via_amalgamation', + default=False, action='store_true', + help='build via amalgamation') + build_group.add_option('--with-build-dir', metavar='DIR', default='', help='setup the build in DIR') @@ -209,27 +247,47 @@ def process_command_line(args): dest='local_config', metavar='FILE', help='include the contents of FILE into build.h') + build_group.add_option('--distribution-info', metavar='STRING', + help='set distribution specific versioning', + default='unspecified') + + build_group.add_option('--with-sphinx', action='store_true', + default=None, + help='Use Sphinx to generate HTML manual') + + build_group.add_option('--without-sphinx', action='store_false', + dest='with_sphinx', help=optparse.SUPPRESS_HELP) + + build_group.add_option('--with-visibility', action='store_true', + default=None, help=optparse.SUPPRESS_HELP) + + build_group.add_option('--without-visibility', action='store_false', + dest='with_visibility', help=optparse.SUPPRESS_HELP) + + build_group.add_option('--with-doxygen', action='store_true', + default=False, + help='Use Doxygen to generate HTML API docs') + + build_group.add_option('--without-doxygen', action='store_false', + dest='with_doxygen', help=optparse.SUPPRESS_HELP) + build_group.add_option('--dumb-gcc', dest='dumb_gcc', action='store_true', default=False, - help=SUPPRESS_HELP) + help=optparse.SUPPRESS_HELP) build_group.add_option('--maintainer-mode', dest='maintainer_mode', action='store_true', default=False, - help=SUPPRESS_HELP) + help=optparse.SUPPRESS_HELP) build_group.add_option('--dirty-tree', dest='clean_build_tree', action='store_false', default=True, - help=SUPPRESS_HELP) + help=optparse.SUPPRESS_HELP) build_group.add_option('--link-method', default=None, - help=SUPPRESS_HELP) - - build_group.add_option('--distribution-info', metavar='STRING', - help='set distribution specific versioning', - default='unspecified') + help=optparse.SUPPRESS_HELP) - wrapper_group = OptionGroup(parser, 'Wrapper options') + wrapper_group = optparse.OptionGroup(parser, 'Wrapper options') wrapper_group.add_option('--with-boost-python', dest='boost_python', default=False, action='store_true', @@ -238,14 +296,14 @@ def process_command_line(args): wrapper_group.add_option('--without-boost-python', dest='boost_python', action='store_false', - help=SUPPRESS_HELP) + help=optparse.SUPPRESS_HELP) - wrapper_group.add_option('--use-python-version', dest='python_version', + wrapper_group.add_option('--with-python-version', dest='python_version', metavar='N.M', default='.'.join(map(str, sys.version_info[0:2])), help='specify Python to build against (eg %default)') - mods_group = OptionGroup(parser, 'Module selection') + mods_group = optparse.OptionGroup(parser, 'Module selection') mods_group.add_option('--enable-modules', dest='enabled_modules', metavar='MODS', action='append', @@ -267,12 +325,12 @@ def process_command_line(args): dest='enabled_modules') mods_group.add_option('--without-%s' % (mod), - help=SUPPRESS_HELP, + help=optparse.SUPPRESS_HELP, action='append_const', const=mod, dest='disabled_modules') - install_group = OptionGroup(parser, 'Installation options') + install_group = optparse.OptionGroup(parser, 'Installation options') install_group.add_option('--prefix', metavar='DIR', help='set the base install directory') @@ -311,7 +369,7 @@ def process_command_line(args): ] for opt in compat_with_autoconf_options: - parser.add_option('--' + opt, help=SUPPRESS_HELP) + parser.add_option('--' + opt, help=optparse.SUPPRESS_HELP) (options, args) = parser.parse_args(args) @@ -443,8 +501,10 @@ class ModuleInfo(object): lex_me_harder(infofile, self, ['source', 'header:internal', 'header:public', - 'requires', 'os', 'arch', 'cc', 'libs'], - { 'load_on': 'auto', + 'requires', 'os', 'arch', 'cc', 'libs', + 'comment'], + { + 'load_on': 'auto', 'define': None, 'need_isa': None, 'mp_bits': 0 }) @@ -493,6 +553,11 @@ class ModuleInfo(object): self.mp_bits = int(self.mp_bits) + if self.comment != []: + self.comment = ' '.join(self.comment) + else: + self.comment = None + def sources(self): return self.source @@ -653,7 +718,8 @@ class CompilerInfo(object): 'lang_flags': '', 'warning_flags': '', 'maintainer_warning_flags': '', - 'dll_import_flags': '', + 'visibility_build_flags': '', + 'visibility_attribute': '', 'ar_command': None, 'makefile_style': '' }) @@ -680,6 +746,23 @@ class CompilerInfo(object): del self.mach_opt """ + Return the shared library build flags, if any + """ + def gen_shared_flags(self, options): + def flag_builder(): + if options.build_shared_lib: + yield self.shared_flags + if options.with_visibility: + yield self.visibility_build_flags + + return ' '.join(list(flag_builder())) + + def gen_visibility_attribute(self, options): + if options.build_shared_lib and options.with_visibility: + return self.visibility_attribute + return '' + + """ Return the machine specific ABI flags """ def mach_abi_link_flags(self, osname, arch, submodel, debug_p): @@ -719,13 +802,18 @@ class CompilerInfo(object): """ Return the flags for LIB_OPT """ - def library_opt_flags(self, debug_build): - flags = self.lib_opt_flags - if debug_build and self.debug_flags != '': - flags += ' ' + self.debug_flags - if not debug_build and self.no_debug_flags != '': - flags += ' ' + self.no_debug_flags - return flags + def library_opt_flags(self, options): + def gen_flags(): + if options.debug_build: + yield self.debug_flags + + if not options.no_optimizations: + yield self.lib_opt_flags + + if not options.debug_build: + yield self.no_debug_flags + + return (' '.join(gen_flags())).strip() """ Return the command needed to link a shared object @@ -791,6 +879,12 @@ def canon_processor(archinfo, proc): if re.search(match, proc) != None: return (ainfo.basename, submodel) + logging.debug('Known CPU names: ' + ' '.join( + sorted(sum([[ainfo.basename] + \ + ainfo.aliases + \ + [x for (x,_) in ainfo.all_submodels()] + for ainfo in archinfo.values()], [])))) + raise Exception('Unknown or unidentifiable processor "%s"' % (proc)) def guess_processor(archinfo): @@ -859,13 +953,21 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): def objectfile_list(sources, obj_dir): for src in sources: - basename = os.path.basename(src) + (dir,file) = os.path.split(os.path.normpath(src)) + + if dir.startswith('src'): + parts = dir.split(os.sep)[1:] + if file == parts[-1] + '.cpp': + name = '_'.join(dir.split(os.sep)[1:]) + '.cpp' + else: + name = '_'.join(dir.split(os.sep)[1:]) + '_' + file + else: + name = file for src_suffix in ['.cpp', '.S']: - basename = basename.replace(src_suffix, - '.' + osinfo.obj_suffix) + name = name.replace(src_suffix, '.' + osinfo.obj_suffix) - yield os.path.join(obj_dir, basename) + yield os.path.join(obj_dir, name) def choose_mp_bits(): @@ -904,11 +1006,6 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): return os.path.join(options.with_build_dir, path) return path - def only_if_shared(option): - if options.build_shared_lib: - return option - return '' - def warning_flags(normal_flags, maintainer_flags, maintainer_mode): @@ -920,14 +1017,13 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): 'version_major': build_config.version_major, 'version_minor': build_config.version_minor, 'version_patch': build_config.version_patch, + 'so_abi_rev': build_config.version_so_rev, 'version': build_config.version_string, 'distribution_info': options.distribution_info, 'version_datestamp': build_config.version_datestamp, - 'so_version': build_config.soversion_string, - 'timestamp': build_config.timestamp(), 'user': build_config.username(), 'hostname': build_config.hostname(), @@ -942,8 +1038,10 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): 'includedir': options.includedir or osinfo.header_dir, 'docdir': options.docdir or osinfo.doc_dir, - 'doc_src_dir': 'doc', 'build_dir': build_config.build_dir, + 'doc_output_dir': build_config.doc_output_dir, + + 'build_doc_commands': build_config.build_doc_commands, 'python_dir': build_config.python_dir, @@ -953,19 +1051,20 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): 'mp_bits': choose_mp_bits(), - 'cc': cc.binary_name + cc.mach_abi_link_flags( - options.os, options.arch, options.cpu, options.debug_build), + 'cc': (options.compiler_binary or cc.binary_name) + + cc.mach_abi_link_flags(options.os, options.arch, + options.cpu, options.debug_build), - 'lib_opt': cc.library_opt_flags(options.debug_build), + 'lib_opt': cc.library_opt_flags(options), 'mach_opt': cc.mach_opts(options.arch, options.cpu), - 'check_opt': cc.check_opt_flags, + 'check_opt': '' if options.no_optimizations else cc.check_opt_flags, 'lang_flags': cc.lang_flags + options.extra_flags, 'warn_flags': warning_flags(cc.warning_flags, cc.maintainer_warning_flags, options.maintainer_mode), - 'shared_flags': only_if_shared(cc.shared_flags), - 'dll_import_flags': only_if_shared(cc.dll_import_flags), + 'shared_flags': cc.gen_shared_flags(options), + 'visibility_attribute': cc.gen_visibility_attribute(options), 'so_link': cc.so_link_command_for(osinfo.basename), @@ -983,7 +1082,7 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): 'include_files': makefile_list(build_config.public_headers), 'lib_objs': makefile_list( - objectfile_list(build_config.sources, + objectfile_list(build_config.build_sources, build_config.libobj_dir)), 'check_objs': makefile_list( @@ -991,7 +1090,7 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): build_config.checkobj_dir)), 'lib_build_cmds': '\n'.join( - build_commands(build_config.sources, + build_commands(build_config.build_sources, build_config.libobj_dir, 'LIB')), 'check_build_cmds': '\n'.join( @@ -1020,13 +1119,13 @@ def create_template_vars(build_config, options, modules, cc, arch, osinfo): 'so_suffix': osinfo.so_suffix, 'botan_config': prefix_with_build_dir( - os.path.join(build_config.build_dir, 'botan-config')), + os.path.join(build_config.build_dir, + build_config.config_shell_script())), + 'botan_pkgconfig': prefix_with_build_dir( os.path.join(build_config.build_dir, build_config.pkg_config_file())), - 'doc_files': makefile_list(build_config.doc_files()), - 'mod_list': '\n'.join(sorted([m.basename for m in modules])), 'python_version': options.python_version @@ -1134,6 +1233,14 @@ def choose_modules_to_use(modules, archinfo, options): logging.info('Skipping, %s - %s' % ( reason, ' '.join(disabled_mods))) + for mod in sorted(to_load): + if mod.startswith('mp_'): + logging.info('Using MP module ' + mod) + if mod.startswith('simd_') and mod != 'simd_engine': + logging.info('Using SIMD module ' + mod) + if modules[mod].comment: + logging.info('%s: %s' % (mod, modules[mod].comment)) + logging.debug('Loading modules %s', ' '.join(sorted(to_load))) return [modules[mod] for mod in to_load] @@ -1258,7 +1365,7 @@ def setup_build(build_config, options, template_vars): if e.errno != errno.ENOENT: logging.error('Problem while removing build dir: %s' % (e)) - for dir in build_config.build_dirs(): + for dir in build_config.build_dirs: try: os.makedirs(dir) except OSError, e: @@ -1281,7 +1388,7 @@ def setup_build(build_config, options, template_vars): if options.os != 'windows': yield (options.build_data, 'botan.pc.in', build_config.pkg_config_file()) - yield (options.build_data, 'botan-config.in', 'botan-config') + yield (options.build_data, 'botan-config.in', build_config.config_shell_script()) if options.os == 'windows': yield (options.build_data, 'innosetup.in', 'botan.iss') @@ -1320,7 +1427,7 @@ def setup_build(build_config, options, template_vars): link_headers(build_config.public_headers, 'public', build_config.botan_include_dir) - link_headers(build_config.internal_headers, 'internal', + link_headers(build_config.build_internal_headers, 'internal', build_config.internal_include_dir) """ @@ -1397,12 +1504,16 @@ def generate_amalgamation(build_config): else: match = std_include.search(line) - if match: + if match and match.group(1) != 'functional': self.all_std_includes.add(match.group(1)) else: yield line - botan_all_h = open('botan_all.h', 'w') + amalg_basename = 'botan_all' + + header_name = '%s.h' % (amalg_basename) + + botan_h = open(header_name, 'w') pub_header_amalag = Amalgamation_Generator(build_config.public_headers) @@ -1414,31 +1525,30 @@ def generate_amalgamation(build_config): */ """ % (build_config.version_string) - botan_all_h.write(amalg_header) + botan_h.write(amalg_header) - botan_all_h.write(""" + botan_h.write(""" #ifndef BOTAN_AMALGAMATION_H__ #define BOTAN_AMALGAMATION_H__ """) - botan_all_h.write(pub_header_amalag.header_includes) - botan_all_h.write(pub_header_amalag.contents) - botan_all_h.write("\n#endif\n") + botan_h.write(pub_header_amalag.header_includes) + botan_h.write(pub_header_amalag.contents) + botan_h.write("\n#endif\n") internal_header_amalag = Amalgamation_Generator( [s for s in build_config.internal_headers if s.find('asm_macr_') == -1]) - botan_all_cpp = open('botan_all.cpp', 'w') - - botan_all_cpp.write(amalg_header) + botan_cpp = open('%s.cpp' % (amalg_basename), 'w') - botan_all_cpp.write('#include "botan_all.h"\n') + botan_cpp.write(amalg_header) - botan_all_cpp.write(internal_header_amalag.header_includes) - botan_all_cpp.write(internal_header_amalag.contents) + botan_cpp.write('\n#include "%s"\n' % (header_name)) + botan_cpp.write(internal_header_amalag.header_includes) + botan_cpp.write(internal_header_amalag.contents) for src in build_config.sources: if src.endswith('.S'): @@ -1449,27 +1559,30 @@ def generate_amalgamation(build_config): if botan_include.search(line): continue else: - botan_all_cpp.write(line) + botan_cpp.write(line) """ -Finding a program by name -code from http://stackoverflow.com/questions/377017/#377028 +Test for the existence of a program """ -def which(program): - def have_exe(fpath): - return os.path.exists(fpath) and os.access(fpath, os.X_OK) - - fpath, fname = os.path.split(program) - if fpath: - if have_exe(program): - return program - else: - for path in os.environ['PATH'].split(os.pathsep): - exe_file = os.path.join(path, program) - if have_exe(exe_file): - return exe_file +def have_program(program): + + def exe_test(path, program): + exe_file = os.path.join(path, program) + + if os.path.exists(exe_file) and os.access(exe_file, os.X_OK): + logging.debug('Found program %s in %s' % (program, path)) + return True + else: + return False - return None + exe_suffixes = ['', '.exe'] + + for path in os.environ['PATH'].split(os.pathsep): + for suffix in exe_suffixes: + if exe_test(path, program + suffix): + return True + + return False """ Main driver @@ -1515,19 +1628,17 @@ def main(argv = None): logging.debug("Converting '%s' to 'cygwin'", options.os) options.os = 'cygwin' - logging.info('Guessing target OS is %s (--os to set)' % (options.os)) + logging.info('Guessing target OS is %s (use --os to set)' % (options.os)) if options.compiler is None: if options.os == 'windows': - if which('cl.exe') is not None: - options.compiler = 'msvc' - elif which('g++.exe') is not None: + if have_program('g++') and not have_program('cl'): options.compiler = 'gcc' else: options.compiler = 'msvc' else: options.compiler = 'gcc' - logging.info('Guessing to use compiler %s (--cc to set)' % ( + logging.info('Guessing to use compiler %s (use --cc to set)' % ( options.compiler)) if options.compiler not in ccinfo: @@ -1550,7 +1661,7 @@ def main(argv = None): if options.cpu is None: (options.arch, options.cpu) = guess_processor(archinfo) - logging.info('Guessing target processor is a %s/%s (--cpu to set)' % ( + logging.info('Guessing target processor is a %s/%s (use --cpu to set)' % ( options.arch, options.cpu)) else: cpu_from_user = options.cpu @@ -1561,45 +1672,73 @@ def main(argv = None): logging.info('Target is %s-%s-%s-%s' % ( options.compiler, options.os, options.arch, options.cpu)) + cc = ccinfo[options.compiler] + # Kind of a hack... options.extra_flags = '' if options.compiler == 'gcc': + def get_gcc_version(gcc_bin): + try: + gcc_version = ''.join(subprocess.Popen( + gcc_bin.split(' ') + ['-dumpversion'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate()).strip() + logging.info('Detected gcc version %s' % (gcc_version)) + return gcc_version + except OSError: + logging.warning('Could not execute %s for version check' % (gcc_bin)) + return None + def is_64bit_arch(arch): if arch.endswith('64') or arch in ['alpha', 's390x']: return True return False - if not is_64bit_arch(options.arch) and not options.dumb_gcc: - try: - matching_version = '(4\.[01234]\.)|(3\.[34]\.)|(2\.95\.[0-4])' + gcc_version = get_gcc_version(options.compiler_binary or cc.binary_name) - gcc_version = ''.join(subprocess.Popen( - ['g++', '-dumpversion'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE).communicate()).strip() + if gcc_version: - logging.info('Detected GCC version %s' % (gcc_version)) + if not is_64bit_arch(options.arch) and not options.dumb_gcc: + matching_version = '(4\.[01234]\.)|(3\.[34]\.)|(2\.95\.[0-4])' if re.search(matching_version, gcc_version): options.dumb_gcc = True - except OSError: - logging.warning('Could not execute GCC for version check') + + versions_without_tr1 = '(4\.0\.)|(3\.[0-4]\.)|(2\.95\.[0-4])' + + if options.with_tr1 == None and \ + re.search(versions_without_tr1, gcc_version): + logging.info('Disabling TR1 support for this gcc, too old') + options.with_tr1 = 'none' + + versions_without_visibility = '(3\.[0-4]\.)|(2\.95\.[0-4])' + if options.with_visibility == None and \ + re.search(versions_without_visibility, gcc_version): + logging.info('Disabling DSO visibility support for this gcc, too old') + options.with_visibility = False if options.dumb_gcc is True: logging.info('Setting -fpermissive to work around gcc bug') options.extra_flags = ' -fpermissive' + if options.with_visibility is None: + options.with_visibility = True + + if options.with_sphinx is None: + if have_program('sphinx-build'): + logging.info('Found sphinx-build, will use it ' + + '(use --without-sphinx to disable)') + options.with_sphinx = True + + if options.via_amalgamation: + options.gen_amalgamation = True + if options.gen_amalgamation: if options.asm_ok: logging.info('Disabling assembly code, cannot use in amalgamation') options.asm_ok = False - for mod in ['sha1_sse2', 'serpent_simd']: - if mod not in options.disabled_modules: - logging.info('Disabling %s, cannot use in amalgamation' % (mod)) - options.disabled_modules.append(mod) - modules_to_use = choose_modules_to_use(modules, archinfo[options.arch], options) @@ -1615,7 +1754,7 @@ def main(argv = None): template_vars = create_template_vars(build_config, options, modules_to_use, - ccinfo[options.compiler], + cc, archinfo[options.arch], osinfo[options.os]) diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html new file mode 100644 index 000000000..c907c7597 --- /dev/null +++ b/doc/_templates/layout.html @@ -0,0 +1,9 @@ +{% extends "!layout.html" %} + +{% block header %} + <div class="header-wrapper"> + <div class="header"> + <h1>{{ shorttitle|e }}</h1> + </div> + </div> +{% endblock %} diff --git a/doc/algos.txt b/doc/algos.txt new file mode 100644 index 000000000..119b81a7f --- /dev/null +++ b/doc/algos.txt @@ -0,0 +1,90 @@ + +.. _algo_list: + +Algorithms +======================================== + +Supported Algorithms +---------------------------------------- + +Botan provides a number of different cryptographic algorithms and +primitives, including: + +* Public key cryptography + + * Encryption algorithms RSA, ElGamal, DLIES (padding schemes OAEP, + PKCS #1 v1.5) + * Signature algorithms RSA, DSA, ECDSA, GOST 34.10-2001, + Nyberg-Rueppel, Rabin-Williams (padding schemes PSS, PKCS #1 v1.5, + X9.31) + * Key agreement techniques Diffie-Hellman and ECDH + +* Hash functions + + * NIST hashes: SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 + * RIPE hashes: RIPEMD-160 and RIPEMD-128 + * SHA-3 candidates Skein-512, Keccak, and Blue Midnight Wish-512 + * Other common hash functions Whirlpool and Tiger + * National standard hashes HAS-160 and GOST 34.11 + * Obsolete or insecure hashes MD5, MD4, MD2 + * Non-cryptographic checksums Adler32, CRC24, CRC32 + +* Block ciphers + + * AES (Rijndael) and AES candidates Serpent, Twofish, MARS, CAST-256, RC6 + * DES, and variants 3DES and DESX + * National/telecom block ciphers SEED, KASUMI, MISTY1, GOST 28147, Skipjack + * Other block ciphers including Blowfish, CAST-128, IDEA, Noekeon, + TEA, XTEA, RC2, RC5, SAFER-SK, and Square + * Block cipher constructions Luby-Rackoff and Lion + * Block cipher modes ECB, CBC, CBC/CTS, CFB, OFB, CTR, XTS and + authenticated cipher mode EAX + +* Stream ciphers ARC4, Salsa20/XSalsa20, Turing, and WiderWake4+1 + +* Authentication codes HMAC, CMAC (aka OMAC1), CBC-MAC, ANSI X9.19 + DES-MAC, and the protocol-specific SSLv3 authentication code + +* Public Key Infrastructure + + * X.509 certificates (including generating new self-signed and CA + certs) and CRLs + * Certificate path validation + * PKCS #10 certificate requests (creation and certificate issue) + +* Other cryptographic utility functions including + + * Key derivation functions for passwords: PBKDF1 (PKCS #5 v1.5), + PBKDF2 (PKCS #5 v2.0), OpenPGP S2K (RFC 2440) + * General key derivation functions KDF1 and KDF2 from IEEE 1363 + * PRFs from ANSI X9.42, SSL v3.0, TLS v1.0 + +Recommended Algorithms +--------------------------------- + +This section is by no means the last word on selecting which +algorithms to use. However, botan includes a sometimes bewildering +array of possible algorithms, and unless you're familiar with the +latest developments in the field, it can be hard to know what is +secure and what is not. The following attributes of the algorithms +were evaluated when making this list: security, standardization, +patent status, support by other implementations, and efficiency (in +roughly that order). + +It is intended as a set of simple guidelines for developers, and +nothing more. It's entirely possible that there are algorithms that +will turn out to be more secure than the ones listed, but the +algorithms listed here are (currently) thought to be safe. + +* Block ciphers: AES or Serpent in CBC, CTR, or XTS mode + +* Hash functions: SHA-256, SHA-512 + +* MACs: HMAC with any recommended hash function + +* Public Key Encryption: RSA with "EME1(SHA-256)" + +* Public Key Signatures: RSA with EMSA4 and any recommended hash, or + DSA or ECDSA with "EMSA1(SHA-256)" + +* Key Agreement: Diffie-Hellman or ECDH, with "KDF2(SHA-256)" diff --git a/doc/api.tex b/doc/api.tex deleted file mode 100644 index 79c090c2a..000000000 --- a/doc/api.tex +++ /dev/null @@ -1,2964 +0,0 @@ -\documentclass{article} - -\setlength{\textwidth}{6.5in} -\setlength{\textheight}{9in} - -\setlength{\headheight}{0in} -\setlength{\topmargin}{0in} -\setlength{\headsep}{0in} - -\setlength{\oddsidemargin}{0in} -\setlength{\evensidemargin}{0in} - -\title{\textbf{Botan Reference Manual}} -\author{} -\date{2010/06/14} - -\newcommand{\filename}[1]{\texttt{#1}} -\newcommand{\manpage}[2]{\texttt{#1}(#2)} - -\newcommand{\macro}[1]{\texttt{#1}} - -\newcommand{\function}[1]{\textbf{#1}} -\newcommand{\keyword}[1]{\texttt{#1}} -\newcommand{\type}[1]{\texttt{#1}} -\renewcommand{\arg}[1]{\textsl{#1}} -\newcommand{\namespace}[1]{\texttt{#1}} - -\newcommand{\url}[1]{\texttt{#1}} - -\newcommand{\ie}[0]{\emph{i.e.}} -\newcommand{\eg}[0]{\emph{e.g.}} - -\begin{document} - -\maketitle - -\tableofcontents - -\parskip=5pt - -\pagebreak - -\section{Introduction} - -Botan is a C++ library that attempts to provide the most common -cryptographic algorithms and operations in an easy to use, efficient, -and portable way. It runs on a wide variety of systems, and can be -used with a number of different compilers. - -The base library is written in ISO C++, so it can be ported with -minimal fuss, but Botan also supports a modules system. This system -exposes system dependent code to the library through portable -interfaces, extending the set of services available to users. - -\subsection{Recommended Reading} - -It's a very good idea if you have some knowledge of cryptography prior -to trying to use this stuff. You really should read at least one and -ideally all of these books before seriously using the library. - -\setlength{\parskip}{5pt} - -\noindent -\textit{Cryptography Engineering}, Niels Ferguson, Bruce Schneier, and -Tadayoshi Kohno; Wiley - -\noindent -\textit{Security Engineering -- A Guide to Building Dependable - Distributed Systems}, Ross Anderson; Wiley - -\noindent -\textit{Handbook of Applied Cryptography}, Alfred J. Menezes, -Paul C. Van Oorschot, and Scott A. Vanstone; CRC Press (available -online at \url{http://www.cacr.math.uwaterloo.ca/hac/}) - -\subsection{Targets} - -Botan's primary targets (system-wise) are 32 and 64-bit CPUs, with a -flat memory address space of at least 32 bits. Given the choice -between optimizing for 32-bit systems and 64-bit systems, Botan is -written to prefer 64-bit, on the theory that where performance is a -real concern, modern 64-bit processors are the obvious choice. - -Smaller handhelds, set-top boxes, and the bigger smart phones and smart -cards, are also capable of using Botan. However, Botan uses a -large amount of code space (up to several megabytes, depending upon -the compiler and options used), which could be prohibitive in some -systems. Usage of RAM is modest, usually under 64K. - -Botan's design makes it quite easy to remove unused algorithms in such -a way that applications do not need to be recompiled to work, even -applications that use the algorithms in question. They can ask Botan -if the algorithm exists, and if Botan says yes, ask the library to -give them such an object for that algorithm. - -\section{Getting Started} - -\subsection{Basic Conventions} - -With a very small number of exceptions, declarations in the library -are contained within the namespace \namespace{Botan}. Botan declares -several \keyword{typedef}'ed types to help buffer it against changes -in machine architecture. These types are used extensively in the -interface, thus it would be often be convenient to use them without -the \namespace{Botan} prefix. You can do so by \keyword{using} the -namespace \namespace{Botan\_types} (this way you can use the type -names without the namespace prefix, but the remainder of the library -stays out of the global namespace). The included types are \type{byte} -and \type{u32bit}, which are unsigned integer types. - -The headers for Botan are usually available in the form -\filename{botan/headername.h}. For brevity in this documentation, -headers are always just called \filename{headername.h}, but they -should be used with the \filename{botan/} prefix in your actual code. - -\subsection{Initializing the Library} - -There is a set of core services that the library needs access to while -it is performing requests. To ensure these are set up, you must create -a \type{LibraryInitializer} object (usually called 'init' in Botan -example code; 'botan\_library' or 'botan\_init' may make more sense in -real applications) prior to making any calls to Botan. This object's -lifetime must exceed that of all other Botan objects your application -creates; for this reason the best place to create the -\type{LibraryInitializer} is at the start of your \function{main} -function, since this guarantees that it will be created first and -destroyed last (via standard C++ RAII rules). The initializer does -things like setting up the memory allocation system and algorithm -lookup tables, finding out if there is a high resolution timer -available to use, and similar such matters. With no arguments, the -library is initialized with various default settings. So (unless you -are writing threaded code; see below), all you need is: - -\texttt{Botan::LibraryInitializer init;} - -at the start of your \texttt{main}. - -The constructor takes an optional string that specifies arguments. -Currently the only possible argument is ``thread\_safe'', which must -have an boolean argument (for instance ``thread\_safe=false'' or -``thread\_safe=true''). If ``thread\_safe'' is specified as true the -library will attempt to register a mutex type to properly guard access -to shared resources. However these locks do not protect individual -Botan objects: explicit locking must be used if you wish to share a -single object between threads. - -If you do not create a \type{LibraryInitializer} object, all library -operations will fail, because it will be unable to do basic things -like allocate memory or get random bits. You should never create more -than one \type{LibraryInitializer}. - -It is not strictly necessary to create a \type{LibraryInitializer}; -the actual code performing the initialization and shutdown are in -static member functions of \type{LibraryInitializer}, called -\function{initialize} and \function{deinitialize}. A -\type{LibraryInitializer} merely provides a convenient RAII wrapper -for the operations (thus for the internal library state as well). - -\subsection{Pitfalls} - -There are a few things to watch out for to prevent problems when using Botan. - -Never allocate any kind of Botan object globally. The problem with -doing this is that the constructor for such an object will be called -before the library is initialized. Many Botan objects will, in their -constructor, make one or more calls into the library global state -object. Access to this object is checked, so an exception should be -thrown (rather than a memory access violation or undetected -uninitialized object access). A rough equivalent that will work is to -keep a global pointer to the object, initializing it after creating -your \type{LibraryInitializer}. Merely making the -\type{LibraryInitializer} also global will probably not help, because -C++ does not make very strong guarantees about the order that such -objects will be created. - -The same rule applies for making sure the destructors of all your -Botan objects are called before the \type{LibraryInitializer} is -destroyed. This implies you can't have static variables that are Botan -objects inside functions or classes; in many C++ runtimes, these -objects will be destroyed after main has returned. - -Botan's memory object classes (\type{MemoryRegion}, -\type{MemoryVector}, \type{SecureVector}) are extremely primitive, and -meant only for secure storage of potentially sensitive data like -keys. They do not meet the requirements for an STL container object -and you should not try to use them with STL algorithms. For a -general-purpose container, use \type{std::vector}. - -Use a \function{try}/\function{catch} block inside your -\function{main} function, and catch any \type{std::exception} throws -(remember to catch by reference, as \type{std::exception}'s -\function{what} method is polymorphic). This is not strictly required, -but if you don't, and Botan throws an exception, the runtime will call -\function{std::terminate}, which usually calls \function{abort} or -something like it, leaving you (or worse, a user of your application) -wondering what went wrong. - -\subsection{Information Flow: Pipes and Filters} - -Many common uses of cryptography involve processing one or more -streams of data. Botan provides services that make setting up data -flows through various operations, such as compression, encryption, and -base64 encoding. Each of these operations is implemented in what are -called \emph{filters} in Botan. A set of filters are created and -placed into a \emph{pipe}, and information ``flows'' through the pipe -until it reaches the end, where the output is collected for -retrieval. If you're familiar with the Unix shell environment, this -design will sound quite familiar. - -Here is an example that uses a pipe to base64 encode some strings: - -\begin{verbatim} - Pipe pipe(new Base64_Encoder); // pipe owns the pointer - pipe.start_msg(); - pipe.write(``message 1''); - pipe.end_msg(); // flushes buffers, increments message number - - // process_msg(x) is start_msg() && write(x) && end_msg() - pipe.process_msg(``message2''); - - std::string m1 = pipe.read_all_as_string(0); // ``message1'' - std::string m2 = pipe.read_all_as_string(1); // ``message2'' -\end{verbatim} - -Bytestreams in the pipe are grouped into messages; blocks of data that -are processed in an identical fashion (\ie, with the same sequence of -\type{Filter}s). Messages are delimited by calls to -\function{start\_msg} and \function{end\_msg}. Each message in a pipe -has its own identifier, which currently is an integer that increments -up from zero. - -As you can see, the \type{Base64\_Encoder} was allocated using -\keyword{new}; but where was it deallocated? When a filter object is -passed to a \type{Pipe}, the pipe takes ownership of the object, and -will deallocate it when it is no longer needed. - -There are two different ways to make use of messages. One is to send -several messages through a \type{Pipe} without changing the -\type{Pipe}'s configuration, so you end up with a sequence of -messages; one use of this would be to send a sequence of identically -encrypted UDP packets, for example (note that the \emph{data} need not -be identical; it is just that each is encrypted, encoded, signed, etc -in an identical fashion). Another is to change the filters that are -used in the \type{Pipe} between each message, by adding or removing -\type{Filter}s; functions that let you do this are documented in the -Pipe API section. - -Botan has about 40 filters that perform different operations on data. -Here's code that uses one of them to encrypt a string with AES: - -\begin{verbatim} - AutoSeeded_RNG rng, - SymmetricKey key(rng, 16); // a random 128-bit key - InitializationVector iv(rng, 16); // a random 128-bit IV - - // The algorithm we want is specified by a string - Pipe pipe(get_cipher(``AES-128/CBC'', key, iv, ENCRYPTION)); - - pipe.process_msg(``secrets''); - pipe.process_msg(``more secrets''); - - MemoryVector<byte> c1 = pipe.read_all(0); - - byte c2[4096] = { 0 }; - u32bit got_out = pipe.read(c2, sizeof(c2), 1); - // use c2[0...got_out] -\end{verbatim} - -Note the use of \type{AutoSeeded\_RNG}, which is a random number -generator. If you want to, you can explicitly set up the random number -generators and entropy sources you want to, however for 99\% of cases -\type{AutoSeeded\_RNG} is preferable. - -\type{Pipe} also has convenience methods for dealing with -\type{std::iostream}s. Here is an example of those, using the -\type{Bzip\_Compression} filter (included as a module; if you have -bzlib available, check \filename{building.pdf} for how to enable it) -to compress a file: - -\begin{verbatim} - std::ifstream in(``data.bin'', std::ios::binary) - std::ofstream out(``data.bin.bz2'', std::ios::binary) - - Pipe pipe(new Bzip_Compression); - - pipe.start_msg(); - in >> pipe; - pipe.end_msg(); - out << pipe; -\end{verbatim} - -However there is a hitch to the code above; the complete contents of -the compressed data will be held in memory until the entire message -has been compressed, at which time the statement \verb|out << pipe| is -executed, and the data is freed as it is read from the pipe and -written to the file. But if the file is very large, we might not have -enough physical memory (or even enough virtual memory!) for that to be -practical. So instead of storing the compressed data in the pipe for -reading it out later, we divert it directly to the file: - -\begin{verbatim} - std::ifstream in(``data.bin'', std::ios::binary) - std::ofstream out(``data.bin.bz2'', std::ios::binary) - - Pipe pipe(new Bzip_Compression, new DataSink_Stream(out)); - - pipe.start_msg(); - in >> pipe; - pipe.end_msg(); -\end{verbatim} - -This is the first code we've seen so far that uses more than one -filter in a pipe. The output of the compressor is sent to the -\type{DataSink\_Stream}. Anything written to a \type{DataSink\_Stream} -is written to a file; the filter produces no output. As soon as the -compression algorithm finishes up a block of data, it will send it along, -at which point it will immediately be written to disk; if you were to -call \verb|pipe.read_all()| after \verb|pipe.end_msg()|, you'd get an -empty vector out. - -Here's an example using two computational filters: - -\begin{verbatim} - AutoSeeded_RNG rng, - SymmetricKey key(rng, 32); - InitializationVector iv(rng, 16); - - Pipe encryptor(get_cipher("AES/CBC/PKCS7", key, iv, ENCRYPTION), - new Base64_Encoder); - - encryptor.start_msg(); - file >> encryptor; - encryptor.end_msg(); // flush buffers, complete computations - std::cout << encryptor; -\end{verbatim} - -\subsection{Fork} - -It is common that you might receive some data and want to -perform more than one operation on it (\ie, encrypt it with Serpent -and calculate the SHA-256 hash of the plaintext at the same -time). That's where \type{Fork} comes in. \type{Fork} is a filter that -takes input and passes it on to \emph{one or more} \type{Filter}s -that are attached to it. \type{Fork} changes the nature of the pipe -system completely. Instead of being a linked list, it becomes a tree. - -Each \type{Filter} in the fork is given its own output buffer, and -thus its own message. For example, if you had previously written two -messages into a \type{Pipe}, then you start a new one with a -\type{Fork} that has three paths of \type{Filter}'s inside it, you -add three new messages to the \type{Pipe}. The data you put into the -\type{Pipe} is duplicated and sent into each set of \type{Filter}s, -and the eventual output is placed into a dedicated message slot in the -\type{Pipe}. - -Messages in the \type{Pipe} are allocated in a depth-first manner. This is only -interesting if you are using more than one \type{Fork} in a single \type{Pipe}. -As an example, consider the following: - -\begin{verbatim} - Pipe pipe(new Fork( - new Fork( - new Base64_Encoder, - new Fork( - NULL, - new Base64_Encoder - ) - ), - new Hex_Encoder - ) - ); -\end{verbatim} - -In this case, message 0 will be the output of the first \type{Base64\_Encoder}, -message 1 will be a copy of the input (see below for how \type{Fork} interprets -NULL pointers), message 2 will be the output of the second -\type{Base64\_Encoder}, and message 3 will be the output of the -\type{Hex\_Encoder}. As you can see, this results in message numbers being -allocated in a top to bottom fashion, when looked at on the screen. However, -note that there could be potential for bugs if this is not anticipated. For -example, if your code is passed a \type{Filter}, and you assume it is a -``normal'' one that only uses one message, your message offsets would be -wrong, leading to some confusion during output. - -If Fork's first argument is a null pointer, but a later argument is -not, then Fork will feed a copy of its input directly through. Here's -a case where that is useful: - -\begin{verbatim} - // have std::string ciphertext, auth_code, key, iv, mac_key; - - Pipe pipe(new Base64_Decoder, - get_cipher(``AES-128'', key, iv, DECRYPTION), - new Fork( - 0 - new MAC_Filter(``HMAC(SHA-1)'', mac_key) - ) - ); - - pipe.process_msg(ciphertext); - std::string plaintext = pipe.read_all_as_string(0); - SecureVector<byte> mac = pipe.read_all(1); - - if(mac != auth_code) - error(); -\end{verbatim} - -Here we wanted to not only decrypt the message, but send the decrypted -text through an additional computation, in order to compute the -authentication code. - -Any \type{Filter}s that are attached to the \type{Pipe} after the -\type{Fork} are implicitly attached onto the first branch created by -the fork. For example, let's say you created this \type{Pipe}: - -\begin{verbatim} -Pipe pipe(new Fork(new Hash_Filter("MD5"), new Hash_Filter("SHA-1")), - new Hex_Encoder); -\end{verbatim} - -And then called \function{start\_msg}, inserted some data, then -\function{end\_msg}. Then \arg{pipe} would contain two messages. The -first one (message number 0) would contain the MD5 sum of the input in -hex encoded form, and the other would contain the SHA-1 sum of the -input in raw binary. However, it's much better to use a \type{Chain} -instead. - -\subsubsection{Chain} - -A \type{Chain} filter creates a chain of \type{Filter}s and -encapsulates them inside a single filter (itself). This allows a -sequence of filters to become a single filter, to be passed into or -out of a function, or to a \type{Fork} constructor. - -You can call \type{Chain}'s constructor with up to 4 \type{Filter*}s -(they will be added in order), or with an array of \type{Filter*}s and -a \type{u32bit} that tells \type{Chain} how many \type{Filter*}s are -in the array (again, they will be attached in order). Here's the -example from the last section, using chain instead of relying on the -obscure rule that version used. - -\begin{verbatim} - Pipe pipe(new Fork( - new Chain(new Hash_Filter("MD5"), new Hex_Encoder), - new Hash_Filter("SHA-1") - ) - ); -\end{verbatim} - -\subsection{The Pipe API} - -\subsubsection{Initializing Pipe} - -By default, \type{Pipe} will do nothing at all; any input placed into -the \type{Pipe} will be read back unchanged. Obviously, this has -limited utility, and presumably you want to use one or more -\type{Filter}s to somehow process the data. First, you can choose a -set of \type{Filter}s to initialize the \type{Pipe} via the -constructor. You can pass it either a set of up to 4 \type{Filter*}s, -or a pre-defined array and a length: - -\begin{verbatim} - Pipe pipe1(new Filter1(/*args*/), new Filter2(/*args*/), - new Filter3(/*args*/), new Filter4(/*args*/)); - Pipe pipe2(new Filter1(/*args*/), new Filter2(/*args*/)); - - Filter* filters[5] = { - new Filter1(/*args*/), new Filter2(/*args*/), new Filter3(/*args*/), - new Filter4(/*args*/), new Filter5(/*args*/) /* more if desired... */ - }; - Pipe pipe3(filters, 5); -\end{verbatim} - -This is by far the most common way to initialize a \type{Pipe}. However, -occasionally a more flexible initialization strategy is necessary; this is -supported by 4 member functions: \function{prepend}(\type{Filter*}), -\function{append}(\type{Filter*}), \function{pop}(), and \function{reset}(). -These functions may only be used while the \type{Pipe} in question is not in -use; that is, either before calling \function{start\_msg}, or after -\function{end\_msg} has been called (and no new calls to \function{start\_msg} -have been made yet). - -The function \function{reset}() removes all the \type{Filter}s that -the \type{Pipe} is currently using~--~it is reset to an initialize, -``empty'' state. Any data that is being retained by the \type{Pipe} -is retained after a \function{reset}(), and \function{reset}() does -not affect the message numbers (discussed later). - -Calling \function{prepend} and \function{append} will either prepend -or append the passed \type{Filter} object to the list of -transformations. For example, if you \function{prepend} a -\type{Filter} implementing encryption, and the \type{Pipe} already had -a \type{Filter} that hex encoded the input, then the next set of -input would be first encrypted, then hex encoded. Alternately, if you -called \function{append}, then the input would be first be hex -encoded, and then encrypted (which is not terribly useful in this -particular example). - -Finally, calling \function{pop}() will remove the first transformation -of the \type{Pipe}. Say we had called \function{prepend} to put an -encryption \type{Filter} into a \type{Pipe}; calling \function{pop}() -would remove this \type{Filter} and return the \type{Pipe} to its -state before we called \function{prepend}. - -\subsubsection{Giving Data to a Pipe} - -Input to a \type{Pipe} is delimited into messages, which can be read from -independently (\ie, you can read 5 bytes from one message, and then all of -another message, without either read affecting any other messages). The -messages are delimited by calls to \function{start\_msg} and -\function{end\_msg}. In between these two calls, you can write data into a -\type{Pipe}, and it will be processed by the \type{Filter}(s) that it -contains. Writes at any other time are invalid, and will result in an -exception. - -As to writing, you can call any of the functions called \function{write}(), -that can take any of: a \type{byte[]}/\type{u32bit} pair, a -\type{SecureVector<byte>}, a \type{std::string}, a \type{DataSource\&}, or a -single \type{byte}. - -Sometimes, you may want to do only a single write per message. In this case, -you can use the \function{process\_msg} series of functions, which start a -message, write their argument into the \type{Pipe}, and then end the -message. In this case you would not make any explicit calls to -\function{start\_msg}/\function{end\_msg}. The version of \function{write} -that takes a single \type{byte} is not supported by \function{process\_msg}, -but all the other variants are. - -\type{Pipe} can also be used with the \verb|>>| operator, and will accept a -\type{std::istream}, (or on Unix systems with the \verb|fd_unix| module), a -Unix file descriptor. In either case, the entire contents of the file will be -read into the \type{Pipe}. - -\subsubsection{Getting Output from a Pipe} - -Retrieving the processed data from a \type{Pipe} is a bit more complicated, for -various reasons. In particular, because \type{Pipe} will separate each message -into a separate buffer, you have to be able to retrieve data from each message -independently. Each of \type{Pipe}'s read functions has a final parameter that -specifies what message to read from (as a 32-bit integer). If this parameter is -set to \type{Pipe::DEFAULT\_MESSAGE}, it will read the current default message -(\type{DEFAULT\_MESSAGE} is also the default value of this parameter). The -parameter will not be mentioned in further discussion of the reading API, but -it is always there (unless otherwise noted). - -Reading is done with a variety of functions. The most basic are \type{u32bit} -\function{read}(\type{byte} \arg{out}[], \type{u32bit} \arg{len}) and -\type{u32bit} \function{read}(\type{byte\&} \arg{out}). Each reads into -\arg{out} (either up to \arg{len} bytes, or a single byte for the one taking a -\type{byte\&}), and returns the total number of bytes read. There is a variant -of these functions, all named \function{peek}, which performs the same -operations, but does not remove the bytes from the message (reading is a -destructive operation with a \type{Pipe}). - -There are also the functions \type{SecureVector<byte>} \function{read\_all}(), -and \type{std::string} \function{read\_all\_as\_string}(), which return the -entire contents of the message, either as a memory buffer, or a -\type{std::string} (which is generally only useful if the \type{Pipe} has -encoded the message into a text string, such as when a \type{Base64\_Encoder} -is used). - -To determine how many bytes are left in a message, call \type{u32bit} -\function{remaining}() (which can also take an optional message -number). Finally, there are some functions for managing the default message -number: \type{u32bit} \function{default\_msg}() will return the current default -message, \type{u32bit} \function{message\_count}() will return the total number -of messages (0...\function{message\_count}()-1), and -\function{set\_default\_msg}(\type{u32bit} \arg{msgno}) will set a new default -message number (which must be a valid message number for that \type{Pipe}). The -ability to set the default message number is particularly important in the case -of using the file output operations (\verb|<<| with a \type{std::ostream} or -Unix file descriptor), because there is no way to specify it explicitly when -using the output operator. - -\subsection{A Filter Example} - -Here is some code that takes one or more filenames in \arg{argv} and -calculates the result of several hash functions for each file. The complete -program can be found as \filename{hasher.cpp} in the Botan distribution. For -brevity, error checking has been removed. - -\begin{verbatim} - string name[3] = { "MD5", "SHA-1", "RIPEMD-160" }; - Botan::Filter* hash[3] = { - 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)); - - for(u32bit j = 1; argv[j] != 0; j++) - { - ifstream file(argv[j]); - pipe.start_msg(); - file >> pipe; - pipe.end_msg(); - file.close(); - for(u32bit k = 0; k != 3; k++) - { - pipe.set_default_msg(3*(j-1)+k); - cout << name[k] << "(" << argv[j] << ") = " << pipe << endl; - } - } -\end{verbatim} - - -\subsection{Filter Catalog} - -This section contains descriptions of every \type{Filter} included in -the portable sections of Botan. \type{Filter}s provided by modules -are documented elsewhere. - -\subsubsection{Keyed Filters} - -A few sections ago, it was mentioned that \type{Pipe} can process multiple -messages, treating each of them the same. Well, that was a bit of a -lie. There are some algorithms (in particular, block ciphers not in ECB mode, -and all stream ciphers) that change their state as data is put through them. - -Naturally, you might well want to reset the keys or (in the case of block -cipher modes) IVs used by such filters, so multiple messages can be processed -using completely different keys, or new IVs, or new keys and IVs, or whatever. -And in fact, even for a MAC or an ECB block cipher, you might well want to -change the key used from message to message. - -Enter \type{Keyed\_Filter}, which acts as an abstract interface for -any filter that is uses keys: block cipher modes, stream ciphers, -MACs, and so on. It has two functions, \function{set\_key} and -\function{set\_iv}. Calling \function{set\_key} will, naturally, set -(or reset) the key used by the algorithm. Setting the IV only makes -sense in certain algorithms -- a call to \function{set\_iv} on an -object that doesn't support IVs will be ignored. You \emph{must} call -\function{set\_key} before calling \function{set\_iv}: while not all -\type{Keyed\_Filter} objects require this, you should assume it is -required anytime you are using a \type{Keyed\_Filter}. - -Here's a example: - -\begin{verbatim} - Keyed_Filter *cast, *hmac; - Pipe pipe(new Base64_Decoder, - // Note the assignments to the cast and hmac variables - cast = new CBC_Decryption("CAST-128", "PKCS7", cast_key, iv), - new Fork( - 0, // Read the section 'Fork' to understand this - new Chain( - hmac = new MAC_Filter("HMAC(SHA-1)", mac_key, 12), - new Base64_Encoder - ) - ) - ); - pipe.start_msg(); - [use pipe for a while, decrypt some stuff, derive new keys and IVs] - pipe.end_msg(); - - cast->set_key(cast_key2); - cast->set_iv(iv2); - hmac->set_key(mac_key2); - - pipe.start_msg(); - [use pipe for some other things] - pipe.end_msg(); -\end{verbatim} - -There are some requirements to using \type{Keyed\_Filter} that you must -follow. If you call \function{set\_key} or \function{set\_iv} on a filter that -is owned by a \type{Pipe}, you must do so while the \type{Pipe} is -``unlocked''. This refers to the times when no messages are being processed by -\type{Pipe} -- either before \type{Pipe}'s \function{start\_msg} is called, or -after \function{end\_msg} is called (and no new call to \function{start\_msg} -has happened yet). Doing otherwise will result in undefined behavior, probably -silently getting invalid output. - -And remember: if you're resetting both values, reset the key \emph{first}. - -\subsubsection{Cipher Filters} - -Getting a hold of a \type{Filter} implementing a cipher is very -easy. Make sure you're including the header \filename{lookup.h}, and -then call \function{get\_cipher}. You will pass the return value -directly into a \type{Pipe}. There are a couple different functions -which do varying levels of initialization: - -\function{get\_cipher}(\type{std::string} \arg{cipher\_spec}, - \type{SymmetricKey} \arg{key}, - \type{InitializationVector} \arg{iv}, - \type{Cipher\_Dir} \arg{dir}); - -\function{get\_cipher}(\type{std::string} \arg{cipher\_spec}, - \type{SymmetricKey} \arg{key}, - \type{Cipher\_Dir} \arg{dir}); - -The version that doesn't take an IV is useful for things that don't -use them, like block ciphers in ECB mode, or most stream ciphers. If -you specify a \arg{cipher\_spec} that does want a IV, and you use the -version that doesn't take one, an exception will be thrown. The -\arg{dir} argument can be either \type{ENCRYPTION} or -\type{DECRYPTION}. - -The \arg{cipher\_spec} is a string that specifies what cipher is to be -used. The general syntax for \arg{cipher\_spec} is ``STREAM\_CIPHER'', -``BLOCK\_CIPHER/MODE'', or ``BLOCK\_CIPHER/MODE/PADDING''. In the case -of stream ciphers, no mode is necessary, so just the name is -sufficient. A block cipher requires a mode of some sort, which can be -``ECB'', ``CBC'', ``CFB(n)'', ``OFB'', ``CTR-BE'', or ``EAX(n)''. The -argument to CFB mode is how many bits of feedback should be used. If -you just use ``CFB'' with no argument, it will default to using a -feedback equal to the block size of the cipher. EAX mode also takes an -optional bit argument, which tells EAX how large a tag size to -use~--~generally this is the size of the block size of the cipher, -which is the default if you don't specify any argument. - -In the case of the ECB and CBC modes, a padding method can also be -specified. If it is not supplied, ECB defaults to not padding, and CBC -defaults to using PKCS \#5/\#7 compatible padding. The padding methods -currently available are ``NoPadding'', ``PKCS7'', ``OneAndZeros'', and -``CTS''. CTS padding is currently only available for CBC mode, but the -others can also be used in ECB mode. - -Some example \arg{cipher\_spec} arguments are: ``AES-128/CBC'', -``Blowfish/CTR-BE'', ``Serpent/XTS'', and ``AES-256/EAX''. - -``CTR-BE'' refers to counter mode where the counter is incremented as -if it were a big-endian encoded integer. This is compatible with most -other implementations, but it is possible some will use the -incompatible little endian convention. This version would be denoted -as ``CTR-LE'' if it were supported. - -``EAX'' is a new cipher mode designed by Wagner, Rogaway, and -Bellare. It is an authenticated cipher mode (that is, no separate -authentication is needed), has provable security, and is free from -patent entanglements. It runs about half as fast as most of the other -cipher modes (like CBC, OFB, or CTR), which is not bad considering you -don't need to use an authentication code. - -\subsubsection{Hashes and MACs} - -Hash functions and MACs don't need anything special when it comes to -filters. Both just take their input and produce no output until -\function{end\_msg()} is called, at which time they complete the hash or MAC -and send that as output. - -These \type{Filter}s take a string naming the type to be used. If for some -reason you name something that doesn't exist, an exception will be thrown. - -\noindent -\function{Hash\_Filter}(\type{std::string} \arg{hash}, - \type{u32bit} \arg{outlength}): - -This type hashes its input with \arg{hash}. When \function{end\_msg} is called -on the owning \type{Pipe}, the hash is completed and the digest is sent on to -the next thing in the pipe. The argument \arg{outlength} specifies how much of -the output of the hash will be passed along to the next filter when -\function{end\_msg} is called. By default, it will pass the entire hash. - -Examples of names for \function{Hash\_Filter} are ``SHA-1'' and ``Whirlpool''. - -\noindent -\function{MAC\_Filter}(\type{std::string} \arg{mac}, - \type{const SymmetricKey\&} \arg{key}, - \type{u32bit} \arg{outlength}): - -The constructor for a \type{MAC\_Filter} takes a key, used in calculating the -MAC, and a length parameter, which has semantics the same as the one -passed to \type{Hash\_Filter}s constructor. - -Examples for \arg{mac} are ``HMAC(SHA-1)'', ``CMAC(AES-128)'', and the -exceptionally long, strange, and probably useless name -``CMAC(Lion(Tiger(20,3),MARK-4,1024))''. - -\subsubsection{PK Filters} - -There are four classes in this category, \type{PK\_Encryptor\_Filter}, -\type{PK\_Decryptor\_Filter}, \type{PK\_Signer\_Filter}, and -\type{PK\_Verifier\_Filter}. Each takes a pointer to an object of the -appropriate type (\type{PK\_Encryptor}, \type{PK\_Decryptor}, etc) that is -deleted by the destructor. These classes are found in \filename{pk\_filts.h}. - -Three of these, for encryption, decryption, and signing are much the -same in terms of dataflow - ach of them buffers its input until the -end of the message is marked with a call to the \function{end\_msg} -function. Then they encrypt, decrypt, or sign the entire input as a -single blob and send the output (the ciphertext, the plaintext, or the -signature) into the next filter. - -Signature verification works a little differently, because it needs to -know what the signature is in order to check it. You can either pass -this in along with the constructor, or call the function -\function{set\_signature} -- with this second method, you need to keep -a pointer to the filter around so you can send it this command. In -either case, after \function{end\_msg} is called, it will try to -verify the signature (if the signature has not been set by either -method, an exception will be thrown here). It will then send a single -byte onto the next filter -- a 1 or a 0, which specifies whether the -signature verified or not (respectively). - -For more information about PK algorithms (including creating the -appropriate objects to pass to the constructors), read the section -``Public Key Cryptography'' in this manual. - -\subsubsection{Encoders} - -Often you want your data to be in some form of text (for sending over channels -that aren't 8-bit clean, printing it, etc). The filters \type{Hex\_Encoder} -and \type{Base64\_Encoder} will convert arbitrary binary data into hex or -base64 formats. Not surprisingly, you can use \type{Hex\_Decoder} and -\type{Base64\_Decoder} to convert it back into its original form. - -Both of the encoders can take a few options about how the data should be -formatted (all of which have defaults). The first is a \type{bool} which -says if the encoder should insert line breaks. This defaults to -false. Line breaks don't matter either way to the decoder, but it makes the -output a bit more appealing to the human eye, and a few transport mechanisms -(notably some email systems) limit the maximum line length. - -The second encoder option is an integer specifying how long such lines will be -(obviously this will be ignored if line-breaking isn't being used). The default -tends to be in the range of 60-80 characters, but is not specified. If -you want a specific value, set it. Otherwise the default should be fine. - -Lastly, \type{Hex\_Encoder} takes an argument of type \type{Case}, which can be -\type{Uppercase} or \type{Lowercase} (default is \type{Uppercase}). This -specifies what case the characters A-F should be output as. The base64 encoder -has no such option, because it uses both upper and lower case letters for its -output. - -The decoders both take a single option, which tells it how the object -should behave in the case of invalid input. The enum (called -\type{Decoder\_Checking}) can take on any of three values: -\type{NONE}, \type{IGNORE\_WS}, and \type{FULL\_CHECK}. With -\type{NONE} (the default, for compatibility with previous releases), -invalid input (for example, a ``z'' character in supposedly hex input) -will be ignored. With \type{IGNORE\_WS}, whitespace will be ignored by -the decoder, but receiving other non-valid data will raise an -exception. Finally, \type{FULL\_CHECK} will raise an exception for -\emph{any} characters not in the encoded character set, including -whitespace. - -You can find the declarations for these types in \filename{hex.h} and -\filename{base64.h}. - -\subsection{Rolling Your Own} - -The system of filters and pipes was designed in an attempt to make it -as simple as possible to write new \type{Filter} objects. There are -four functions that need to be implemented by an object deriving from -\type{Filter}: - -\noindent -\type{void} \function{write}(\type{byte} \arg{input}[], \type{u32bit} -\arg{length}): - -The \function{write} function is what is called when a filter receives input -for it to process. The filter is \emph{not} required to process it right away; -many filters buffer their input before producing any output. A filter will -usually have \function{write} called many times during its lifetime. - -\noindent -\type{void} \function{send}(\type{byte} \arg{output}[], \type{u32bit} -\arg{length}): - -Eventually, a filter will want to produce some output to send along to the next -filter in the pipeline. It does so by calling \function{send} with whatever it -wants to send along to the next filter. There is also a version of -\function{send} taking a single byte argument, as a convenience. - -\noindent -\type{void} \function{start\_msg()}: - -This function is optional. Implement it if your \type{Filter} would like to do -some processing or setup at the start of each message (for an example, see the -Zlib compression module). - -\noindent -\type{void} \function{end\_msg()}: - -Implementing the \function{end\_msg} function is optional. It is -called when it has been requested that filters finish up their -computations. The filter should finish up with whatever computation it -is working on (for example, a compressing filter would flush the -compressor and \function{send} the final block), and empty any buffers -in preparation for processing a fresh new set of input. - -Additionally, if necessary, filters can define a constructor that -takes any needed arguments, and a destructor to deal with deallocating -memory, closing files, etc. - -\section{Public Key Cryptography} - -Let's create a 1024-bit RSA private key, encode the public key as a -PKCS \#1 file with PEM encoding (which can be understood by many other -cryptographic programs) - -\begin{verbatim} -// everyone does: -AutoSeeded_RNG rng; - -// Alice -RSA_PrivateKey priv_rsa(rng, 1024 /* bits */); - -std::string alice_pem = X509::PEM_encode(priv_rsa); - -// send alice_pem to Bob, who does - -// Bob -std::auto_ptr<Public_Key> alice(load_key(alice_pem)); - -RSA_PublicKey* alice_rsa = dynamic_cast<RSA_PublicKey>(alice); -if(alice_rsa) - { - /* ... */ - } - -\end{verbatim} - -\subsection{Creating PK Algorithm Key Objects} - -The library has interfaces for encryption, signatures, etc that do not require -knowing the exact algorithm in use (for example RSA and Rabin-Williams -signatures are handled by the exact same code path). - -One place where we \emph{do} need to know exactly what kind of -algorithm is in use is when we are creating a key (\emph{But}: read -the section ``Importing and Exporting PK Keys'', later in this -manual). - -There are currently three kinds of public key algorithms in Botan: -ones based on integer factorization (RSA and Rabin-Williams), ones -based on the discrete logarithm problem in the integers modulo a prime -(DSA, Diffie-Hellman, Nyberg-Rueppel, and ElGamal), and ones based on -the discrete logarithm problem in an elliptic curve (ECDSA, ECDH, GOST -34.10). The systems based on discrete logarithms (in either regular -integers or elliptic curves) use a group (a mathematical term), which -can be shared among many keys. An elliptic curve group is represented -by the class \type{EC\_Domain\_Params}, while a modulo-prime group is -represented by a \type{DL\_Group}. - -There are two ways to create a DL private key (such as -\type{DSA\_PrivateKey}). One is to pass in just a \type{DL\_Group} -object -- a new key will automatically be generated. The other -involves passing in a group to use, along with both the public and -private values (private value first). - -Since in integer factorization algorithms, the modulus used isn't shared by -other keys, we don't use this notion. You can create a new key by passing in a -\type{u32bit} telling how long (in bits) the key should be, or you can copy an -pre-existing key by passing in the appropriate parameters (primes, exponents, -etc). For RSA and Rabin-Williams (the two IF schemes in Botan), the parameters -are all \type{BigInt}s: prime 1, prime 2, encryption exponent, decryption -exponent, modulus. The last two are optional, since they can easily be derived -from the first three. - -\subsubsection{Creating a DL\_Group} - -There are quite a few ways to get a \type{DL\_Group} object. The best is to use -the function \function{get\_dl\_group}, which takes a string naming a group; it -will either return that group, if it knows about it, or throw an -exception. Names it knows about include ``IETF-n'' where n is 768, 1024, 1536, -2048, 3072, or 4096, and ``DSA-n'', where n is 512, 768, or 1024. The IETF -groups are the ones specified for use with IPSec, and the DSA ones are the -default DSA parameters specified by Java's JCE. For DSA and Nyberg-Rueppel, you -should only use the ``DSA-n'' groups, while Diffie-Hellman and ElGamal can use -either type (keep in mind that some applications/standards require DH/ELG to -use DSA-style primes, while others require strong prime groups). - -You can also generate a new random group. This is not recommend, because it is -quite slow, especially for safe primes. - -\subsection{Key Checking} - -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 \function{check\_key} that -takes a \type{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 -\function{check\_key}'s argument is \type{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). - -\subsection{Getting a PK algorithm object} - -The key types, like \type{RSA\_PrivateKey}, do not implement any kind -of padding or encoding (which is necessary for security). To get an -object that knows how to do padding, use the wrapper classes included -in \filename{pubkey.h}. These take a key, along with a string that -specifies what hashing and encoding method(s) to use. Examples of such -strings are ``EME1(SHA-256)'' for OAEP encryption and -``EMSA4(SHA-256)'' for PSS signatures (where the message is hashed -using SHA-256). - -Here are some basic examples (using an RSA key) to give you a feel for -the possibilities. These examples assume \type{rsakey} is an -\type{RSA\_PrivateKey}, since otherwise we would not be able to create -a decryption or signature object with it (you can create encryption or -signature verification objects with public keys, naturally). - -\begin{verbatim} - // PKCS #1 v2.0 / IEEE 1363 compatible encryption - PK_Encryptor_EME rsa_enc_pkcs1_v2(rsakey, "EME1(SHA-1)"); - // PKCS #1 v1.5 compatible encryption - PK_Encryptor_EME rsa_enc_pkcs1_v15(rsakey, "PKCS1v15") - - // This object can decrypt things encrypted by rsa_ - PK_Decryptor_EME rsa_dec_pkcs1_v2(rsakey, "EME1(SHA-1)"); - - // PKCS #1 v1.5 compatible signatures - PK_Signer rsa_sign_pkcs1_v15(rsakey, "EMSA3(MD5)"); - PK_Verifier rsa_verify_pkcs1_v15(rsakey, "EMSA3(MD5)"); - - // PKCS #1 v2.1 compatible signatures - PK_Signer rsa_sign_pkcs1_v2(rsakey, "EMSA4(SHA-1)"); - PK_Verifier rsa_verify_pkcs1_v2(rsakey, "EMSA4(SHA-1)"); -\end{verbatim} - -\subsection{Encryption} - -The \type{PK\_Encryptor} and \type{PK\_Decryptor} classes are the -interface for encryption and decryption, respectively. - -Calling \function{encrypt} with a \type{byte} array, a length -parameter, and an RNG object will return the input encrypted with -whatever scheme is being used. Calling the similar \function{decrypt} -will perform the inverse operation. You can also do these operations -with \type{SecureVector<byte>}s. In all cases, the output is returned -via a \type{SecureVector<byte>}. - -If you attempt an operation with a larger size than the key can -support (this limit varies based on the algorithm, the key size, and -the padding method used (if any)), an exception will be thrown. You -can call \function{maximum\_input\_size} to find out the maximum size -input (in bytes) that you can safely use with any particular key. - -Available public key encryption algorithms in Botan are RSA and -ElGamal. The encoding methods are EME1, denoted by ``EME1(HASHNAME)'', -PKCS \#1 v1.5, called ``PKCS1v15'' or ``EME-PKCS1-v1\_5'', and raw -encoding (``Raw''). - -For compatibility reasons, PKCS \#1 v1.5 is recommend for use with -ElGamal (most other implementations of ElGamal do not support any -other encoding format). RSA can also be used with PKCS \# 1 encoding, -but because of various possible attacks, EME1 is the preferred -encoding. EME1 requires the use of a hash function: unless a competent -applied cryptographer tells you otherwise, you should use SHA-256 or -SHA-512. - -Don't use ``Raw'' encoding unless you need it for backward -compatibility with old protocols. There are many possible attacks -against both ElGamal and RSA when they are used in this way. - -\subsection{Signatures} - -The signature algorithms look quite a bit like the hash functions. You -can repeatedly call \function{update}, giving more and more of a -message you wish to sign, and then call \function{signature}, which -will return a signature for that message. If you want to do it all in -one shot, call \function{sign\_message}, which will just call -\function{update} with its argument and then return whatever -\function{signature} returns. Generating a signature requires random -numbers with some schemes, so \function{signature} and -\function{sign\_message} both take a \type{RandomNumberGenerator\&}. - -You can validate a signature by updating the verifier class, and finally seeing -the if the value returned from \function{check\_signature} is true (you pass -the supposed signature to the \function{check\_signature} function as a byte -array and a length or as a \type{MemoryRegion<byte>}). There is another -function, \function{verify\_message}, which takes a pair of byte array/length -pairs (or a pair of \type{MemoryRegion<byte>} objects), the first of which is -the message, the second being the (supposed) signature. It returns true if the -signature is valid and false otherwise. - -Available public key signature algorithms in Botan are RSA, DSA, -ECDSA, GOST-34.11, Nyberg-Rueppel, and Rabin-Williams. Signature -encoding methods include EMSA1, EMSA2, EMSA3, EMSA4, and Raw. All of -them, except Raw, take a parameter naming a message digest function to -hash the message with. The Raw encoding signs the input directly; if -the message is too big, the signing operation will fail. Raw is not -useful except in very specialized applications. - -There are various interactions that make certain encoding schemes and -signing algorithms more or less useful. - -EMSA2 is the usual method for encoding Rabin-William signatures, so -for compatibility with other implementations you may have to use -that. EMSA4 (also called PSS), also works with Rabin-Williams. EMSA1 -and EMSA3 do \emph{not} work with Rabin-Williams. - -RSA can be used with any of the available encoding methods. EMSA4 is -by far the most secure, but is not (as of now) widely -implemented. EMSA3 (also called ``EMSA-PKCS1-v1\_5'') is commonly used -with RSA (for example in SSL). EMSA1 signs the message digest -directly, without any extra padding or encoding. This may be useful, -but is not as secure as either EMSA3 or EMSA4. EMSA2 may be used but -is not recommended. - -For DSA, ECDSA, GOST-34.11, and Nyberg-Rueppel, you should use -EMSA1. None of the other encoding methods are particularly useful for -these algorithms. - -\subsection{Key Agreement} - -You can get a hold of a \type{PK\_Key\_Agreement\_Scheme} object by -calling \function{get\_pk\_kas} with a key that is of a type that -supports key agreement (such as a Diffie-Hellman key stored in a -\type{DH\_PrivateKey} object), and the name of a key derivation -function. This can be ``Raw'', meaning the output of the primitive -itself is returned as the key, or ``KDF1(hash)'' or ``KDF2(hash)'' -where ``hash'' is any string you happen to like (hopefully you like -strings like ``SHA-256'' or ``RIPEMD-160''), or -``X9.42-PRF(keywrap)'', which uses the PRF specified in ANSI X9.42. It -takes the name or OID of the key wrap algorithm that will be used to -encrypt a content encryption key. - -How key agreement works is that you trade public values with some -other party, and then each of you runs a computation with the other's -value and your key (this should return the same result to both -parties). This computation can be called by using -\function{derive\_key} with either a byte array/length pair, or a -\type{SecureVector<byte>} than holds the public value of the other -party. The last argument to either call is a number that specifies how -long a key you want. - -Depending on the KDF you're using, you \emph{might not} get back a key -of the size you requested. In particular ``Raw'' will return a number -about the size of the Diffie-Hellman modulus, and KDF1 can only return -a key that is the same size as the output of the hash. KDF2, on the -other hand, will always give you a key exactly as long as you request, -regardless of the underlying hash used with it. The key returned is a -\type{SymmetricKey}, ready to pass to a block cipher, MAC, or other -symmetric algorithm. - -The public value that should be used can be obtained by calling -\function{public\_data}, which exists for any key that is associated with a -key agreement algorithm. It returns a \type{SecureVector<byte>}. - -``KDF2(SHA-256)'' is by far the preferred algorithm for key derivation -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. - -\subsection{Importing and Exporting PK Keys} - -[This section mentions \type{Pipe} and \type{DataSource}, which is not covered -until later in the manual. Please read those sections for more about -\type{Pipe} and \type{DataSource} and their uses.] - -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: X.509 (for public keys), and -PKCS \#8 (for private keys). Other crypto libraries, like OpenSSL and B-SAFE, -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 the section ``Certificate Handling'', later in this -manual. - -\subsubsection{Public Keys} - -The interfaces for doing either of these are quite similar. Let's look at the -X.509 stuff first: -\begin{verbatim} -namespace X509 { - MemoryVector<byte> BER_encode(const Public_Key& key); - std::string PEM_encode(const Public_Key& out); - - Public_Key* load_key(DataSource& in); - Public_Key* load_key(const SecureVector<byte>& buffer); -} -\end{verbatim} - -The function \function{X509::BER\_encode} will take any -\type{Public\_Key} and return a standard binary structure representing -the key which can be read by many other crypto libraries. - -The function \function{X509::PEM\_encode} does the same, but -additionally formats it into a text format with headers and base64 -encoding. Using PEM is \emph{highly} recommended for many reasons, -including compatibility with other software, for transmission over -8-bit unclean channels, because it can be identified by a human -without special tools, and because it sometimes allows more sane -behavior of tools that process the data. - -For loading a public key, use one of the variants of -\function{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 -\function{new}, and should be released with \function{delete} when you -are done with it. The first takes a generic \type{DataSource} that you -have to create~--~the others are simple wrapper functions that take -either a filename or a memory buffer. - -Here's an example of loading a public key and then encrypting with it: - -\begin{verbatim} - /* Might be RSA, might be ElGamal, might be ... */ - Public_Key* key = X509::load_key("pubkey.asc"); - - /* This might throw an exception if the key doesn't support any - encryption operations - */ - - PK_Encryptor_EME encryptor(*key, "EME1(SHA-1)"); - - SecureVector<byte> ciphertext = encryptor.encrypt(msg, size_of_msg); -\end{verbatim} - -\subsubsection{Private Keys} - -There are two different options for private key import/export. The first is a -plaintext version of the private key. This is supported by the following -functions: - -\begin{verbatim} -namespace PKCS8 { - SecureVector<byte> BER_encode(const Private_Key& key); - std::string PEM_encode(const Private_Key& key); -} -\end{verbatim} - -These functions are similiar to the X.509 functions described -previously. The only difference is that they take a -\type{Private\_Key} object instead. In most situations, using these is -a bad idea, because anyone can come along and grab the private key -without having to know any passwords or other secrets. Unless you have -very particular security requirements, always use the versions that -encrypt the key based on a passphrase. For importing, the same -functions can be used for encrypted and unencrypted keys. - -The other way to export a PKCS \#8 key is to first encode it in the -same manner as done above, then encrypt it using a passphrase, and -store the whole thing into another structure. This method is -definitely preferred, since otherwise the private key is -unprotected. The algorithms and structures used here are standardized -by PKCS \#5 and PKCS \#8, and can be read by many other crypto -libraries. - -\begin{verbatim} -namespace PKCS8 { - SecureVector<byte> BER_encode(const Private_Key& key, - RandomNumberGenerator& rng, - const std::string& pass, - const std::string& pbe_algo = ""); - - std::string PEM_encode(const Private_Key& key, - RandomNumberGenerator& rng, - const std::string& pass, - const std::string& pbe_algo = ""); -} -\end{verbatim} - -There are three new arguments needed here to support the encryption -process in addition to the private key itself. The first is a -\type{RandomNumberGenerator}, which is needed for various purposes -internally. The \arg{pass} argument is the passphrase that will be -used to encrypt the key. Both of these are required. The final -(optional) argument is \arg{pbe}; this specifies a particular password -based encryption (or PBE) algorithm. If you don't specify a PBE, -a compiled in default will be used; this should be fine. - -Last but not least, there are some functions that will load (and -decrypt, if necessary) a PKCS \#8 private key: - -\begin{verbatim} -namespace PKCS8 { - Private_Key* load_key( - DataSource& in, - RandomNumberGenerator& rng, - std::function<std::pair<bool, std::string> ()> get_passphrase); - - Private_Key* load_key( - const std::string& filename, - RandomNumberGenerator& rng, - std::function<std::pair<bool, std::string> ()> get_passphrase); - - Private_Key* load_key(DataSource& in, - RandomNumberGenerator& rng, - std::string passphrase = ""); - - Private_Key* load_key(const std::string& filename, - RandomNumberGenerator& rng, - const std::string& passphrase = ""); -} -\end{verbatim} - -The versions that take \type{std::string} \arg{passphrase}s are -primarily for compatibility, but they are useful in limited -circumstances. The versions using \type{std::function} callbacks are -how \function{load\_key} is implemented, and provides for much more -flexibility. If you use the versions that take just a single -passphrase, then if the passphrase passed in is not correct, then an -exception is thrown and that is that. However, if you pass in a -callback, then you can keep querying to the user until they get it -right (or they cancel the action). The first return value of the -callback is if the action should continue - if false, -\function{load_key} will bail out. Otherwise, it will use the second -return value as the supposed passphrase that was used to decrypt the -key. - -If you know (or want to assume) the key is not encrypted, just ignore -the passphrase/callback entirely, letting the third parameter default -to an empty string. The call will fail if the key was encrypted. - -All versions need access to a \type{RandomNumberGenerator} in order to -perform probabilistic tests on the loaded key material. - -After loading a key, you can use \function{dynamic\_cast} to find out -what operations it supports, and use it appropriately. Remember to -\function{delete} the object once you are done with it. - -\subsubsection{Limitations} - -As of now Nyberg-Rueppel and Rabin-Williams keys cannot be imported or -exported, because they have no official ASN.1 OID or definition. ElGamal keys -can (as of Botan 1.3.8) be imported and exported, but the only other -implementation that supports the format is Peter Gutmann's Cryptlib. If you -can help it, stick to RSA and DSA. - -\emph{Note}: Currently NR and RW are given basic ASN.1 key formats (which -mirror DSA and RSA, respectively), which means that, if they are assigned an -OID, they can be imported and exported just as easily as RSA and DSA. You can -assign them an OID by putting a line in a Botan configuration file, calling -\function{OIDS::add\_oid}, or editing \filename{src/policy.cpp}. Be warned that -it is possible that a future version will use a format that is different from -the current one (\ie, a newly standardized format). - -\section{Certificate Handling} - -A certificate is a binding between some identifying information -(called a \emph{subject}) and a public key. This binding is asserted -by a signature on the certificate, which is placed there by some -authority (the \emph{issuer}) that at least claims that it knows the -subject named in the certificate really ``owns'' the private key -corresponding to the public key in the certificate. - -The major certificate format in use today is X.509v3, designed by ISO and -further hacked on by dozens (hundreds?) of other organizations. - -When working with certificates, the main class to remember is -\type{X509\_Certificate}. You can read an object of this type, but you -can't create one on the fly; a CA object is necessary for making a new -certificate. So for the most part, you only have to worry about -reading them in, verifying the signatures, and getting the bits of -data in them (most commonly the public key, and the information about -the user of that key). An X.509v3 certificate can contain a literally -infinite number of items related to all kinds of things. Botan doesn't -support a lot of them, because nobody uses them and they're an -impossible mess to work with. This section only documents the most -commonly used ones of the ones that are supported; for the rest, read -\filename{x509cert.h} and \filename{asn1\_obj.h} (which has the -definitions of various common ASN.1 constructs used in X.509). - -\subsection{So what's in an X.509 certificate?} - -Obviously, you want to be able to get the public key. This is achieved -by calling the member function \function{subject\_public\_key}, which -will return a \type{Public\_Key*}. As to what to do with this, read -about \function{load\_key} in the section ``Importing and Exporting PK -Keys''. In the general case, this could be any kind of public key, -though 99\% of the time it will be an RSA key. However, Diffie-Hellman -and DSA keys are also supported, so be careful about how you treat -this. It is also a wise idea to examine the value returned by -\function{constraints}, to see what uses the public key is approved -for. - -The second major piece of information you'll want is the -name/email/etc of the person to whom this certificate is -assigned. Here is where things get a little nasty. X.509v3 has two -(well, mostly just two $\ldots$) different places where you can stick -information about the user: the \emph{subject} field, and in an -extension called \emph{subjectAlternativeName}. The \emph{subject} -field is supposed to only included the following information: country, -organization, an organizational sub-unit name, and a so-called common -name. The common name is usually the name of the person, or it could -be a title associated with a position of some sort in the -organization. It may also include fields for state/province and -locality. What a locality is, nobody knows, but it's usually given as -a city name. - -Botan doesn't currently support any of the Unicode variants used in -ASN.1 (UTF-8, UCS-2, and UCS-4), any of which could be used for the -fields in the DN. This could be problematic, particularly in Asia and -other areas where non-ASCII characters are needed for most names. The -UTF-8 and UCS-2 string types \emph{are} accepted (in fact, UTF-8 is -used when encoding much of the time), but if any of the characters -included in the string are not in ISO 8859-1 (\ie 0 \ldots 255), an -exception will get thrown. Currently the \type{ASN1\_String} type -holds its data as ISO 8859-1 internally (regardless of local character -set); this would have to be changed to hold UCS-2 or UCS-4 in order to -support Unicode (also, many interfaces in the X.509 code would have to -accept or return a \type{std::wstring} instead of a -\type{std::string}). - -Like the distinguished names, subject alternative names can contain a -lot of things that Botan will flat out ignore (most of which you would -likely never want to use). However, there are three very useful pieces -of information that this extension might hold: an email address -(``[email protected]''), a DNS name (``somehost.site2.com''), or a URI -(``http://www.site3.com''). - -So, how to get the information? Call \function{subject\_info} with the -name of the piece of information you want, and it will return a -\type{std::string} that is either empty (signifying that the -certificate doesn't have this information), or has the information -requested. There are several names for each possible item, but the -most easily readable ones are: ``Name'', ``Country'', -``Organization'', ``Organizational Unit'', ``Locality'', ``State'', -``RFC822'', ``URI'', and ``DNS''. These values are returned as a -\type{std::string}. - -You can also get information about the issuer of the certificate in the same -way, using \function{issuer\_info}. - -\subsubsection{X.509v3 Extensions} - -X.509v3 specifies a large number of possible extensions. Botan -supports some, but by no means all of them. This section lists which -ones are supported, and notes areas where there may be problems with -the handling. - -\begin{list}{$\cdot$} - \item Key Usage and Extended Key Usage: No problems known. - \item - - \item Basic Constraints: No problems known. The default for a v1/v2 - certificate is assume it's a CA if and only if the option - ``x509/default\_to\_ca'' is set. A v3 certificate is marked as a CA if - (and only if) the basic constraints extension is present and set for a - CA cert. - - \item Subject Alternative Names: Only the ``rfc822Name'', ``dNSName'', and - ``uniformResourceIdentifier'' fields will be stored; all others are - ignored. - - \item Issuer Alternative Names: Same restrictions as the Subject Alternative - Names extension. New certificates generated by Botan never include the - issuer alternative name. - - \item Authority Key Identifier: Only the version using KeyIdentifier is - supported. If the GeneralNames version is used and the extension is - critical, an exception is thrown. If both the KeyIdentifier and - GeneralNames versions are present, then the KeyIdentifier will be - used, and the GeneralNames ignored. - - \item Subject Key Identifier: No problems known. -\end{list} - -\subsubsection{Revocation Lists} - -It will occasionally happen that a certificate must be revoked before -its expiration date. Examples of this happening include the private -key being compromised, or the user to which it has been assigned -leaving an organization. Certificate revocation lists are an answer to -this problem (though online certificate validation techniques are -starting to become somewhat more popular). Every once in a while the -CA will release a new CRL, listing all certificates that have been -revoked. Also included is various pieces of information like what time -a particular certificate was revoked, and for what reason. In most -systems, it is wise to support some form of certificate revocation, -and CRLs handle this easily. - -For most users, processing a CRL is quite easy. All you have to do is call the -constructor, which will take a filename (or a \type{DataSource\&}). The CRLs -can either be in raw BER/DER, or in PEM format; the constructor will figure out -which format without any extra information. For example: - -\begin{verbatim} - X509_CRL crl1("crl1.der"); - - DataSource_Stream in("crl2.pem"); - X509_CRL crl2(in); -\end{verbatim} - -After that, pass the \type{X509\_CRL} object to a \type{X509\_Store} object -with \type{X509\_Code} \function{add\_crl}(\type{X509\_CRL}), and all future -verifications will take into account the certificates listed, assuming -\function{add\_crl} returns \type{VERIFIED}. If it doesn't return -\type{VERIFIED}, then the return value is an error code signifying that the CRL -could not be processed due to some problem (which could range from the issuing -certificate not being found, to the CRL having some format problem). For more -about the \type{X509\_Store} API, read the section later in this chapter. - -\subsection{Reading Certificates} - -\type{X509\_Certificate} has two constructors, each of which takes a source of -data; a filename to read, and a \type{DataSource\&}. - -\subsection{Storing and Using Certificates} - -If you read a certificate, you probably want to verify the signature on -it. However, consider that to do so, we may have to verify the signature on the -certificate that we used to verify the first certificate, and on and on until -we hit the top of the certificate tree somewhere. It would be a might huge pain -to have to handle all of that manually in every application, so there is -something that does it for you: \type{X509\_Store}. - -The basic operations are: put certificates and CRLs into it, search -for certificates, and attempt to verify certificates. That's about -it. In the future, there will be support for online retrieval of -certificates and CRLs (\eg with the HTTP cert-store interface -currently under consideration by PKIX). - -\subsubsection{Adding Certificates} - -You can add new certificates to a certificate store using any of these -functions: - -\function{add\_cert}(\type{const X509\_Certificate\&} \arg{cert}, - \type{bool} \arg{trusted} \type{= false}) - -\function{add\_certs}(\type{DataSource\&} \arg{source}) - -\function{add\_trusted\_certs}(\type{DataSource\&} \arg{source}) - -The versions that take a \type{DataSource\&} will add all the certificates -that it can find in that source. - -All of them add the cert(s) to the store. The 'trusted' certificates are the -ones that you have some reason to trust are genuine. For example, say your -application is working with certificates that are owned by employees of some -company, and all of their certificates are signed by the company CA, whose -certificate is in turned signed by a commercial root CA. What you would then do -is include the certificate of the commercial CA with your application, and read -it in as a trusted certificate. From there, you could verify the company CA's -certificate, and then use that to verify the end user's certificates. Only -self-signed certificates may be considered trusted. - -\subsubsection{Adding CRLs} - -\type{X509\_Code} \function{add\_crl}(\type{const X509\_CRL\&} \arg{crl}); - -This will process the CRL and mark the revoked certificates. This will also -work if a revoked certificate is added to the store sometime after the CRL is -processed. The function can return an error code (listed later), or will return -\type{VERIFIED} if everything completed successfully. - -\subsubsection{Storing Certificates} - -You can output a set of certificates by calling \function{PEM\_encode}, which -will return a \type{std::string} containing each of the certificates in the -store, PEM encoded and concatenated. This simple format can easily be read by -both Botan and other libraries/applications. - -\subsubsection{Searching for Certificates} - -You can find certificates in the store with a series of functions contained -in the \function{X509\_Store\_Search} namespace: - -\begin{verbatim} -namespace X509_Store_Search { -std::vector<X509_Certificate> by_email(const X509_Store& store, - const std::string& email_addr); -std::vector<X509_Certificate> by_name(const X509_Store& store, - const std::string& name); -std::vector<X509_Certificate> by_dns(const X509_Store&, - const std::string& dns_name); -} -\end{verbatim} - -These functions will return a (possibly empty) vector of certificates from -\arg{store} matching your search criteria. The email address and DNS name -searches are case-insensitive but are sensitive to extra whitespace and so -on. The name search will do case-insensitive substring matching, so, for -example, calling \function{X509\_Store\_Search::by\_name}(\arg{your\_store}, -``dob'') will return certificates for ``J.R. 'Bob' Dobbs'' and -``H. Dobbertin'', assuming both of those certificates are in \arg{your\_store}. - -You could then display the results to a user, and allow them to select the -appropriate one. Searching using an email address as the key is usually more -effective than the name, since email addresses are rarely shared. - -\subsubsection{Certificate Stores} - -An object of type \type{Certificate\_Store} is a generalized interface -to an external source for certificates (and CRLs). Examples of such a -store would be one that looked up the certificates in a SQL database, -or by contacting a CGI script running on a HTTP server. There are -currently three mechanisms for looking up a certificate, and one for -retrieving CRLs. By default, most of these mechanisms will return an -empty \type{std::vector} of \type{X509\_Certificate}. This storage -mechanism is \emph{only} queried when doing certificate validation: it -allows you to distribute only the root key with an application, and -let some online method handle getting all the other certificates that -are needed to validate an end entity certificate. In particular, the -search routines will not attempt to access the external database. - -The three certificate lookup methods are \function{by\_SKID} (Subject Key -Identifier), \function{by\_name} (the CommonName DN entry), and -\function{by\_email} (stored in either the distinguished name, or in a -subjectAlternativeName extension). The name and email versions take a -\type{std::string}, while the SKID version takes a \type{SecureVector<byte>} -containing the subject key identifier in raw binary. You can choose not to -implement \function{by\_name} or \function{by\_email}, but \function{by\_SKID} -is mandatory to implement, and, currently, is the only version that is used by -\type{X509\_Store}. - -Finally, there is a method for finding CRLs, called -\function{get\_crls\_for}, that takes an \type{X509\_Certificate} -object, and returns a \type{std::vector} of \type{X509\_CRL}. While -normally there will be only one CRL, the use of the vector makes it -easy to return no CRLs (\eg, if the certificate store doesn't support -retrieving them), or return multiple ones (for example, if the -certificate store can't determine precisely which key was used to sign -the certificate). Implementing the function is optional, and by -default will return no CRLs. If it is available, it will be used by -\type{X509\_CRL}. - -As for using such a store, you have to tell \type{X509\_Store} about -it, by calling the \type{X509\_Store} member function - -\function{add\_new\_certstore}(\type{Certificate\_Store}* \arg{new\_store}) - -The argument, \arg{new\_store}, will be deleted by \type{X509\_Store}'s -destructor, so make sure to allocate it with \function{new}. - -\subsubsection{Verifying Certificates} - -There is a single function in \type{X509\_Store} related to verifying a -certificate: - -\type{X509\_Code} -\function{validate\_cert}(\type{const X509\_Certificate\&} \arg{cert}, - \type{Cert\_Usage} \arg{usage} = \type{ANY}) - -This function will return \type{VERIFIED} if the certificate can -safely be considered valid for the usage(s) described by \arg{usage}, -and an error code if it is not. Naturally, things are a bit more -complicated than that. The enum \type{Cert\_Usage} is defined inside -the \type{X509\_Store} class, it (currently) can take on any of the -values \type{ANY} (any usage is OK), \type{TLS\_SERVER} (for SSL/TLS -server authentication), \type{TLS\_CLIENT} (for SSL/TLS client -authentication), \type{CODE\_SIGNING}, \type{EMAIL\_PROTECTION} (email -encryption, usually this means S/MIME), \type{TIME\_STAMPING} (in -theory any time stamp application, usually IETF PKIX's Time Stamp -Protocol), or \type{CRL\_SIGNING}. Note that Microsoft's code signing -system, certainly the most widely used, uses a completely different -(and mostly undocumented) method for marking certificates for code -signing. - -First, how does it know if a certificate is valid? A certificate is -valid if both of the following hold: a) the signature in the -certificate can be verified using the public key in the issuer's -certificate, and b) the issuer's certificate is a valid CA -certificate. Note that this definition is recursive. We get out of -this by ``bottoming out'' when we reach a certificate that we consider -trusted. In general this will either be a commercial root CA, or an -organization or application specific CA. - -There are a few other restrictions (validity periods, key usage -restrictions, etc), but the above summarizes the major points of the -validation algorithm. In theory, Botan implements the certificate path -validation algorithm given in RFC 2459, but in practice it does not -(yet), because we don't support the X.509v3 policy or name constraint -extensions. - -Possible values for \arg{usage} are \type{TLS\_SERVER}, -\type{TLS\_CLIENT}, \type{CODE\_SIGNING}, \type{EMAIL\_PROTECTION}, -\type{CRL\_SIGNING}, and \type{TIME\_STAMPING}, and \type{ANY}. The -default \type{ANY} does not mean valid for any use, it means ``is -valid for some usage''. This is usually what you want; requiring that -a random certificate support a particular usage will likely result in -a lot of failures, unless your application is very careful to always -issue certificates with the proper extensions, and you never use -certificates generated by other apps. - -Return values for \function{validate\_cert} (and \function{add\_crl}) include: - -\begin{list}{$\cdot$} - \item VERIFIED: The certificate is valid for the specified use. - \item - \item INVALID\_USAGE: The certificate cannot be used for the specified use. - - \item CANNOT\_ESTABLISH\_TRUST: The root certificate was not marked as - trusted. - \item CERT\_CHAIN\_TOO\_LONG: The certificate chain exceeded the length - allowed by a basicConstraints extension. - \item SIGNATURE\_ERROR: An invalid signature was found - \item POLICY\_ERROR: Some problem with the certificate policies was found. - - \item CERT\_FORMAT\_ERROR: Some format problem was found in a certificate. - \item CERT\_ISSUER\_NOT\_FOUND: The issuer of a certificate could not be - found. - \item CERT\_NOT\_YET\_VALID: The certificate is not yet valid. - \item CERT\_HAS\_EXPIRED: The certificate has expired. - \item CERT\_IS\_REVOKED: The certificate has been revoked. - - \item CRL\_FORMAT\_ERROR: Some format problem was found in a CRL. - \item CRL\_ISSUER\_NOT\_FOUND: The issuer of a CRL could not be found. - \item CRL\_NOT\_YET\_VALID: The CRL is not yet valid. - \item CRL\_HAS\_EXPIRED: The CRL has expired. - - \item CA\_CERT\_CANNOT\_SIGN: The CA certificate found does not have an - contain a public key that allows signature verification. - \item CA\_CERT\_NOT\_FOR\_CERT\_ISSUER: The CA cert found is not allowed to - issue certificates. - \item CA\_CERT\_NOT\_FOR\_CRL\_ISSUER: The CA cert found is not allowed to - issue CRLs. - - \item UNKNOWN\_X509\_ERROR: Some other error occurred. - -\end{list} - -\subsection{Certificate Authorities} - -Setting up a CA for X.509 certificates is perhaps the easiest thing to -do related to X.509. A CA is represented by the type \type{X509\_CA}, -which can be found in \filename{x509\_ca.h}. A CA always needs its own -certificate, which can either be a self-signed certificate (see below -on how to create one) or one issued by another CA (see the section on -PKCS \#10 requests). Creating a CA object is done by the following -constructor: - -\begin{verbatim} - X509_CA(const X509_Certificate& cert, const Private_Key& key); -\end{verbatim} - -The private key is the private key corresponding to the public key in the -CA's certificate. - -Requests for new certificates are supplied to a CA in the form on PKCS -\#10 certificate requests (called a \type{PKCS10\_Request} object in -Botan). These are decoded in a similar manner to -certificates/CRLs/etc. A request is vetted by humans (who somehow -verify that the name in the request corresponds to the name of the -entity who requested it), and then signed by a CA key, generating a -new certificate. - -\begin{verbatim} - X509_Certificate sign_request(const PKCS10_Request&) const; -\end{verbatim} - -\subsubsection{Generating CRLs} - -As mentioned previously, the ability to process CRLs is highly important in -many PKI systems. In fact, according to strict X.509 rules, you must not -validate any certificate if the appropriate CRLs are not available (though -hardly any systems are that strict). In any case, a CA should have a valid CRL -available at all times. - -Of course, you might be wondering what to do if no certificates have -been revoked. Never fear; empty CRLs, which revoke nothing at all, can -be issued. To generate a new, empty CRL, just call \type{X509\_CRL} -\function{X509\_CA::new\_crl}(\type{u32bit}~\arg{seconds}~=~0)~--~it -will create a new, empty, CRL. If \arg{seconds} is the default 0, then -the normal default CRL next update time (the value of the -``x509/crl/next\_update'') will be used. If not, then \arg{seconds} -specifies how long (in seconds) it will be until the CRL's next update -time (after this time, most clients will reject the CRL as too old). - -On the other hand, you may have issued a CRL before. In that case, you will -want to issue a new CRL that contains all previously revoked -certificates, along with any new ones. This is done by calling the -\type{X509\_CA} member function -\function{update\_crl}(\type{X509\_CRL}~\arg{old\_crl}, -\type{std::vector<CRL\_Entry>}~\arg{new\_revoked}, -\type{u32bit}~\arg{seconds}~=~0), where \type{X509\_CRL} is the last CRL this -CA issued, and \arg{new\_revoked} is a list of any newly revoked certificates. -The function returns a new \type{X509\_CRL} to make available for clients. The -semantics for the \arg{seconds} argument is the same as \function{new\_crl}. - -The \type{CRL\_Entry} type is a structure that contains, at a minimum, the -serial number of the revoked certificate. As serial numbers are never repeated, -the pairing of an issuer and a serial number (should) distinctly identify any -certificate. In this case, we represent the serial number as a -\type{SecureVector<byte>} called \arg{serial}. There are two additional -(optional) values, an enumeration called \type{CRL\_Code} that specifies the -reason for revocation (\arg{reason}), and an object that represents the time -that the certificate became invalid (if this information is known). - -If you wish to remove an old entry from the CRL, insert a new entry for the -same cert, with a \arg{reason} code of \type{DELETE\_CRL\_ENTRY}. For example, -if a revoked certificate has expired 'normally', there is no reason to continue -to explicitly revoke it, since clients will reject the cert as expired in any -case. - -\subsubsection{Self-Signed Certificates} - -Generating a new self-signed certificate can often be useful, for -example when setting up a new root CA, or for use in email -applications. The library provides a utility function for this: - -\begin{verbatim} -namespace X509 { - X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, - const Private_Key& key); -} -\end{verbatim} - -Where \arg{key} is obviously the private key you wish to use (the public key, -used in the certificate itself, is extracted from the private key), and -\arg{opts} is an structure that has various bits of information that will be -used in creating the certificate (this structure, and its use, is discussed -below). This function is found in the header \filename{x509self.h}. There is an -example of using this function in the \filename{self\_sig} example. - -\subsubsection{Creating PKCS \#10 Requests} - -Also in \filename{x509self.h}, there is a function for generating new PKCS \#10 -certificate requests. - -\begin{verbatim} -namespace X509 { - PKCS10_Request create_cert_req(const X509_Cert_Options&, - const Private_Key&); -} -\end{verbatim} - -This function acts quite similarly to \function{create\_self\_signed\_cert}, -except it instead returns a PKCS \#10 certificate request. After creating it, -one would typically transmit it to a CA, who signs it and returns a freshly -minted X.509 certificate. There is an example of using this function in the -\filename{pkcs10} example. - -\subsubsection{Certificate Options} - -What is this \type{X509\_Cert\_Options} thing we've been passing -around? It's a class representing a bunch of information that will end -up being stored into the certificate. This information comes in 3 -major flavors: information about the subject (CA or end-user), the -validity period of the certificate, and restrictions on the usage of -the certificate. - -First and foremost is a number of \type{std::string} members, which contains -various bits of information about the user: \arg{common\_name}, -\arg{serial\_number}, \arg{country}, \arg{organization}, \arg{org\_unit}, -\arg{locality}, \arg{state}, \arg{email}, \arg{dns\_name}, and \arg{uri}. As -many of these as possible should be filled it (especially an email address), -though the only required ones are \arg{common\_name} and \arg{country}. - -There is another value that is only useful when creating a PKCS \#10 request, -which is called \arg{challenge}. This is a challenge password, which you can -later use to request certificate revocation (\emph{if} the CA supports doing -revocations in this manner). - -Then there is the validity period; these are set with \function{not\_before} -and \function{not\_after}. Both of these functions also take a -\type{std::string}, which specifies when the certificate should start being -valid, and when it should stop being valid. If you don't set the starting -validity period, it will automatically choose the current time. If you don't -set the ending time, it will choose the starting time plus a default time -period. The arguments to these functions specify the time in the following -format: ``2002/11/27 1:50:14''. The time is in 24-hour format, and the date is -encoded as year/month/day. The date must be specified, but you can omit the -time or trailing parts of it, for example ``2002/11/27 1:50'' or -``2002/11/27''. - -Lastly, you can set constraints on a key. The one you're mostly likely to want -to use is to create (or request) a CA certificate, which can be done by calling -the member function \function{CA\_key}. This should only be used when needed. - -Other constraints can be set by calling the member functions -\function{add\_constraints} and \function{add\_ex\_constraints}. The -first takes a \type{Key\_Constraints} value, and replaces any -previously set value. If no value is set, then the certificate key is -marked as being valid for any usage. You can set it to any of the -following (for more than one usage, OR them together): -\type{DIGITAL\_SIGNATURE}, \type{NON\_REPUDIATION}, -\type{KEY\_ENCIPHERMENT}, \type{DATA\_ENCIPHERMENT}, -\type{KEY\_AGREEMENT}, \type{KEY\_CERT\_SIGN}, \type{CRL\_SIGN}, -\type{ENCIPHER\_ONLY}, \type{DECIPHER\_ONLY}. Many of these have quite -special semantics, so you should either consult the appropriate -standards document (such as RFC 3280), or just not call -\function{add\_constraints}, in which case the appropriate values will -be chosen for you. - -The second function, \function{add\_ex\_constraints}, allows you to specify an -OID that has some meaning with regards to restricting the key to particular -usages. You can, if you wish, specify any OID you like, but there is a set of -standard ones that other applications will be able to understand. These are -the ones specified by the PKIX standard, and are named ``PKIX.ServerAuth'' (for -TLS server authentication), ``PKIX.ClientAuth'' (for TLS client -authentication), ``PKIX.CodeSigning'', ``PKIX.EmailProtection'' (most likely -for use with S/MIME), ``PKIX.IPsecUser'', ``PKIX.IPsecTunnel'', -``PKIX.IPsecEndSystem'', and ``PKIX.TimeStamping''. You can call -\function{add\_ex\_constraints} any number of times~--~each new OID will be -added to the list to include in the certificate. - -\section{The Low-Level Interface} - -Botan has two different interfaces. The one documented in this section is meant -more for implementing higher-level types (see the section on filters, earlier in -this manual) than for use by applications. Using it safely requires a solid -knowledge of encryption techniques and best practices, so unless you know, for -example, what CBC mode and nonces are, and why PKCS \#1 padding is important, -you should avoid this interface in favor of something working at a higher level -(such as the CMS interface). - -\subsection{Basic Algorithm Abilities} - -There are a small handful of functions implemented by most of Botan's -algorithm objects. Among these are: - -\noindent -\type{std::string} \function{name}(): - -Returns a human-readable string of the name of this algorithm. Examples of -names returned are ``Blowfish'' and ``HMAC(MD5)''. You can turn names back into -algorithm objects using the functions in \filename{lookup.h}. - -\noindent -\type{void} \function{clear}(): - -Clear out the algorithm's internal state. A block cipher object will -``forget'' its key, a hash function will ``forget'' any data put into -it, etc. The object will look and behave as it did when you initially -allocated it. - -\noindent -\function{clone}(): - -This function is central to Botan's name-based interface. The \function{clone} -has many different return types, such as \type{BlockCipher*} and -\type{HashFunction*}, depending on what kind of object it is called on. Note -that unlike Java's clone, this returns a new object in a ``pristine'' state; -that is, operations done on the initial object before calling \function{clone} -do not affect the initial state of the new clone. - -Cloned objects can (and should) be deallocated with the C++ \texttt{delete} -operator. - -\subsection{Keys and IVs} - -Both symmetric keys and initialization values can be considered byte -(or octet) strings. These are represented by the classes -\type{SymmetricKey} and \type{InitializationVector}, which are -subclasses of \type{OctetString}. - -Since often it's hard to distinguish between a key and IV, many things (such as -key derivation mechanisms) return \type{OctetString} instead of -\type{SymmetricKey} to allow its use as a key or an IV. - -\noindent -\function{OctetString}(\type{u32bit} \arg{length}): - -This constructor creates a new random key of size \arg{length}. - -\noindent -\function{OctetString}(\type{std::string} \arg{str}): - -The argument \arg{str} is assumed to be a hex string; it is converted to binary -and stored. Whitespace is ignored. - -\noindent -\function{OctetString}(\type{const byte} \arg{input}[], \type{u32bit} -\arg{length}): - -This constructor copies its input. - -\subsection{Symmetrically Keyed Algorithms} - -Block ciphers, stream ciphers, and MACs are all keyed operations; to -be useful, they have to be set to use a particular key, which is a -randomly chosen string of bits of a specified length. The length -required by any particular algorithm may vary, depending on both the -algorithm specification and the implementation. You can query any -botan object to find out what key length(s) it supports. - -To make this similarity in terms of keying explicit, all algorithms of -those types are derived from the \type{SymmetricAlgorithm} base -class. This type has three functions: - -\noindent -\type{void} \function{set\_key}(\type{const byte} \arg{key}[], \type{u32bit} -\arg{length}): - -Most algorithms only accept keys of certain lengths. If you attempt to call -\function{set\_key} with a key length that is not supported, the exception -\type{Invalid\_Key\_Length} will be thrown. There is also another version of -\function{set\_key} that takes a \type{SymmetricKey} as an argument. - -\noindent -\type{bool} \function{valid\_keylength}(\type{u32bit} \arg{length}) const: - -This function returns true if a key of the given length will be accepted by -the cipher. - -There are also three constant data members of every -\type{SymmetricAlgorithm} object, which specify what limits there are -on keys which that object can accept: - -MAXIMUM\_KEYLENGTH: The maximum length of a key. Usually, this is at -most 32 (256 bits), even if the algorithm supports more. In a few rare -cases larger keys will be supported. - -MINIMUM\_KEYLENGTH: The minimum length of a key. This is at least 1. - -KEYLENGTH\_MULTIPLE: The length of the key must be a multiple of this value. - -In all cases, \function{set\_key} must be called on an object before any data -processing (encryption, decryption, etc) is done by that object. If this is not -done, the results are undefined -- that is to say, Botan reserves the right in -this situation to do anything from printing a nasty, insulting message on the -screen to dumping core. - -\subsection{Block Ciphers} - -Block ciphers implement the interface \type{BlockCipher}, found in -\filename{base.h}, as well as the \type{SymmetricAlgorithm} interface. - -\noindent -\type{void} \function{encrypt}(\type{const byte} \arg{in}[], - \type{byte} \arg{out}[]) const - -\noindent -\type{void} \function{encrypt}(\type{byte} \arg{block}[]) const - -These functions apply the block cipher transformation to \arg{in} and -place the result in \arg{out}, or encrypts \arg{block} in place -(\arg{in} may be the same as \arg{out}). Exactly one block will be -encrypted; you can find out the block size of the cipher you are -working with by calling the member function \function{block\_size}. -\type{BlockCipher}s have similar functions \function{decrypt}, which -perform the inverse operation. - -If you want to process multiple blocks in parallel, use -\function{encrypt\_n} and \function{decrypt\_n}. - -\begin{verbatim} -AES_128 cipher; -SymmetricKey key(cipher.MAXIMUM_KEYLENGTH); // randomly created -cipher.set_key(key); - -byte in[16] = { /* secrets */ }; -byte out[16]; -cipher.encrypt(in, out); -\end{verbatim} - -\subsection{Stream Ciphers} - -Stream ciphers are somewhat different from block ciphers, in that encrypting -data results in changing the internal state of the cipher. Also, you may -encrypt any length of data in one go (in byte amounts). - -\noindent -\type{void} \function{encrypt}(\type{const byte} \arg{in}[], \type{byte} -\arg{out}[], \type{u32bit} \arg{length}) - -\noindent -\type{void} \function{encrypt}(\type{byte} \arg{data}[], \type{u32bit} -\arg{length}): - -These functions encrypt the arbitrary length (well, less than 4 gigabyte long) -string \arg{in} and place it into \arg{out}, or encrypts it in place in -\arg{data}. The \function{decrypt} functions look just like -\function{encrypt}. - -Stream ciphers implement the \type{SymmetricAlgorithm} interface. - -Some stream ciphers support random access to any point in their cipher -stream. For such ciphers, calling \type{void} \function{seek}(\type{u32bit} -\arg{byte}) will change the cipher's state so that it is as if the cipher had been -keyed as normal, then encrypted \arg{byte} -- 1 bytes of data (so the next byte -in the cipher stream is byte number \arg{byte}). - -\subsection{Hash Functions / Message Authentication Codes} - -Hash functions take their input without producing any output, only producing -anything when all input has already taken place. MACs are very similar, but are -additionally keyed. Both of these are derived from the base class -\type{BufferedComputation}, which has the following functions. - -\noindent -\type{size\_t} \function{output\_length}() - -Return the size of the output of this function. - -\type{void} \function{update}(\type{const byte} \arg{input}[], \type{u32bit} -\arg{length}) - -\noindent -\type{void} \function{update}(\type{byte} \arg{input}) - -\noindent -\type{void} \function{update}(\type{const std::string \&} \arg{input}) - -Updates the hash/mac calculation with \arg{input}. - -\noindent -\type{void} \function{final}(\type{byte} \arg{out}[]) - -\noindent -\type{SecureVector<byte>} \function{final}(): - -Complete the hash/MAC calculation and place the result into \arg{out}. -For the argument taking an array, exactly \function{output\_length}() -bytes will be written. After you call \function{final}, the hash -function is reset to its initial state, so it may be reused -immediately. - -The second method of using final is to call it with no arguments at -all, as shown in the second prototype. It will return the hash/mac -value in a memory buffer. - -There is also a pair of functions called \function{process}. They are -a combination of a single \function{update}, and \function{final}. -Both versions return the final value, rather than placing it an -array. Calling \function{process} with a single byte value isn't -available, mostly because it would rarely be useful. - -A MAC can be viewed (in most cases) as a keyed hash function, so -classes that are derived from \type{MessageAuthenticationCode} have -\function{update} and \function{final} classes just like a -\type{HashFunction} (and like a \type{HashFunction}, after -\function{final} is called, it can be used to make a new MAC right -away; the key is kept around). - -A MAC has the \type{SymmetricAlgorithm} interface in addition to the -\type{BufferedComputation} interface. - -\section{Random Number Generators} - -The random number generators provided in Botan are meant for creating -keys, IVs, padding, nonces, and anything else that requires 'random' -data. It is important to remember that the output of these classes -will vary, even if they are supplied with ethe same seed (\ie, two -\type{Randpool} objects with similar initial states will not produce -the same output, because the value of high resolution timers is added -to the state at various points). - -To ensure good quality output, a PRNG needs to be seeded with truly random data -(such as that produced by a hardware RNG). Typically, you will use an -\type{EntropySource} (see below). To add entropy to a PRNG, you can use -\type{void} \function{add\_entropy}(\type{const byte} \arg{data}[], -\type{u32bit} \arg{length}) or (better), use the \type{EntropySource} -interface. - -Once a PRNG has been initialized, you can get a single byte of random data by -calling \type{byte} \function{random()}, or get a large block by calling -\type{void} \function{randomize}(\type{byte} \arg{data}[], \type{u32bit} -\arg{length}), which will put random bytes into each member of the array from -indexes 0 $\ldots$ \arg{length} -- 1. - -You can avoid all the problems inherent in seeding the PRNG by using the -globally shared PRNG, described later in this section. - -\subsection{Randpool} - -\type{Randpool} is the primary PRNG within Botan. In recent versions all uses -of it have been wrapped by an implementation of the X9.31 PRNG (see below). If -for some reason you should have cause to create a PRNG instead of using the -``global'' one owned by the library, it would be wise to consider the same on -the grounds of general caution; while \type{Randpool} is designed with known -attacks and PRNG weaknesses in mind, it is not an standard/official PRNG. The -remainder of this section is a (fairly technical, though high-level) description -of the algorithms used in this PRNG. Unless you have a specific interest in -this subject, the rest of this section might prove somewhat uninteresting. - -\type{Randpool} has an internal state called pool, which is 512 bytes -long. This is where entropy is mixed into and extracted from. There is also a -small output buffer (called buffer), which holds the data which has already -been generated but has just not been output yet. - -It is based around a MAC and a block cipher (which are currently HMAC(SHA-256) -and AES-256). Where a specific size is mentioned, it should be taken as a -multiple of the cipher's block size. For example, if a 256-bit block cipher -were used instead of AES, all the sizes internally would double. Every time -some new output is needed, we compute the MAC of a counter and a high -resolution timer. The resulting MAC is XORed into the output buffer (wrapping -as needed), and the output buffer is then encrypted with AES, producing 16 -bytes of output. - -After 8 blocks (or 128 bytes) have been produced, we mix the pool. To do this, -we first rekey both the MAC and the cipher; the new MAC key is the MAC of the -current pool under the old MAC key, while the new cipher key is the MAC of the -current pool under the just-chosen MAC key. We then encrypt the entire pool in -CBC mode, using the current (unused) output buffer as the IV. We then generate -a new output buffer, using the mechanism described in the previous paragraph. - -To add randomness to the PRNG, we compute the MAC of the input and XOR the -output into the start of the pool. Then we remix the pool and produce a new -output buffer. The initial MAC operation should make it very hard for chosen -inputs to harm the security of \type{Randpool}, and as HMAC should be able to -hold roughly 256 bits of state, it is unlikely that we are wasting much input -entropy (or, if we are, it doesn't matter, because we have a very abundant -supply). - -\subsection{ANSI X9.31} - -\type{ANSI\_X931\_PRNG} is the standard issue X9.31 Appendix A.2.4 PRNG, though -using AES-256 instead of 3DES as the block cipher. This PRNG implementation has -been checked against official X9.31 test vectors. - -Internally, the PRNG holds a pointer to another PRNG (typically -Randpool). This internal PRNG generates the key and seed used by the -X9.31 algorithm, as well as the date/time vectors. Each time an X9.31 -PRNG object receives entropy, it passes it along to the PRNG it is -holding, and then pulls out some random bits to generate a new key and -seed. This PRNG considers itself seeded as soon as the internal PRNG -is seeded. - -As of version 1.4.7, the X9.31 PRNG is by default used for all random number -generation. - -\subsection{Entropy Sources} - -An \type{EntropySource} is an abstract representation of some method of gather -``real'' entropy. This tends to be very system dependent. The \emph{only} way -you should use an \type{EntropySource} is to pass it to a PRNG that will -extract entropy from it -- never use the output directly for any kind of key or -nonce generation! - -\type{EntropySource} has a pair of functions for getting entropy from -some external source, called \function{fast\_poll} and -\function{slow\_poll}. These pass a buffer of bytes to be written; the -functions then return how many bytes of entropy were -gathered. \type{EntropySource}s are usually used to seed the global -PRNG using the functions found in the \namespace{Global\_RNG} -namespace. - -Note for writers of \type{EntropySource}s: it isn't necessary to use any kind -of cryptographic hash on your output. The data produced by an EntropySource is -only used by an application after it has been hashed by the -\type{RandomNumberGenerator} that asked for the entropy, thus any hashing -you do will be wasteful of both CPU cycles and entropy. - -\section{User Interfaces} - -Botan has recently changed some infrastructure to better accommodate -more complex user interfaces, in particular ones that are based on -event loops. Primary among these was the fact that when doing -something like loading a PKCS \#8 encoded private key, a passphrase -might be needed, but then again it might not (a PKCS \#8 key doesn't -have to be encrypted). Asking for a passphrase to decrypt an -unencrypted key is rather pointless. Not only that, but the way to -handle the user typing the wrong passphrase was complicated, -undocumented, and inefficient. - -So now Botan has an object called \type{UI}, which provides a simple -interface for the aspects of user interaction the library has to be -concerned with. Currently, this means getting a passphrase from the -user, and that's it (\type{UI} will probably be extended in the future -to support other operations as they are needed). The base \type{UI} -class is very stupid, because the library can't directly assume -anything about the environment that it's running under (for example, -if there will be someone sitting at the terminal, if the application -is even \emph{attached} to a terminal, and so on). But since you can -subclass \type{UI} to use whatever method happens to be appropriate -for your application, this isn't a big deal. - -\begin{verbatim} - std::string get_passphrase(const std::string& what, - const std::string& source, - UI_Result& result) const; -\end{verbatim} - -The \arg{what} argument specifies what the passphrase is needed for (for -example, PKCS \#8 key loading passes \arg{what} as ``PKCS \#8 private -key''). This lets you provide the user with some indication of \emph{why} your -application is asking for a passphrase; feel free to pass the string through -\function{gettext(3)} or moral equivalent for i18n purposes. Similarly, -\arg{source} specifies where the data in question came from, if available (for -example, a file name). If the source is not available for whatever reason, then -\arg{source} will be an empty string; be sure to account for this possibility -when writing a \type{UI} subclass. - -The function returns the passphrase as the return value, and a status code in -\arg{result} (either \type{OK} or \type{CANCEL\_ACTION}). If -\type{CANCEL\_ACTION} is returned in \arg{result}, then the return value will -be ignored, and the caller will take whatever action is necessary (typically, -throwing an exception stating that the passphrase couldn't be determined). In -the specific case of PKCS \#8 key decryption, a \type{Decoding\_Error} -exception will be thrown; your UI should assume this can happen, and provide -appropriate error handling (such as putting up a dialog box informing the user -of the situation, and canceling the operation in progress). - -There is an example \type{UI} that uses GTK+ available on the web site. The -\type{GTK\_UI} code is cleanly separated from the rest of the example, so if -you happen to be using GTK+, you can copy (and/or adapt) that code for your -application. If you write a \type{UI} object for another windowing system -(Win32, Qt, wxWidgets, FOX, etc), and would like to make it available to users -in general (ideally under a permissive license such as public domain or -MIT/BSD), feel free to send in a copy. - -\section{Botan's Modules} - -Botan comes with a variety of modules that can be compiled into the system. -These will not be available on all installations of the library, but you can -check for their availability based on whether or not certain macros are -defined. - -\subsection{Pipe I/O for Unix File Descriptors} - -This is a minor feature, but it comes in handy sometimes. In all -installations of the library, Botan's \type{Pipe} object overloads the -\keyword{<<} and \keyword{>>} operators for C++ iostream objects, -which is usually more than sufficient for doing I/O. - -However, there are cases where the iostream hierarchy does not map well to -local 'file types', so there is also the ability to do I/O directly with Unix -file descriptors. This is most useful when you want to read from or write to -something like a TCP or Unix-domain socket, or a pipe, since for simple file -access it's usually easier to just use C++'s file streams. - -If \macro{BOTAN\_EXT\_PIPE\_UNIXFD\_IO} is defined, then you can use the -overloaded I/O operators with Unix file descriptors. For an example of this, -check out the \filename{hash\_fd} example, included in the Botan distribution. - -\subsection{Entropy Sources} - -All of these are used by the \function{Global\_RNG::seed} function if -they are available. Since this function is called by the -\type{LibraryInitializer} class when it is created, it is rare -that you will need to deal with any of these classes directly. Even in -the case of a long-running server that needs to renew its entropy -poll, it is easier to call \function{Global\_RNG::seed} (see the -section entitled ``The Global PRNG'' for more details). - -\noindent -\type{EGD\_EntropySource}: Query an EGD socket. If the macro -\macro{BOTAN\_EXT\_ENTROPY\_SRC\_EGD} is defined, it can be found in -\filename{es\_egd.h}. The constructor takes a \type{std::vector<std::string>} -that specifies the paths to look for an EGD socket. - -\noindent -\type{Unix\_EntropySource}: This entropy source executes programs common on -Unix systems (such as \filename{uptime}, \filename{vmstat}, and \filename{df}) -and adds it to a buffer. It's quite slow due to process overhead, and (roughly) -1 bit of real entropy is in each byte that is output. It is declared in -\filename{es\_unix.h}, if \macro{BOTAN\_EXT\_ENTROPY\_SRC\_UNIX} is -defined. If you don't have \filename{/dev/urandom} \emph{or} EGD, this is -probably the thing to use. For a long-running process on Unix, keep on object -of this type around and run fast polls ever few minutes. - -\noindent -\type{FTW\_EntropySource}: Walk through a filesystem (the root to start -searching is passed as a string to the constructor), reading files. This tends -to only be useful on things like \filename{/proc} that have a great deal of -variability over time, and even then there is only a small amount of entropy -gathered: about 1 bit of entropy for every 16 bits of output (and many hundreds -of bits are read in order to get that 16 bits). It is declared in -\filename{es\_ftw.h}, if \macro{BOTAN\_EXT\_ENTROPY\_SRC\_FTW} is defined. Only -use this as a last resort. I don't really trust it, and neither should you. - -\noindent -\type{Win32\_CAPI\_EntropySource}: This routines gathers entropy from -a Win32 CAPI module. It takes an optional \type{std::string} that will -specify what type of CAPI provider to use. The CAPI RNG is usually a -default software-based PRNG, but there are a few providers that may -use a hardware RNG. By default it will use the first provider listed -in the option ``rng/ms\_capi\_prov\_type'' that is available on the -machine (currently the providers ``RSA\_FULL'', ``INTEL\_SEC'', -``FORTEZZA'', and ``RNG'' are recognized). - -\noindent -\type{BeOS\_EntropySource}: Query system statistics using various BeOS-specific -APIs. - -\noindent -\type{Pthread\_EntropySource}: Attempt to gather entropy based on jitter -between a number of threads competing for a single mutex. This entropy source -is \emph{very} slow, and highly questionable in terms of security. However, it -provides a worst-case fallback on systems that don't have Unix-like features, -but do support POSIX threads. This module is currently unavailable due to -problems on some systems. - -\subsection{Compressors} - -There are two compression algorithms supported by Botan, Zlib and Bzip2 (Gzip -and Zip encoding will be supported in future releases). Only lossless -compression algorithms are currently supported by Botan, because they tend to -be the most useful for cryptography. However, it is very reasonable to consider -supporting something like GSM speech encoding (which is lossy), for use in -encrypted voice applications. - -You should always compress \emph{before} you encrypt, because encryption seeks -to hide the redundancy that compression is supposed to try to find and remove. - -\subsubsection{Bzip2} - -To test for Bzip2, check to see if \macro{BOTAN\_EXT\_COMPRESSOR\_BZIP2} is -defined. If so, you can include \filename{bzip2.h}, which will declare a pair -of \type{Filter} objects: \type{Bzip2\_Compression} and -\type{Bzip2\_Decompression}. - -You should be prepared to take an exception when using the decompressing -filter, for if the input is not valid Bzip2 data, that is what you will -receive. You can specify the desired level of compression to -\type{Bzip2\_Compression}'s constructor as an integer between 1 and 9, 1 -meaning worst compression, and 9 meaning the best. The default is to use 9, -since small values take the same amount of time, just use a little less memory. - -The Bzip2 module was contributed by Peter J. Jones. - -\subsubsection{Zlib} - -Zlib compression works much like Bzip2 compression. The only -differences in this case are that the macro is -\macro{BOTAN\_EXT\_COMPRESSOR\_ZLIB}, the header you need to include -is called \filename{botan/zlib.h} (remember that you shouldn't just -\verb|#include <zlib.h>|, or you'll get the regular zlib API, which is -not what you want). The Botan classes for Zlib -compression/decompression are called \type{Zlib\_Compression} and -\type{Zlib\_Decompression}. - -Like Bzip2, a \type{Zlib\_Decompression} object will throw an exception if -invalid (in the sense of not being in the Zlib format) data is passed into it. - -In the case of zlib's algorithm, a worse compression level will be faster than -a very high compression ratio. For this reason, the Zlib compressor will -default to using a compression level of 6. This tends to give a good trade off -in terms of time spent to compression achieved. There are several factors you -need to consider in order to decide if you should use a higher compression -level: - -\begin{list}{$\cdot$} - \item Better security: the less redundancy in the source text, the harder it - is to attack your ciphertext. This is not too much of a concern, - because with decent algorithms using sufficiently long keys, it doesn't - really matter \emph{that} much (but it certainly can't hurt). - \item - - \item Decreasing returns. Some simple experiments by the author showed - minimal decreases in the size between level 6 and level 9 compression - with large (1 to 3 megabyte) files. There was some difference, but it - wasn't that much. - - \item CPU time. Level 9 zlib compression is often two to four times as slow - as level 6 compression. This can make a substantial difference in the - overall runtime of a program. -\end{list} - -While the zlib compression library uses the same compression algorithm as the -gzip and zip programs, the format is different. The zlib format is defined in -RFC 1950. - -\subsubsection{Data Sources} - -A \type{DataSource} is a simple abstraction for a thing that stores bytes. This -type is used heavily in the areas of the API related to ASN.1 -encoding/decoding. The following types are \type{DataSource}s: \type{Pipe}, -\type{SecureQueue}, and a couple of special purpose ones: -\type{DataSource\_Memory} and \type{DataSource\_Stream}. - -You can create a \type{DataSource\_Memory} with an array of bytes and a length -field. The object will make a copy of the data, so you don't have to worry -about keeping that memory allocated. This is mostly for internal use, but if it -comes in handy, feel free to use it. - -A \type{DataSource\_Stream} is probably more useful than the memory based -one. Its constructors take either a \type{std::istream} or a -\type{std::string}. If it's a stream, the data source will use the -\type{istream} to satisfy read requests (this is particularly useful to use -with \type{std::cin}). If the string version is used, it will attempt to open -up a file with that name and read from it. - -\subsubsection{Data Sinks} - -A \type{DataSink} (in \filename{data\_snk.h}) is a \type{Filter} that -takes arbitrary amounts of input, and produces no output. This means -it's doing something with the data outside the realm of what -\type{Filter}/\type{Pipe} can handle, for example, writing it to a -file (which is what the \type{DataSink\_Stream} does). There is no -need for \type{DataSink}s that write to a \type{std::string} or memory -buffer, because \type{Pipe} can handle that by itself. - -Here's a quick example of using a \type{DataSink}, which encrypts -\filename{in.txt} and sends the output to \filename{out.txt}. There is -no explicit output operation; the writing of \filename{out.txt} is -implicit. - -\begin{verbatim} - DataSource_Stream in("in.txt"); - Pipe pipe(new CBC_Encryption("Blowfish", "PKCS7", key, iv), - new DataSink_Stream("out.txt")); - pipe.process_msg(in); -\end{verbatim} - -A real advantage of this is that even if ``in.txt'' is large, only as -much memory is needed for internal I/O buffers will be used. - -\section{Miscellaneous} - -This section has documentation for anything that just didn't fit into -any of the major categories. Many of them (Timers, Allocators) will -rarely be used in actual application code, but others, like the PBKDF -algorithms, have a wide degree of applicability. - -\subsection{PBKDF Algorithms} - -There are various procedures (usually ad-hoc) for turning a -passphrase into a (mostly) arbitrary length key for a symmetric -cipher. A general interface for such algorithms is presented in -\filename{pbkdf.h}. The main function is \function{derive\_key}, which -takes a passphrase, a salt, an iteration count, and the desired length -of the output key, and returns a key of that length, deterministically -produced from the passphrase and salt. If an algorithm can't produce a -key of that size, it will throw an exception (most notably, PKCS \#5's -PBKDF1 can only produce strings between 1 and $n$ bytes, where $n$ is -the output size of the underlying hash function). - -The purpose of the iteration count is to make the algorithm take -longer to compute the final key (reducing the speed of brute-force -attacks of various kinds). Most standards recommend an iteration count -of at least 10000. Currently defined PBKDF algorithms are -``PBKDF1(digest)'', ``PBKDF2(digest)'', and ``OpenPGP-S2K(digest)''; -you can retrieve any of these using the \function{get\_pbkdf}, found in -\filename{lookup.h}. As of this writing, ``PBKDF2(SHA-256)'' with -10000 iterations and a 16 byte salt is recommend for new applications. - -\subsubsection{OpenPGP S2K} - -There are some oddities about OpenPGP's S2K algorithms that are -documented here. For one thing, it uses the iteration count in a -strange manner; instead of specifying how many times to iterate the -hash, it tells how many \emph{bytes} should be hashed in total -(including the salt). So the exact iteration count will depend on the -size of the salt (which is fixed at 8 bytes by the OpenPGP standard, -though the implementation will allow any salt size) and the size of -the passphrase. - -To get what OpenPGP calls ``Simple S2K'', set iterations to 0, and do -not specify a salt. To get ``Salted S2K'', again leave the iteration -count at 0, but give an 8-byte salt. ``Salted and Iterated S2K'' -requires an 8-byte salt and some iteration count (this should be -significantly larger than the size of the longest passphrase that -might reasonably be used; somewhere from 1024 to 65536 would probably -be about right). Using both a reasonably sized salt and a large -iteration count is highly recommended to prevent password guessing -attempts. - -\subsection{Password Hashing} - -Storing passwords for user authentication purposes in plaintext is the -simplest but least secure method; when an attacker compromises the -database in which the passwords are stored, they immediately gain -access to all of them. Often passwords are reused among multiple -services or machines, meaning once a password to a single service is -known an attacker has a substantial head start on attacking other -machines. - -The general approach is to store, instead of the password, the output -of a one way function of the password. Upon receiving an -authentication request, the authenticator can recompute the one way -function and compare the value just computed with the one that was -stored. If they match, then the authentication request succeeds. But -when an attacker gains access to the database, they only have the -output of the one way function, not the original password. - -Common hash functions such as SHA-256 are one way, but used alone they -have problems for this purpose. What an attacker can do, upon gaining -access to such a stored password database, is hash common dictionary -words and other possible passwords, storing them in a list. Then he -can search through his list; if a stored hash and an entry in his list -match, then he has found the password. Even worse, this can happen -\emph{offline}: an attacker can begin hashing common passwords days, -months, or years before ever gaining access to the database. In -addition, if two users choose the same password, the one way function -output will be the same for both of them, which will be visible upon -inspection of the database. - -There are two solutions to these problems: salting and -iteration. Salting refers to including, along with the password, a -randomly chosen value which perturbs the one way function. Salting can -reduce the effectivness of offline dictionary generation (because for -each potential password, an attacker would have to compute the one way -function output for all possible salts - with a large enough salt, -this can make the problem quite difficult). It also prevents the same -password from producing the same output, as long as the salts do not -collide. With a large salt (say 80 to 128 bits) this will be quite -unlikely. Iteration refers to the general technique of forcing -multiple one way function evaluations when computing the output, to -slow down the operation. For instance if hashing a single password -requires running SHA-256 100,000 times instead of just once, that will -slow down user authentication by a factor of 100,000, but user -authentication happens quite rarely, and usually there are more -expensive operations that need to occur anyway (network and database -I/O, etc). On the other hand, an attacker who is attempting to break a -database full of stolen password hashes will be seriously -inconvenienced by a factor of 100,000 slowdown; they will be able to -only test at a rate of .0001\% of what they would without iterations -(or, equivalently, will require 100,000 times as many zombie botnet -hosts). - -There are many different ways of doing this password hashing -operation, with common ones including Unix's crypt (which is based on -DES) and OpenBSD's bcrypt (based on Blowfish). Other variants using -MD5 or SHA-256 are also in use on various systems. - -Botan provides a technique called passhash9, in -\filename{passhash9.h}, which is based on PBKDF2. Two functions are -provided in this header, \function{generate\_passhash9} and -\function{check\_passhash9}. The generate function takes the password -to hash, a \type{RandomNumberGenerator}, and a work factor, which -tells how many iterations to compute. The default work factor is 10 -(which means 100,000 iterations), but any non-zero value is accepted. -The check function takes a password and a passhash9 output and checks -if the password is the same as the one that was used to generate the -passhash9 output, returning a boolean true (same) or false (not same). -An example can be found in \filename{doc/examples/passhash.cpp}. - -Passhash9 currently uses HMAC(SHA-1) for the underlying PBKDF2 -psuedo-random function, but can be extended to use different -algorithms in the future if necessary. For instance using a PRF based -on Blowfish (a block cipher that requires 4 KiB of RAM for efficient -execution) could be used to make hardware-based password cracking more -expensive (this was one motivation for Blowfish's use in the bcrypt -hashing scheme, in fact). - -\subsection{Checksums} - -Checksums are very similar to hash functions, and in fact share the same -interface. But there are some significant differences, the major ones being -that the output size is very small (usually in the range of 2 to 4 bytes), and -is not cryptographically secure. But for their intended purpose (error -checking), they perform very well. Some examples of checksums included in Botan -are the Adler32 and CRC32 checksums. - -\subsection{Exceptions} - -Sooner or later, something is going to go wrong. Botan's behavior when -something unusual occurs, like most C++ software, is to throw an exception. -Exceptions in Botan are derived from the \type{Exception} class. You can see -most of the major varieties of exceptions used in Botan by looking at -\filename{exceptn.h}. The only function you really need to concern yourself -with is \type{const char*} \function{what()}. This will return an error message -relevant to the error that occurred. For example: - -\begin{verbatim} -try { - // various Botan operations - } -catch(Botan::Exception& e) - { - cout << "Botan exception caught: " << e.what() << endl; - // error handling, or just abort - } -\end{verbatim} - -Botan's exceptions are derived from \type{std::exception}, so you don't need -to explicitly check for Botan exceptions if you're already catching the ISO -standard ones. - -\subsection{Threads and Mutexes} - -Botan includes a mutex system, which is used internally to lock some shared -data structures that must be kept shared for efficiency reasons (mostly, these -are in the allocation systems~--~handing out 1000 separate allocators hurts -performance and makes caching memory blocks useless). This system is supported -by the \texttt{mux\_pthr} module, implementing the \type{Mutex} interface for -systems that have POSIX threads. - -If your application is using threads, you \emph{must} add the option -``thread\_safe'' to the options string when you create the -\type{LibraryInitializer} object. If you specify this option and no mutex type -is available, an exception is thrown, since otherwise you would probably be -facing a nasty crash. - -\subsection{Secure Memory} - -A major concern with mixing modern multiuser OSes and cryptographic -code is that at any time the code (including secret keys) could be -swapped to disk, where it can later be read by an attacker. Botan -stores almost everything (and especially anything sensitive) in memory -buffers that a) clear out their contents when their destructors are -called, and b) have easy plugins for various memory locking functions, -such as the \function{mlock}(2) call on many Unix systems. - -Two of the allocation method used (``malloc'' and ``mmap'') don't -require any extra privileges on Unix, but locking memory does. At -startup, each allocator type will attempt to allocate a few blocks -(typically totaling 128k), so if you want, you can run your -application \texttt{setuid} \texttt{root}, and then drop privileges -immediately after creating your \type{LibraryInitializer}. If you end -up using more than what's been allocated, some of your sensitive data -might end up being swappable, but that beats running as \texttt{root} -all the time. - -These classes should also be used within your own code for storing -sensitive data. They are only meant for primitive data types (int, -long, etc): if you want a container of higher level Botan objects, you -can just use a \verb|std::vector|, since these objects know how to -clear themselves when they are destroyed. You cannot, however, have a -\verb|std::vector| (or any other container) of \type{Pipe}s or -\type{Filter}s, because these types have pointers to other -\type{Filter}s, and implementing copy constructors for these types -would be both hard and quite expensive (vectors of pointers to such -objects is fine, though). - -These types are not described in any great detail: for more information, -consult the definitive sources~--~the header files \filename{secmem.h} and -\filename{allocate.h}. - -\type{SecureBuffer} is a simple array type, whose size is specified at compile -time. It will automatically convert to a pointer of the appropriate type, and -has a number of useful functions, including \function{clear()}, and -\type{u32bit} \function{size()}, which returns the length of the array. It is a -template that takes as parameters a type, and a constant integer which is how -long the array is (for example: \verb|SecureBuffer<byte, 8> key;|). - -\type{SecureVector} is a variable length array. Its size can be increased or -decreased as need be, and it has a wide variety of functions useful for copying -data into its buffer. Like \type{SecureBuffer}, it implements \function{clear} -and \function{size}. - -\subsection{Allocators} - -The containers described above get their memory from allocators. As a -user of the library, you can add new allocator methods at run time for -containers, including the ones used internally by the library, to -use. The interface to this is in \filename{allocate.h}. Code needing -to allocate or deallocate memory calls \function{get\_allocator}, -which returns a pointer to an allocator object. This pointer should -not be freed: the caller does not own the allocator (it is shared -among multiple allocatore users, and uses a mutex to serialize access -internally if necessary). It is possible to call -\function{get\_allocator} with a specific name to request a particular -type of allocator, otherwise, a default allocator type is returned. - -At start time, the only allocator known is a \type{Default\_Allocator}, which -just allocates memory using \function{malloc}, and \function{memset}s it to 0 -when the memory is released. It is known by the name ``malloc''. If you ask for -another type of allocator (``locking'' and ``mmap'' are currently used), and it -is not available, some other allocator will be returned. - -You can add in a new allocator type using \function{add\_allocator\_type}. This -function takes a string and a pointer to an allocator. The string gives this -allocator type a name to which it can be referred when one is requesting it -with \function{get\_allocator}. If an error occurs (such as the name being -already registered), this function returns false. It will return true if the -allocator was successfully registered. If you ask it to, -\type{LibraryInitializer} will do this for you. - -Finally, you can set the default allocator type that will be returned using -the policy setting ``default\_alloc'' to the name of any previously registered -allocator. - -\subsection{BigInt} - -\type{BigInt} is Botan's implementation of a multiple-precision -integer. Thanks to C++'s operator overloading features, using \type{BigInt} is -often quite similar to using a native integer type. The number of functions -related to \type{BigInt} is quite large. You can find most of them in -\filename{bigint.h} and \filename{numthry.h}. - -Due to the sheer number of functions involved, only a few, which a regular user -of the library might have to deal with, are mentioned here. Fully documenting -the MPI library would take a significant while, so if you need to use it now, -the best way to learn is to look at the headers. - -Probably the most important are the encoding/decoding functions, which -transform the normal representation of a \type{BigInt} into some other form, -such as a decimal string. - -\type{SecureVector<byte>} \function{BigInt::encode}(\type{BigInt}, -\type{Encoding}) - -\noindent -and - -\type{BigInt} \function{BigInt::decode}(\type{SecureVector<byte>}, -\type{Encoding}) - -\type{Encoding} is an enum that has values \type{Binary}, \type{Octal}, -\type{Decimal}, and \type{Hexadecimal}. The parameter will default to -\type{Binary}. These functions are static member functions, so they would be -called like this: - -\begin{verbatim} - BigInt n1; // some number - SecureVector<byte> n1_encoded = BigInt::encode(n1); - BigInt n2 = BigInt::decode(n1_encoded); - // now n1 == n2 -\end{verbatim} - -There are also C++-style I/O operators defined for use with \type{BigInt}. The -input operator understands negative numbers, hexadecimal numbers (marked with a -leading ``0x''), and octal numbers (marked with a leading '0'). The '-' must -come before the ``0x'' or '0' marker. The output operator will never adorn the -output; for example, when printing a hexadecimal number, there will not be a -leading ``0x'' (though a leading '-' will be printed if the number is -negative). If you want such things, you'll have to do them yourself. - -\type{BigInt} has constructors that can create a \type{BigInt} from an unsigned -integer or a string. You can also decode a \type{byte}[] / length pair into a -BigInt. There are several other \type{BigInt} constructors, which I would -seriously recommend you avoid, as they are only intended for use internally by -the library, and may arbitrarily change, or be removed, in a future release. - -An random sampling of \type{BigInt} related functions: - -\type{u32bit} \function{BigInt::bytes}(): Return the size of this \type{BigInt} -in bytes. - -\type{BigInt} \function{random\_prime(\type{u32bit} \arg{b})}: Return a prime -number \arg{b} bits long. - -\type{BigInt} \function{gcd}(\type{BigInt} \arg{x}, \type{BigInt} \arg{y}): -Returns the greatest common divisor of \arg{x} and \arg{y}. Uses the binary -GCD algorithm. - -\type{bool} \function{is\_prime}(\type{BigInt} \arg{x}): Returns true if -\arg{x} is a (possible) prime number. Uses the Miller-Rabin probabilistic -primality test with fixed bases. For higher assurance, use -\function{verify\_prime}, which uses more rounds and randomized 48-bit bases. - -\subsubsection{Efficiency Hints} - -If you can, always use expressions of the form \verb|a += b| over -\verb|a = a + b|. The difference can be \emph{very} substantial, -because the first form prevents at least one needless memory -allocation, and possibly as many as three. - -If you're doing repeated modular exponentiations with the same modulus, create -a \type{BarrettReducer} ahead of time. If the exponent or base is a constant, -use the classes in \filename{mod\_exp.h}. This stuff is all handled for you by -the normal high-level interfaces, of course. - -Never use the low-level MPI functions (those that begin with -\texttt{bigint\_}). These are completely internal to the library, and -may make arbitrarily strange and undocumented assumptions about their -inputs, and don't check to see if they are true, on the assumption -that only the library itself calls them, and that the library knows -what the assumptions are. The interfaces for these functions can -change completely without notice. - -\section{Algorithms} - -\subsection{Recommended Algorithms} - -This section is by no means the last word on selecting which -algorithms to use. However, Botan includes a sometimes bewildering -array of possible algorithms, and unless you're familiar with the -latest developments in the field, it can be hard to know what is -secure and what is not. The following attributes of the algorithms -were evaluated when making this list: security, standardization, -patent status, support by other implementations, and efficiency (in -roughly that order). - -It is intended as a set of simple guidelines for developers, and -nothing more. It's entirely possible that there are algorithms in -Botan that will turn out to be more secure than the ones listed, but -the algorithms listed here are (currently) thought to be safe. - -\begin{list}{$\cdot$} - \item Block ciphers: AES or Serpent in CBC, CTR, or XTS mode - - \item Hash functions: SHA-256, SHA-512 - - \item MACs: HMAC with any recommended hash function - - \item Public Key Encryption: RSA with ``EME1(SHA-256)'' - - \item Public Key Signatures: RSA with EMSA4 and any recommended - hash, or DSA or ECDSA with ``EMSA1(SHA-256)'' - - \item Key Agreement: Diffie-Hellman or ECDH, with ``KDF2(SHA-256)'' -\end{list} - -\subsection{Algorithms Listing} - -Botan includes a very sizable number of cryptographic algorithms. In -nearly all cases, you never need to know the header file or type name -to use them. However, you do need to know what string (or strings) are -used to identify that algorithm. These names conform to those set out -by SCAN (Standard Cryptographic Algorithm Naming), which is a document -that specifies how strings are mapped onto algorithm objects, which is -useful for a wide variety of crypto APIs (SCAN is oriented towards -Java, but Botan and several other non-Java libraries also make at -least some use of it). For full details, read the SCAN document, which -can be found at -\url{http://www.users.zetnet.co.uk/hopwood/crypto/scan/} - -Many of these algorithms can take options (such as the number of -rounds in a block cipher, the output size of a hash function, -etc). These are shown in the following list; all of them default to -reasonable values. There are algorithm-specific limits on most of -them. When you see something like ``HASH'' or ``BLOCK'', that means -you should insert the name of some algorithm of that type. There are -no defaults for those options. - -A few very obscure algorithms are skipped; if you need one of them, -you'll know it, and you can look in the appropriate header to see what -that classes' \function{name} function returns (the names tend to -match that in SCAN, if it's defined there). - -\begin{list}{$\cdot$} - \item ROUNDS: The number of rounds in a block cipher. - \item - \item OUTSZ: The output size of a hash function or MAC -\end{list} - -\vskip .05in -\noindent -\textbf{Block Ciphers:} ``AES'' (and ``AES-128'', ``AES-192'', and -``AES-256''), ``Blowfish'', ``CAST-128'', ``CAST-256'', ``DES'', -``DESX'', ``TripleDES'', ``GOST-28147-89'', ``IDEA'', ``KASUMI'', -``MARS'', ``MISTY1(ROUNDS)'', ``Noekeon'', ``RC2'', ``RC5(ROUNDS)'', -``RC6'', ``SAFER-SK(ROUNDS)'', ``SEED'', ``Serpent'', ``Skipjack'', -``Square'', ``TEA'', ``Twofish'', ``XTEA'' - -\noindent -\textbf{Stream Ciphers:} ``ARC4'', ``MARK4'', ``Salsa20'', ``Turing'', -``WiderWake4+1-BE'' - -\noindent -\textbf{Hash Functions:} ``HAS-160'', ``GOST-34.11'', -``MD2'', ``MD4'', ``MD5'', ``RIPEMD-128'', ``RIPEMD-160'', -``SHA-160'', ``SHA-256'', ``SHA-384'', ``SHA-512'', ``Skein-512'', -``Tiger(OUTSZ)'', ``Whirlpool'' - -\noindent -\textbf{MACs:} ``HMAC(HASH)'', ``CMAC(BLOCK)'', ``X9.19-MAC'' - -\section{Support and Further Information} - -\subsection{Patents} - -Some of the algorithms implemented by Botan may be covered by patents in some -locations. Algorithms known to have patent claims on them in the United States -and that are not available in a license-free/royalty-free manner include: -IDEA, MISTY1, RC5, RC6, and Nyberg-Rueppel. - -You must not assume that, just because an algorithm is not listed here, it is -not encumbered by patents. If you have any concerns about the patent status of -any algorithm you are considering using in an application, please discuss it -with your attorney. - -\subsection{Support} - -Questions or problems you have with Botan can be directed to the -development mailing list. Joining this list is highly recommended if -you're going to be using Botan, since often advance notice of upcoming -changes is sent there. ``Philosophical'' bug reports, announcements of -programs using Botan, and anything else having to do with Botan are -also welcome. - -The lists can be found at -\url{http://lists.randombit.net/mailman/listinfo/}. - -\subsection{Contact Information} - -A PGP key with a fingerprint of -\verb|621D AF64 11E1 851C 4CF9 A2E1 6211 EBF1 EFBA DFBC| is used to sign all -Botan releases. This key can be found in the file \filename{doc/pgpkeys.asc}; -PGP keys for the developers are also stored there. - -\vskip 5pt \noindent -Web Site: \url{http://botan.randombit.net} - -\subsection{License} - -Copyright \copyright 2000-2010, Jack Lloyd - -Licensed under the same terms as the Botan source - -\end{document} diff --git a/doc/architecture.pdf b/doc/architecture.pdf Binary files differdeleted file mode 100644 index f0edc3fc1..000000000 --- a/doc/architecture.pdf +++ /dev/null diff --git a/doc/bigint.txt b/doc/bigint.txt new file mode 100644 index 000000000..7eb884039 --- /dev/null +++ b/doc/bigint.txt @@ -0,0 +1,104 @@ +BigInt +======================================== + +``BigInt`` is Botan's implementation of a multiple-precision +integer. Thanks to C++'s operator overloading features, using +``BigInt`` is often quite similar to using a native integer type. The +number of functions related to ``BigInt`` is quite large. You can find +most of them in ``botan/bigint.h`` and ``botan/numthry.h``. + +.. note:: + + If you can, always use expressions of the form ``a += b`` over ``a = + a + b``. The difference can be *very* substantial, because the first + form prevents at least one needless memory allocation, and possibly + as many as three. This will be less of an issue once the library + adopts use of C++0x's rvalue references. + +Encoding Functions +---------------------------------------- + +These transform the normal representation of a ``BigInt`` into some +other form, such as a decimal string: + +.. cpp:function:: SecureVector<byte> BigInt::encode(const BigInt& n, Encoding enc = Binary) + + This function encodes the BigInt n into a memory + vector. ``Encoding`` is an enum that has values ``Binary``, + ``Octal``, ``Decimal``, and ``Hexadecimal``. + +.. cpp:function:: BigInt BigInt::decode(const MemoryRegion<byte>& vec, Encoding enc) + + Decode the integer from ``vec`` using the encoding specified. + +These functions are static member functions, so they would be called +like this:: + + BigInt n1 = ...; // some number + SecureVector<byte> n1_encoded = BigInt::encode(n1); + BigInt n2 = BigInt::decode(n1_encoded); + assert(n1 == n2); + +There are also C++-style I/O operators defined for use with +``BigInt``. The input operator understands negative numbers, +hexadecimal numbers (marked with a leading "0x"), and octal numbers +(marked with a leading '0'). The '-' must come before the "0x" or '0' +marker. The output operator will never adorn the output; for example, +when printing a hexadecimal number, there will not be a leading "0x" +(though a leading '-' will be printed if the number is negative). If +you want such things, you'll have to do them yourself. + +``BigInt`` has constructors that can create a ``BigInt`` from an +unsigned integer or a string. You can also decode an array (a ``byte`` +pointer plus a length) into a ``BigInt`` using a constructor. + +Number Theory +---------------------------------------- + +Number theoretic functions available include: + +.. cpp:function:: BigInt gcd(BigInt x, BigInt y) + + Returns the greatest common divisor of x and y + +.. cpp:function:: BigInt lcm(BigInt x, BigInt y) + + Returns an integer z which is the smallest integer such that z % x + == 0 and z % y == 0 + +.. cpp:function:: BigInt inverse_mod(BigInt x, BigInt m) + + Returns the modular inverse of x modulo m, that is, an integer + y such that (x*y) % m == 1. If no such y exists, returns zero. + +.. cpp:function:: BigInt power_mod(BigInt b, BigInt x, BigInt m) + + Returns b to the xth power modulo m. If you are doing many + exponentiations with a single fixed modulus, it is faster to use a + ``Power_Mod`` implementation. + +.. cpp:function:: BigInt ressol(BigInt x, BigInt p) + + Returns the square root modulo a prime, that is, returns a number y + such that (y*y) % p == x. Returns -1 if no such integer exists. + +.. cpp:function:: bool quick_check_prime(BigInt n, RandomNumberGenerator& rng) + +.. cpp:function:: bool check_prime(BigInt n, RandomNumberGenerator& rng) + +.. cpp:function:: bool verify_prime(BigInt n, RandomNumberGenerator& rng) + + Three variations on primality testing. All take an integer to test along with + a random number generator, and return true if the integer seems like it might + be prime; there is a chance that this function will return true even with + a composite number. The probability decreases with the amount of work performed, + so it is much less likely that ``verify_prime`` will return a false positive + than ``check_prime`` will. + +.. cpp:function BigInt random_prime(RandomNumberGenerator& rng, \ + size_t bits, BigInt coprime = 1, size_t equiv = 1, size_t equiv_mod = 2) + + Return a random prime number of ``bits`` bits long that is + relatively prime to ``coprime``, and equivalent to ``equiv`` modulo + ``equiv_mod``. + diff --git a/doc/build_log.txt b/doc/build_log.txt new file mode 100644 index 000000000..2e92a6f90 --- /dev/null +++ b/doc/build_log.txt @@ -0,0 +1,231 @@ + +Build Log +======================================== + +To report build results (successful or not), email the `development +list <http://lists.randombit.net/mailman/listinfo/botan-devel/>`_ your +results and relevant system information (OS versions, compiler name +and version, CPU architecture and other hardware information, +configuration settings). + +Debian reports the build results for 1.8 on `a number of platforms +<http://buildd.debian.org/pkg.cgi?pkg=botan1.8>`_. + +=========== ======= =================== ======================== ============================ ======== +Date Version OS CPU Compiler Results +=========== ======= =================== ======================== ============================ ======== +2011-05-09 1.9.17 Debian 6.0 Intel Atom D510 GCC 4.4.5 OK +2010-05-09 1.9.17 Gentoo 10.0 PowerPC G5 GCC 4.4.5 OK +2011-05-02 1.9.17 FreeBSD 8.2 x86-64 GCC 4.2.1 OK +2011-04-25 1.9.16 Gentoo 10.0 Intel Core i7-860 Clang 2.9 Miscompiles SSE2 IDEA +2011-04-23 1.9.16 Gentoo 10.0 Intel Core i7-860 Sun C++ 5.10 OK +2011-04-22 1.9.16 Gentoo 10.0 Intel Core i7-860 Intel C++ 11.1 OK +2011-04-15 1.9.16 Haiku R1-alpha2 x86 GCC 4.3.3 OK +2011-04-15 1.9.16 Haiku R1-alpha2 x86 GCC 2.95.3 Can't compile +2011-04-15 1.9.16 Windows 7 x86-64 Visual C++ 16.00.30319.01 OK +2011-04-15 1.9.16 QNX 6.4.1 i386 GCC 4.3.3 OK +2011-03-29 1.9.15 Gentoo 10.0 Intel Core i5-520M GCC 4.5.2 OK +2011-03-21 1.9.15 Ark Linux x86-64 GCC 4.6.0-pre OK +2011-03-21 1.9.15 Ark Linux x86-32 GCC 4.6.0-pre OK +2011-03-21 1.9.15 Ark Linux ARM GCC 4.6.0-pre OK +2011-03-18 1.9.14 Debian 6.0 Intel Atom D510 GCC 4.4.5 OK +2011-03-01 1.9.14 OpenBSD 4.6 UltraSPARC IIIi GCC 4.2.4 OK +2011-03-01 1.9.14 OpenBSD 4.7 i386 GCC 4.2.4 OK +2011-03-01 1.9.14 Debian 6.0 Intel Madison IA-64 GCC 4.4.5 OK +2011-03-01 1.9.14 Ubuntu 9.10 ARM Cortex-A8 GCC 4.4.1 OK +2011-03-01 1.9.14 Debian 5.0 PowerPC G5/970 GCC 4.3.2 OK +2011-03-01 1.9.14 Windows 7 x64 Intel Core i5-520M Visual C++ 15.00.30729.01 OK (32/64) +2011-03-01 1.9.14 Gentoo 10.0 Intel Core i7-860 Open64 4.2.1 OK +2011-03-01 1.9.14 Gentoo 10.0 Intel Core i7-860 Sun C++ 5.10 OK +2011-03-01 1.9.14 Gentoo 10.0 Intel Core i7-860 Intel C++ 11.1 OK +2011-03-01 1.9.14 Gentoo 10.0 Intel Core i7-860 GCC 4.5.2 OK +2011-02-14 1.9.13 NetBSD 5.1 Intel Xeon P4 GNU GCC 4.1.3 OK +2011-01-14 1.9.12 FreeBSD 8.1 x86-64 Clang 2.9 OK +2010-11-29 1.9.11 Windows 7 x64 Intel Core i5-520M Visual C++ 15.00.30729.01 OK (32/64) +2010-11-29 1.9.11 Gentoo 10.0 Intel Core i7-860 GNU GCC 4.1.2, 4.4.5, 4.5.1 OK +2010-11-29 1.9.11 Debian 5.0 PowerPC G5/970 GCC 4.3.2 OK +2010-11-29 1.9.11 Gentoo 10.0 Intel Core i7-860 Intel C++ 11.1 OK +2010-11-29 1.9.11 Gentoo 10.0 Intel Core i7-860 Clang 2.8 Miscompiles SSE2 IDEA +2010-11-29 1.9.11 Debian 5.0 (32 bit) UltraSPARC T1 Niagra GCC 4.3.2 OK +2010-09-07 1.9.11 Gentoo 10.0 Intel Core i7-860 Sun C++ 5.10 OK +2010-08-12 1.9.10 Debian 5.0 Xeon X5450 Harpertown GCC 4.3.2 OK +2010-08-12 1.9.10 Ubuntu 9.04 Intel Atom N270 GCC 4.3.3 OK +2010-08-12 1.9.10 Debian 5.0 Intel Prescott GCC 4.3.2 OK +2010-08-08 1.9.10 Gentoo 10.0 Intel Core i7-860 GCC 3.4.6 OK +2010-08-08 1.9.10 Gentoo 10.0 Intel Core i7-860 GCC 4.1.2 OK +2010-08-08 1.9.10 Gentoo 10.0 Intel Core i7-860 GCC 4.3.5 OK +2010-08-08 1.9.10 Gentoo 10.0 Intel Core i7-860 GCC 4.4.4 OK +2010-08-08 1.9.10 Gentoo 10.0 Intel Core i7-860 GCC 4.5.1 OK +2010-08-08 1.9.10 Gentoo 10.0 Intel Core i7-860 Clang SVN Miscompiles Turing +2010-07-27 1.9.9 Debian 5.0 AMD Magny-Cours GCC 4.3.2, 4.5.0 OK +2010-06-16 1.9.8 Gentoo 10.0 Intel Core2 Q6600 Intel C++ 11.1 OK +2010-06-16 1.9.8 Debian 5.0 (32 bit) UltraSPARC T1 Niagra GCC 4.3.2 OK +2010-06-16 1.9.8 Debian 5.0 Intel Madison IA-64 GCC 4.3.2 OK +2010-06-16 1.9.8 Gentoo 10.0 IBM POWER5+ GCC 4.1.2, 4.2.4, 4.3.2 OK +2010-06-16 1.9.8 OpenBSD 4.6 UltraSPARC IIIi GCC 3.3.5, 4.2.4 OK +2010-06-16 1.9.8 FreeBSD 8.0 AMD Opteron 252 GCC 4.2.1 OK +2010-06-16 1.9.8 gNewSense MIPS Loongson-2 (64) GCC 4.3.2 OK +2010-06-16 1.9.8 Ubuntu 9.10 ARM Cortex-A8 GCC 4.4.1 OK +2010-06-11 1.9.8 Gentoo 10.0 Intel Core2 Q6600 GCC 3.4.6, 4.1.2 OK +2010-06-11 1.9.8 Windows 7 x64 Intel Core i5-520M Visual C++ 15.00.30729.01 OK (32 and 64 bit) +2010-06-11 1.9.8 Gentoo 10.0 Intel Core i5-520M GCC 4.5.0 OK +2010-06-01 1.9.8 OpenBSD 4.7 i386 GCC 3.3.5 OK +2010-05-03 1.9.7 Windows 7 x64 Intel Core i5-520M Visual C++ 15.00.30729.01 OK +2010-04-27 1.9.7 Gentoo 10.0 PPC 970FX (G5) GCC 4.3.4 OK +2010-04-27 1.9.7 Gentoo 10.0 Intel Core2 Q6600 GCC 4.4.3, 4.5.0 OK +2010-03-18 1.9.4 Gentoo 10.0 Intel Core2 Q6600 GCC 4.4.3 OK +2010-03-18 1.9.4 Debian 5.0 UltraSPARC II (64) GCC 4.3.2 OK +2010-03-18 1.9.4 Gentoo 10.0 PowerPC G5 GCC 4.3.4 OK +2010-03-18 1.9.4 Gentoo 10.0 IBM POWER5+ GCC 4.3.2 OK +2010-03-15 1.9.4 Windows XP x86 Visual C++ 15.00.30729.01 OK +2010-03-10 1.9.4 FreeBSD 8.0 AMD Opteron 252 GCC 4.2.1 OK, but missing includes +2009-12-29 1.9.4 Debian 4.0 PowerPC G4 7455 GCC 4.1.2 OK +2009-12-23 1.9.4 Debian 5.0 Xeon X5450 Harpertown GCC 4.3.2 OK +2009-11-13 1.9.3 Debian 5.0 UltraSPARC II GCC 4.3.2 OK +2009-11-10 1.9.2 Debian 4.0 PowerPC G4 GCC 4.1.2 OK +2009-11-03 1.9.2 Debian Linux 4.0 AMD Opteron 8354 GCC 4.4.1 OK +2009-10-27 1.9.2 Debian Linux 5.0 Xeon X5450 Harpertown GCC 4.3.2 OK +2009-10-23 1.9.1 Gentoo Linux Intel Core2 Q6600 GCC 4.4.1, Intel C++ 11.1 OK +2009-10-23 1.9.1 Gentoo Linux AMD Opteron 2212 GCC 4.3.4 OK +2009-09-24 1.9.0 Debian 4.0 AMD Opteron 8354 GCC 4.1.2, 4.4.1 OK +2010-07-01 1.8.9 OpenSUSE 10.3 Intel Core2 GCC 4.2.1 OK +2010-06-22 1.8.9 Slackware 13.1 Intel E5400 (64) GCC 4.4.4 OK +2010-06-22 1.8.9 Slackware 13.1 Pentium-M (32) GCC 4.4.4 OK +2010-06-16 1.8.9 Debian 5.0 (32 bit) UltraSPARC T1 Niagra GCC 4.3.2 (GCC TR1) Crashes in GF(p) tests +2010-03-18 1.8.8 Debian 5.0 UltraSPARC II (64) GCC 4.3.2 OK +2008-10-23 1.8.7 Gentoo 2008.0 PPC 970FX (G5) GCC 4.3.4 OK +2009-10-07 1.8.7 Debian GNU/Hurd 0.3 i686 GCC 4.3.4 OK +2009-09-08 1.8.7 Gentoo 2008.0 Intel Core2 Q6600 GCC 4.4.1 OK +2009-09-04 1.8.6 Gentoo 2008.0 PPC 970FX (G5) GCC 4.3.4 OK +2009-08-13 1.8.6 Gentoo 2008.0 Intel Core2 Q6600 GCC 4.3.3 OK +2009-08-13 1.8.6 Windows XP x86 Visual C++ 15.00.30729.01 OK (no TR1) +2009-08-03 1.8.5 openSuSE 10.3 x86 GCC 4.2.1 OK +2009-08-03 1.8.5 Gentoo 2008.0 Intel Core2 Q6600 Open64 4.2.1 BAD: Miscompiles several ciphers +2009-07-31 1.8.5 Solaris 11 x86 Sun C++ 5.9 OK, but minor build problems +2009-07-30 1.8.5 Gentoo 2006.1 UltraSPARC IIe (32) GCC 3.4.6 OK (no TR1) +2009-07-25 1.8.5 Debian 4.0 AMD Opteron 2212 GCC 4.1.2 OK +2009-07-23 1.8.5 Gentoo 2008.0 Marvel Feroceon 88FR131 GCC 4.1.2 OK +2009-07-23 1.8.5 Debian 5.0 Intel Xscale 80219 GCC 4.3.2 OK +2009-07-23 1.8.5 Debian 5.0 UltraSPARC II (64) GCC 4.3.2 OK +2009-07-23 1.8.5 Debian 5.0 UltraSPARC II (32) GCC 4.3.2 BAD: bus error in GF(p) +2009-07-23 1.8.5 Debian 5.0 UltraSPARC II (32) GCC 4.1.3 BAD: miscompiles BigInt code +2009-07-23 1.8.5 Debian 4.0 PowerPC G4 GCC 4.1.2 OK +2009-07-23 1.8.5 Debian 4.0 PowerPC G5 GCC 4.1.2 OK +2009-07-23 1.8.5 Debian 5.0 Intel Madison IA-64 GCC 4.1.3, 4.3.2 OK +2009-07-23 1.8.5 Debian 5.0 HP-PA PA8600 GCC 4.3.2 OK +2009-07-23 1.8.5 Mandriva 2008.1 MIPS Loongson-2 (32) GCC 4.2.3 OK +2009-07-23 1.8.5 gNewSense MIPS Loongson-2 (64) GCC 4.3.2 OK +2009-07-21 1.8.5 Windows XP x86 Visual C++ 15.00.30729.01 OK (no TR1) +2009-07-21 1.8.5 Gentoo 2008.0 Intel Core2 Q6600 GCC 4.1.2, 4.3.3 OK +2009-07-21 1.8.5 Gentoo 2008.0 Intel Core2 Q6600 Intel C++ 10.1 20080801 OK +2009-07-21 1.8.5 Gentoo 2008.0 AMD Opteron 2212 GCC 4.3.3 OK +2009-07-21 1.8.5 Ubuntu 8.04 Intel Xeon X5492 GCC 4.2.4 OK +2009-07-21 1.8.5 MacOS X 10.5.6 Intel Core 2 Duo T5600 GCC 4.0.1 OK +2009-07-21 1.8.5 Solaris 10 AMD Opteron GCC 3.4.3 OK (no TR1) +2008-07-11 1.8.3 Fedora 11 Intel Pentium E5200 GCC 4.4.0 OK +2008-07-10 1.8.3 Gentoo 2008.0 PPC 970FX (G5) GCC 4.3.1 OK +2008-07-10 1.8.3 Gentoo 2008.0 IBM POWER5+ GCC 4.2.2 OK +2009-07-10 1.8.3 Gentoo 2008.0 AMD Opteron 2212 GCC 4.3.3 OK +2009-07-10 1.8.3 Ubuntu 8.04 Intel Xeon X5492 GCC 4.2.4 OK +2009-07-10 1.8.3 MacOS X 10.5.6 Intel Core 2 Duo T5600 GCC 4.0.1 OK +2009-07-10 1.8.3 Debian 5.0.1 Intel Core 2 Duo T5600 GCC 4.3.2 OK +2009-07-10 1.8.3 Fedora 10 Intel Core 2 Duo T5600 GCC 4.3.2 OK +2009-07-10 1.8.3 Solaris 10 AMD Opteron GCC 3.4.3 OK (no TR1) +2009-07-09 1.8.3 Gentoo 2008.0 Intel Core2 Q6600 Intel C++ 10.1 20080801 OK +2009-07-02 1.8.3 Gentoo 2008.0 Intel Core2 Q6600 GCC 4.3.3 OK +2009-07-02 1.8.3 FreeBSD 7.0 x86-64 GCC 4.2.1 OK +2009-07-02 1.8.3 Windows XP x86 Visual C++ 15.00.30729.01 OK (no TR1) +2008-12-27 1.8.0 Ubuntu 8.04 Pentium 4-M GCC 4.2.3 OK +2008-12-14 1.8.0 FreeBSD 7.0 x86-64 GCC 4.2.1 OK +2008-12-10 1.8.0 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.1.2, 4.2.4, 4.3.2 OK +2008-12-05 1.7.24 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.1.2, 4.2.4, 4.3.2 OK +2008-12-04 1.7.24 Gentoo 2007.0 Intel Core2 Q6600 Intel 10.1-20080801 OK +2008-12-03 1.7.24 Solaris 10 x86 GCC 3.4.3 OK (small patch needed, fixed in 1.8.0) +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.1.2 OK +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.2.4 OK +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.3.2 OK +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.4-20081017 OK +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 (32) GCC 4.1.2, 4.2.4 OK +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 (32) GCC 4.3.2 OK (with Boost 1.35 TR1) +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 (32) GCC 4.3.2 Crashes (with libstdc++ TR1) +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 9.1-20061101 OK +2008-11-24 1.7.23 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 10.1-20080801 OK +2008-11-24 1.7.23 Fedora 8 STI Cell PPU GCC 4.1.2 OK +2008-11-24 1.7.23 Fedora 8 STI Cell PPU IBM XLC for Cell 0.9 45 minute link. Miscompiles DES +2008-11-24 1.7.23 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2, 4.2.2, 4.3.1 OK +2008-11-24 1.7.23 Gentoo 2007.0 AMD Opteron 2212 GCC 3.3.6, 4.1.2, 4.3.2 OK (no TR1 with 3.3.6) +2008-11-24 1.7.23 Windows XP x86 Visual C++ 15.00.30729.01 OK (no TR1) +2008-11-09 1.7.20 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2 OK +2008-11-09 1.7.20 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.3.2 OK +2008-11-09 1.7.20 Windows XP x86 Visual C++ 15.00.30729.01 OK +2008-11-06 1.7.19 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2 OK +2008-11-06 1.7.19 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.1.2, 4.3.1 OK +2008-11-06 1.7.19 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 9.1-20061101 OK +2008-11-06 1.7.19 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 10.1-20080801 OK +2008-11-06 1.7.19 Windows XP x86 Visual C++ 15.00.30729.01 OK +2008-11-03 1.7.19 FreeBSD 7.0 x86-64 GCC 4.2.1 OK +2008-10-24 1.7.18 Gentoo 2007.0 IBM POWER5+ GCC 4.2.2, 4.3.1 OK +2008-10-24 1.7.18 Fedora 8 STI Cell PPU GCC 4.1.2 OK +2008-10-22 1.7.18 Windows XP Pentium 4-M GCC 3.4.5 (MinGW) OK +2008-10-22 1.7.18 Windows XP Pentium 4-M Visual C++ 15.00.30729.01 OK +2008-10-22 1.7.18 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2 OK +2008-10-22 1.7.18 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.1.2, 4.2.4, 4.3.2 OK +2008-10-22 1.7.18 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 9.1-20061101 OK +2008-10-22 1.7.18 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 10.1-20080801 OK +2008-10-07 1.7.15 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2 OK +2008-10-07 1.7.15 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.3.1 OK +2008-09-30 1.7.14 Gentoo 2007.0 PPC 970FX (G5) GCC 4.3.1 OK +2008-09-30 1.7.14 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2 OK +2008-09-30 1.7.14 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.3.1 OK +2008-09-30 1.7.14 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 10.1.018 OK +2008-09-30 1.7.14 Windows XP Pentium 4-M Visual C++ 15.00.30729.01 OK +2008-09-30 1.7.14 Windows XP Pentium 4-M GCC 3.4.5 (MinGW) OK +2008-09-18 1.7.12 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2, 4.2.2 OK +2008-09-18 1.7.12 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.2.4, 4.3.1 OK +2008-09-18 1.7.12 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 10.1.018 OK +2008-09-18 1.7.12 Windows XP Pentium 4-M Visual C++ 15.00.30729.01 OK +2008-09-18 1.7.12 Windows XP Pentium 4-M GCC 3.4.5 (MinGW) OK +2008-09-16 1.7.12 Fedora 7 STI Cell PPU GCC 4.1.2 OK +2008-09-16 1.7.11 MacOS X 10.4 (32) Intel Core2 GCC 4.0.1 OK +2008-09-11 1.7.11 Gentoo 2007.0 Intel Core2 Q6600 GCC 4.3.1 OK +2008-09-11 1.7.11 Windows XP Pentium 4-M Visual C++ 15.00.30729.01 OK +2008-09-08 1.7.9 Gentoo 2007.0 Intel Core2 Q6600 Intel C++ 10.1.018 OK +2008-08-28 1.7.9 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2 OK +2008-08-28 1.7.9 Gentoo 2007.0 IBM POWER5+ GCC 4.2.2 OK +2008-08-28 1.7.9 Gentoo 2007.0 IBM POWER5+ GCC 4.3.1 OK +2008-08-28 1.7.9 Gentoo STI Cell PPU GCC 4.1.2 OK +2008-08-27 1.7.9 Gentoo Intel Core2 Q6600 GCC 4.1.2 OK +2008-08-27 1.7.9 Gentoo Intel Core2 Q6600 GCC 4.2.4 OK +2008-08-27 1.7.9 Gentoo Intel Core2 Q6600 GCC 4.3.1 OK +2008-08-27 1.7.9 Gentoo Intel Core2 Q6600 GCC 4.4-20080822 OK +2008-08-27 1.7.9 Gentoo Intel Core2 Q6600 Intel C++ 9.1-20061101 OK +2008-08-27 1.7.9 Gentoo Intel Core2 Q6600 Intel C++ 10.1-20080602 OK +2008-08-27 1.7.9 Windows XP Pentium 4-M Visual C++ 2008 OK +2008-08-27 1.7.9 Windows XP Pentium 4-M GCC 3.4.5 (MinGW) OK +2008-08-18 1.7.8 Ubuntu 8.04 Pentium 4-M GCC 4.2.3 OK +2008-08-18 1.7.8 Windows XP Pentium 4-M Visual C++ 2008 OK +2008-08-18 1.7.8 Windows XP Pentium 4-M GCC 3.4.5 (MinGW) OK +2008-07-18 1.7.8 Gentoo IBM POWER5+ GCC 4.1.2 OK +2008-07-15 1.7.8 Gentoo Intel Core2 Q6600 GCC 4.3.1 OK +2008-07-06 1.7.7 Gentoo Intel Core2 Q6600 PGI 7.2 Miscompiles TEA, Turing, BigInt +2008-06-28 1.7.7 Gentoo Pentium 4-M GCC 4.1.2 OK +2008-06-28 1.7.7 Gentoo Intel Core2 Q6600 GCC 4.1.2, 4.2.4, 4.3.1 OK +2008-06-28 1.7.7 Gentoo Intel Core2 Q6600 Intel C++ 10.1 OK +2008-06-28 1.7.7 Gentoo IBM POWER5+ GCC 4.1.2, 4.2.2 OK +2008-06-25 1.7.6 Gentoo IBM POWER5+ GCC 4.1.2, 4.2.2 OK +2008-06-09 1.7.6 Gentoo PPC 970FX (G5) GCC 4.1.2 OK +2008-05-14 1.7.6 Gentoo Intel Core2 Q6600 Intel C++ 9.1 Builds, but link problems +2008-05-14 1.7.6 Gentoo Intel Core2 Q6600 GCC 4.2.3 OK +2008-04-21 1.7.5 Gentoo STI Cell PPU GCC 4.1.2 OK +2008-04-14 1.7.5 Debian Pentium 4 GCC 4.1.2 OK +2008-04-13 1.7.5 Gentoo 2006.1 UltraSPARC II (32) GCC 3.4.6 OK +2008-04-12 1.7.5 RHEL3 Pentium 4 Xeon GCC 3.2.3 OK +2008-04-12 1.7.5 Gentoo Intel Core2 Q6600 Intel C++ 10.1 OK +2008-04-12 1.7.5 Gentoo AMD Opteron 2212 GCC 4.1.2 OK +2008-04-12 1.7.5 Gentoo Intel Core2 Q6600 GCC 4.2.3 OK +2008-09-16 1.6.5 MacOS X 10.4 Intel Core2 (32) GCC 4.0.1 OK +2008-08-28 1.6.5 Gentoo 2007.0 IBM POWER5+ GCC 4.1.2, 4.2.2, 4.3.1 OK +2008-08-27 1.6.5 Gentoo Intel Core2 Q6600 GCC 4.3.1, 4.4-20080822 OK +2008-08-18 1.6.4 Windows XP Pentium 4-M Visual C++ 2008 OK +2008-07-02 1.6.4 Solaris 10 x86-64 Sun Forte 12 OK +=========== ======= =================== ======================== ============================ ======== diff --git a/doc/building.tex b/doc/building.tex deleted file mode 100644 index 7164f74eb..000000000 --- a/doc/building.tex +++ /dev/null @@ -1,444 +0,0 @@ -\documentclass{article} - -\setlength{\textwidth}{6.5in} -\setlength{\textheight}{9in} - -\setlength{\headheight}{0in} -\setlength{\topmargin}{0in} -\setlength{\headsep}{0in} - -\setlength{\oddsidemargin}{0in} -\setlength{\evensidemargin}{0in} - -\title{\textbf{Botan Build Guide}} -\author{Jack Lloyd \\ - \texttt{[email protected]}} -\date{2010-06-10} - -\newcommand{\filename}[1]{\texttt{#1}} -\newcommand{\module}[1]{\texttt{#1}} - -\newcommand{\type}[1]{\texttt{#1}} -\newcommand{\function}[1]{\textbf{#1}} -\newcommand{\macro}[1]{\texttt{#1}} - -\begin{document} - -\maketitle - -\tableofcontents - -\parskip=5pt -\pagebreak - -\section{Introduction} - -This document describes how to build Botan on Unix/POSIX and MS -Windows systems. The POSIX oriented descriptions should apply to most -common Unix systems (including MacOS X), along with POSIX-ish systems -like BeOS, QNX, and Plan 9. Currently, systems other than Windows and -POSIX (such as VMS, MacOS 9, OS/390, OS/400, ...) are not supported by -the build system, primarily due to lack of access. Please contact the -maintainer if you would like to build Botan on such a system. - -Botan's build is controlled by configure.py, which is a Python -script. Python 2.5 or later is required. If you want to use the -(incompatible) Python 3, you must first run the \texttt{2to3} script -on it. - -\section{For the Impatient} - -\begin{verbatim} -$ ./configure.py [--prefix=/some/directory] -$ make -$ make check -$ make install -\end{verbatim} - -Or using \verb|nmake|, if you're compiling on Windows with Visual -C++. On platforms that do not understand the '\#!' convention for -beginning script files, or that have Python installed in an unusual -spot, you might need to prefix the \texttt{configure.py} command with -\texttt{python} or \texttt{/path/to/python}. - -\section{Building the Library} - -The first step is to run \filename{configure.py}, which is a Python -script that creates various directories, config files, and a Makefile -for building everything. The script requires at least Python 2.5; any -later version of Python 2.x should also work. Python 3.1 will also -work but requires an extra step, see the section ``Using Python 3.1'', -later in this document. - -The script will attempt to guess what kind of system you are trying -to compile for (and will print messages telling you what it guessed). -You can override this process by passing the options \verb|--cc|, -\verb|--os|, and \verb|--cpu|. - -You can pass basically anything reasonable with \verb|--cpu|: the -script knows about a large number of different architectures, their -sub-models, and common aliases for them. You should only select the -64-bit version of a CPU (such as ``sparc64'' or ``mips64'') if your -operating system knows how to handle 64-bit object code -- a 32-bit -kernel on a 64-bit CPU will generally not like 64-bit code. - -By default the script tries to figure out what will work on your -system, and use that. It will print a display at the end showing which -algorithms have and have not been enabled. For instance on one system -we might see lines like: - -\begin{verbatim} - INFO: Skipping mod because CPU incompatible - asm_amd64 mp_amd64 mp_asm64 sha1_amd64 - INFO: Skipping mod because OS incompatible - cryptoapi_rng win32_stats - INFO: Skipping mod because compiler incompatible - mp_ia32_msvc - INFO: Skipping mod because loaded on request only - bzip2 gnump openssl qt_mutex zlib -\end{verbatim} - -The ones that are 'loaded on request only' have to be explicitly asked -for, because they rely on third party libraries which your system -might not have. For instance to enable zlib support, add -\verb|--with-zlib| to your invocation of \verb|configure.py|. - -You can control which algorithms and modules are built using the -options \verb|--enable-modules=MODS| and -\verb|--disable-modules=MODS|, for instance -\verb|--enable-modules=zlib| and \verb|--disable-modules=rc5,idea|. -Modules not listed on the command line will simply be loaded if needed -or if configured to load by default. If you use \verb|--no-autoload|, -only the most core modules will be included; you can then explicitly -enable things that you want to use with enable-modules. This is useful -for creating a minimal build targetted to a specific application. - -The script tries to guess what kind of makefile to generate, and it -almost always guesses correctly (basically, Visual C++ uses NMAKE with -Windows commands, and everything else uses Unix make with POSIX -commands). Just in case, you can override it with -\verb|--make-style=somestyle|. The styles Botan currently knows about -are 'unix' (normal Unix makefiles), and 'nmake', the make variant -commonly used by Windows compilers. To add a new variant (eg, a build -script for VMS), you will need to create a new template file in -\filename{src/build-data/makefile}. - -\subsection{POSIX / Unix} - -The basic build procedure on Unix and Unix-like systems is: - -\begin{verbatim} - $ ./configure.py [--enable-modules=<list>] [--cc=CC] - $ make - # You may need to set your LD_LIBRARY_PATH or equivalent for ./check to run - $ make check # optional, but a good idea - $ make install -\end{verbatim} - -On Unix systems the script will default to using GCC; use -\texttt{--cc} if you want something else. For instance use -\texttt{--cc=icc} for Intel C++ and \texttt{--cc=clang} for Clang. - -The \verb|make install| target has a default directory in which it -will install Botan (typically \verb|/usr/local|). You can override -this by using the \texttt{--prefix} argument to -\filename{configure.py}, like so: - -\verb|./configure.py --prefix=/opt <other arguments>| - -On some systems shared libraries might not be immediately visible to -the runtime linker. For example, on Linux you may have to edit -\filename{/etc/ld.so.conf} and run \texttt{ldconfig} (as root) in -order for new shared libraries to be picked up by the linker. An -alternative is to set your \texttt{LD\_LIBRARY\_PATH} shell variable -to include the directory that the Botan libraries were installed into. - -\subsection{Mac OS X} - -In general the Unix instructions above should apply, however OS X does -not support \texttt{LD\_LIBRARY\_PATH}. Thomas Keller suggests instead -running \verb|install_name_tool| between building and running the -self-test program: - -\begin{verbatim} - $ VERSION=1.9.10 - $ install_name_tool -change $(otool -X -D libbotan-$VERSION.dylib) \ - $PWD/libbotan-$VERSION.dylib check -\end{verbatim} - -\subsection{MS Windows} - -If you don't want to deal with building botan on Windows, check the -website; commonly prebuilt Windows binaries with installers are -available, especially for stable versions. - -You need to have a copy of Python installed, and have both Python and -your chosen compiler in your path. Open a command shell (or the SDK -shell), and run: - -\begin{verbatim} - > python configure.py --cc=msvc (or --cc=gcc for MinGW) [--cpu=CPU] - > nmake - > nmake check # optional, but recommended - > nmake install -\end{verbatim} - -For Win95 pre OSR2, the \verb|cryptoapi_rng| module will not work, -because CryptoAPI didn't exist. And all versions of NT4 lack the -ToolHelp32 interface, which is how \verb|win32_stats| does its slow -polls, so a version of the library built with that module will not -load under NT4. Later versions of Windows support both methods, so -this shouldn't be much of an issue anymore. - -By default the install target will be 'C:\textbackslash botan'; you -can modify this with the \texttt{--prefix} option. - -When building your applications, all you have to do is tell the -compiler to look for both include files and library files in -\verb|C:\botan|, and it will find both. Or you can move them to a -place where they will be in the default compiler search paths (consult -your documentation and/or local expert for details). - -\section{Trickier Things} - -\subsection{Modules Relying on Third Party Libraries} - -There are a fairly large number of modules included with Botan. Some -of these are extremely useful, while others are only necessary in very -unusual circumstances. Most are loaded (or not) automatically as -necessary, but some require external libraries are thus must be -enabled at build time; these include: - -\newcommand{\mod}[2]{\textbf{#1}: #2} - -\begin{list}{$\cdot$} - \item \mod{bzip2}{Enables an application to perform bzip2 - compression and decompression using the library. Available on any - system that has bzip2. To enable, use option \texttt{--with-bzip2}} - - \item \mod{zlib}{Enables an application to perform zlib compression - and decompression using the library. Available on any system that - has zlib. To enable, use option \texttt{--with-zlib}} - - \item \mod{gnump}{An engine that uses GNU MP to speed up PK - operations. GNU MP 4.1 or later is required. To enable, use - option \texttt{--with-gnump}} - - \item \mod{openssl}{An engine that uses OpenSSL to speed up public - key operations and some ciphers/hashes. OpenSSL 0.9.7 or later is - required. Note that, unlike GNU MP, OpenSSL's versions are not - always faster than the versions built into botan. To enable, use - option \texttt{--with-openssl}} - -\end{list} - -\subsection{Amalgamation} - -You can also configure Botan to be built using only a single source -file; this is quite convenient if you plan to embed the library into -another application. To do so, run \filename{configure.py} with -whatever arguments you would ordinarily use, along with the option -\texttt{--gen-amalgamation}. This will create two (rather large) -files, \filename{botan\_all.h} and \filename{botan\_all.cpp}. - -Whenever you would have included a botan header, you can then include -\filename{botan\_all.h}, and include \filename{botan\_all.cpp} along -with the rest of the source files in your build. If you want to be -able to easily switch between amalgamated and non-amalgamated versions -(for instance to take advantage of prepackaged versions of botan on -operating systems that support it), you can instead ignore -\filename{botan\_all.h} and use the headers from -\filename{build/include} as normal. - -\subsection{Multiple Builds} - -It may be useful to run multiple builds with different -configurations. Specify \verb|--build-dir=<dir>| to set up a build -environment in a different directory. - -\subsection{Using Python 3.1} - -The versions of Python begininning with 3 are (intentionally) -incompatible with the (currently more common) 2.x series. If you want -to use Python 3.1 to set up the build, you'll have to use the -\texttt{2to3} program (included in the Python distribution) on the -script; this will convert the script to the Python 3.x dialect: - -\begin{verbatim} - $ python ./configure.py - File "configure.py", line 860 - except KeyError, e: - ^ -SyntaxError: invalid syntax - $ # incompatible python version, let's fix it - $ 2to3 -w configure.py -[...] -RefactoringTool: Files that were modified: -RefactoringTool: configure.py - $ python ./configure.py -[...] -\end{verbatim} - -\subsection{Local Configuration} - -You may want to do something peculiar with the configuration; to -support this there is a flag to \filename{configure.py} called -\texttt{--with-local-config=<file>}. The contents of the file are -inserted into \filename{build/build.h} which is (indirectly) included -into every Botan header and source file. - -\subsection{Configuration Parameters} - -There are some configuration parameters which you may want to tweak -before building the library. These can be found in -\filename{config.h}. This file is overwritten every time the configure -script is run (and does not exist until after you run the script for -the first time). - -Also included in \filename{build/build.h} are macros which are defined -if one or more extensions are available. All of them begin with -\verb|BOTAN_HAS_|. For example, if \verb|BOTAN_HAS_COMPRESSOR_BZIP2| -is defined, then an application using Botan can include -\filename{<botan/bzip2.h>} and use the Bzip2 filters. - -\macro{BOTAN\_MP\_WORD\_BITS}: This macro controls the size of the -words used for calculations with the MPI implementation in Botan. You -can choose 8, 16, 32, or 64, with 32 being the default. You can use 8, -16, or 32 bit words on any CPU, but the value should be set to the -same size as the CPU's registers for best performance. You can only -use 64-bit words if an assembly module (such as \module{mp\_ia32} or -\module{mp\_asm64}) is used. If the appropriate module is available, -64 bits are used, otherwise this is set to 32. Unless you are building -for a 8 or 16-bit CPU, this isn't worth messing with. - -\macro{BOTAN\_VECTOR\_OVER\_ALLOCATE}: The memory container -\type{SecureVector} will over-allocate requests by this amount (in -elements). In several areas of the library, we grow a vector fairly often. By -over-allocating by a small amount, we don't have to do allocations as often -(which is good, because the allocators can be quite slow). If you \emph{really} -want to reduce memory usage, set it to 0. Otherwise, the default should be -perfectly fine. - -\macro{BOTAN\_DEFAULT\_BUFFER\_SIZE}: This constant is used as the size of -buffers throughout Botan. A good rule of thumb would be to use the page size of -your machine. The default should be fine for most, if not all, purposes. - -\section{Building Applications} - -\subsection{Unix} - -Botan usually links in several different system libraries (such as -\texttt{librt} and \texttt{libz}), depending on which modules are -configured at compile time. In many environments, particularly ones -using static libraries, an application has to link against the same -libraries as Botan for the linking step to succeed. But how does it -figure out what libraries it \emph{is} linked against? - -The answer is to ask the \filename{botan-config} script. This -basically solves the same problem all the other \filename{*-config} -scripts solve, and in basically the same manner. - -There are 4 options: - -\texttt{--prefix[=DIR]}: If no argument, print the prefix where Botan -is installed (such as \filename{/opt} or \filename{/usr/local}). If an -argument is specified, other options given with the same command will -execute as if Botan as actually installed at \filename{DIR} and not -where it really is; or at least where \filename{botan-config} thinks -it really is. I should mention that it - -\texttt{--version}: Print the Botan version number. - -\texttt{--cflags}: Print options that should be passed to the compiler -whenever a C++ file is compiled. Typically this is used for setting -include paths. - -\texttt{--libs}: Print options for which libraries to link to (this includes -\texttt{-lbotan}). - -Your \filename{Makefile} can run \filename{botan-config} and get the -options necessary for getting your application to compile and link, -regardless of whatever crazy libraries Botan might be linked against. - -Botan also by default installs a file for \texttt{pkg-config}, -namespaced by the major and minor versions. So it can be used, -for instance, as - -\begin{verbatim} -$ pkg-config botan-1.9 --modversion -1.9.8 -$ pkg-config botan-1.9 --cflags --I/usr/local/include -$ pkg-config botan-1.9 --libs --L/usr/local/lib -lbotan -lm -lbz2 -lpthread -lrt -\end{verbatim} - -\subsection{MS Windows} - -No special help exists for building applications on Windows. However, -given that typically Windows software is distributed as binaries, this -is less of a problem - only the developer needs to worry about it. As -long as they can remember where they installed Botan, they just have -to set the appropriate flags in their Makefile/project file. - -\section{Language Wrappers} - -\subsection{Building the Python wrappers} - -The Python wrappers for Botan use Boost.Python, so you must have Boost -installed. To build the wrappers, add the flag - -\verb|--with-boost-python| - -to \verb|configure.py|. This will create a second makefile, -\verb|Makefile.python|, with instructions for building the Python -module. After building the library, execute - -\begin{verbatim} -$ make -f Makefile.python -\end{verbatim} - -to build the module. Currently only Unix systems are supported, and -the Makefile assumes that the version of Python you want to build -against is the same one you used to run \verb|configure.py|. - -To install the module, use the \verb|install| target. - -Examples of using the Python module can be seen in \filename{doc/python} - -\subsection{Building the Perl XS wrappers} - -To build the Perl XS wrappers, change your directory to -\filename{src/wrap/perl-xs} and run \verb|perl Makefile.PL|, then run -\verb|make| to build the module and \verb|make test| to run the test -suite. - -\begin{verbatim} -$ perl Makefile.PL -Checking if your kit is complete... -Looks good -Writing Makefile for Botan -$ make -cp Botan.pm blib/lib/Botan.pm -AutoSplitting blib/lib/Botan.pm (blib/lib/auto/Botan) -/usr/bin/perl5.8.8 /usr/lib64/perl5/5.8.8/ExtUtils/xsubpp [...] -g++ -c -Wno-write-strings -fexceptions -g [...] -Running Mkbootstrap for Botan () -chmod 644 Botan.bs -rm -f blib/arch/auto/Botan/Botan.so -g++ -shared Botan.o -o blib/arch/auto/Botan/Botan.so \ - -lbotan -lbz2 -lpthread -lrt -lz \ - -chmod 755 blib/arch/auto/Botan/Botan.so -cp Botan.bs blib/arch/auto/Botan/Botan.bs -chmod 644 blib/arch/auto/Botan/Botan.bs -Manifying blib/man3/Botan.3pm -$ make test -PERL_DL_NONLAZY=1 /usr/bin/perl5.8.8 [...] -t/base64......ok -t/filt........ok -t/hex.........ok -t/oid.........ok -t/pipe........ok -t/x509cert....ok -All tests successful. -Files=6, Tests=83, 0 wallclock secs ( 0.08 cusr + 0.02 csys = 0.10 CPU) -\end{verbatim} - -\end{document} diff --git a/doc/building.txt b/doc/building.txt new file mode 100644 index 000000000..9e7be79a3 --- /dev/null +++ b/doc/building.txt @@ -0,0 +1,433 @@ + +Building The Library +================================= + +This document describes how to build Botan on Unix/POSIX and MS +Windows systems. The POSIX oriented descriptions should apply to most +common Unix systems (including MacOS X), along with POSIX-ish systems +like BeOS, QNX, and Plan 9. Currently, systems other than Windows and +POSIX (such as VMS, MacOS 9, OS/390, OS/400, ...) are not supported by +the build system, primarily due to lack of access. Please contact the +maintainer if you would like to build Botan on such a system. + +Botan's build is controlled by configure.py, which is a `Python +<http://www.python.org>`_ script. Python 2.5 or later is required. + +For the impatient, this works for most systems:: + + $ ./configure.py [--prefix=/some/directory] + $ make + $ make check + $ make install + +Or using ``nmake``, if you're compiling on Windows with Visual C++. On +platforms that do not understand the '#!' convention for beginning +script files, or that have Python installed in an unusual spot, you +might need to prefix the ``configure.py`` command with ``python`` or +``/path/to/python``:: + + $ python ./configure.py [arguments] + +Configuring the Build +--------------------------------- + +The first step is to run ``configure.py``, which is a Python script +that creates various directories, config files, and a Makefile for +building everything. The script requires at least Python 2.5; any +later version of Python 2.x should also work. Python 3.1 will also +work but requires an extra step; see :ref:`configure_with_python3` for +details. + +The script will attempt to guess what kind of system you are trying to +compile for (and will print messages telling you what it guessed). +You can override this process by passing the options ``--cc``, +``--os``, and ``--cpu``. + +You can pass basically anything reasonable with ``--cpu``: the script +knows about a large number of different architectures, their +sub-models, and common aliases for them. You should only select the +64-bit version of a CPU (such as "sparc64" or "mips64") if your +operating system knows how to handle 64-bit object code - a 32-bit +kernel on a 64-bit CPU will generally not like 64-bit code. + +By default the script tries to figure out what will work on your +system, and use that. It will print a display at the end showing which +algorithms have and have not been enabled. For instance on one system +we might see lines like:: + + INFO: Skipping, by request only - bzip2 gnump openssl qt_mutex zlib + INFO: Skipping, incompatible CPU - aes_intel aes_ssse3 asm_x86_64 mp_asm64 mp_x86_64 sha1_x86_64 + INFO: Skipping, incompatible OS - beos_stats cryptoapi_rng win32_crit_section win32_stats + INFO: Skipping, incompatible compiler - mp_msvc64 mp_x86_32_msvc + +The ones that are 'loaded on request only' have to be explicitly asked +for, because they rely on third party libraries which your system +might not have. For instance to enable zlib support, add +``--with-zlib`` to your invocation of ``configure.py``. + +You can control which algorithms and modules are built using the +options ``--enable-modules=MODS`` and ``--disable-modules=MODS``, for +instance ``--enable-modules=zlib`` and ``--disable-modules=rc5,idea``. +Modules not listed on the command line will simply be loaded if needed +or if configured to load by default. If you use ``--no-autoload``, +only the most core modules will be included; you can then explicitly +enable things that you want to use with ``--enable-modules``. This is +useful for creating a minimal build targeting to a specific +application, especially in conjunction with the amalgamation option; +see :ref:`amalgamation`. + +For instance:: + + $ ./configure.py --no-autoload --enable-modules=rsa,ecdsa,eme1,emsa1,emsa4 + +will set up a build that only includes RSA, ECDSA, and some padding +modes, along with their dependencies. A small subset of core features, +including AES, SHA-2, HMAC, and the multiple precision integer +library, are always loaded. + +The script tries to guess what kind of makefile to generate, and it +almost always guesses correctly (basically, Visual C++ uses NMAKE with +Windows commands, and everything else uses Unix make with POSIX +commands). Just in case, you can override it with +``--make-style=somestyle``. The styles Botan currently knows about are +'unix' (normal Unix makefiles), and 'nmake', the make variant commonly +used by Windows compilers. To add a new variant (eg, a build script +for VMS), you will need to create a new template file in +``src/build-data/makefile``. + +On Unix +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The basic build procedure on Unix and Unix-like systems is:: + + $ ./configure.py [--enable-modules=<list>] [--cc=CC] + $ make + # You may need to set your LD_LIBRARY_PATH or equivalent for ./check to run + $ make check # optional, but a good idea + $ make install + +On Unix systems the script will default to using GCC; use +``--cc`` if you want something else. For instance use +``--cc=icc`` for Intel C++ and ``--cc=clang`` for Clang. + +The ``make install`` target has a default directory in which it +will install Botan (typically ``/usr/local``). You can override +this by using the ``--prefix`` argument to +``configure.py``, like so: + +``./configure.py --prefix=/opt <other arguments>`` + +On some systems shared libraries might not be immediately visible to +the runtime linker. For example, on Linux you may have to edit +``/etc/ld.so.conf`` and run ``ldconfig`` (as root) in +order for new shared libraries to be picked up by the linker. An +alternative is to set your ``LD_LIBRARY_PATH`` shell variable +to include the directory that the Botan libraries were installed into. + +On Mac OS X +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In general the Unix instructions above should apply, however OS X does +not support ``LD_LIBRARY_PATH``. Thomas Keller suggests instead +running ``install_name_tool`` between building and running the +self-test program:: + + $ VERSION=1.10.0 # or whatever the current version is + $ install_name_tool -change $(otool -X -D libbotan-$VERSION.dylib) \ + $PWD/libbotan-$VERSION.dylib check + +On MS Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you don't want to deal with building botan on Windows, check the +website; commonly prebuilt Windows binaries with installers are +available, especially for stable versions. + +You need to have a copy of Python installed, and have both Python and +your chosen compiler in your path. Open a command shell (or the SDK +shell), and run:: + + > python configure.py --cc=msvc (or --cc=gcc for MinGW) [--cpu=CPU] + > nmake + > nmake check # optional, but recommended + > nmake install + +For Win95 pre OSR2, the ``cryptoapi_rng`` module will not work, +because CryptoAPI didn't exist. And all versions of NT4 lack the +ToolHelp32 interface, which is how ``win32_stats`` does its slow +polls, so a version of the library built with that module will not +load under NT4. Later versions of Windows support both methods, so +this shouldn't be much of an issue anymore. + +By default the install target will be ``C:\botan``; you can modify +this with the ``--prefix`` option. + +When building your applications, all you have to do is tell the +compiler to look for both include files and library files in +``C:\botan``, and it will find both. Or you can move them to a +place where they will be in the default compiler search paths (consult +your documentation and/or local expert for details). + +Other Build-Related Tasks +---------------------------------------- + +.. _amalgamation: + +The Amalgamation Build +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can also configure Botan to be built using only a single source +file; this is quite convenient if you plan to embed the library into +another application. To do so, run ``configure.py`` with whatever +arguments you would ordinarily use, along with the option +``--gen-amalgamation``. This will create two (rather large) files, +``botan_all.h`` and ``botan_all.cpp``. + +Whenever you would have included a botan header, you can then include +``botan_all.h``, and include ``botan_all.cpp`` along with the rest of +the source files in your build. If you want to be able to easily +switch between amalgamated and non-amalgamated versions (for instance +to take advantage of prepackaged versions of botan on operating +systems that support it), you can instead ignore ``botan_all.h`` and +use the headers from ``build/include`` as normal. + +You can also build the library as normal but using the amalgamation +instead of the individual source files using ``--via-amalgamation``. +This is essentially a very simple form of link time optimization; +because the entire library source is visible to the compiler, it has +more opportunities for interprocedural optimizations. + +Modules Relying on Third Party Libraries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are a fairly large number of modules included with Botan. Some +of these are extremely useful, while others are only necessary in very +unusual circumstances. Most are loaded (or not) automatically as +necessary, but some require external libraries are thus must be +enabled at build time; these include: + + - ``--with-bzip2`` enables the filters providing bzip2 compression + and decompression. Requires the bzip2 development libraries to be + installed. + + - ``--with-zlib`` enables the filters providing zlib compression + and decompression. Requires the zlib development libraries to be + installed. + + - ``--with-gnump`` adds an alternative engine for public key + cryptography that uses the GNU MP library. GNU MP 4.1 or later is + required. + + - ``--with-openssl`` adds an engine that uses OpenSSL for some public + key operations and ciphers/hashes. OpenSSL 0.9.7 or later is + required. Note that OpenSSL's versions are not always faster than + the versions built into botan. + +Multiple Builds +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It may be useful to run multiple builds with different +configurations. Specify ``--build-dir=<dir>`` to set up a build +environment in a different directory. + + +.. _configure_with_python3: + +Configuring the Build With Python 3.1 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The versions of Python beginning with 3 are (intentionally) +incompatible with the (currently more common) 2.x series. If you want +to use Python 3.1 to set up the build, you'll have to use the +``2to3`` program (included in the Python distribution) on the +script; this will convert the script to the Python 3.x dialect:: + + $ python ./configure.py + File "configure.py", line 860 + except KeyError, e: + ^ + SyntaxError: invalid syntax + $ # incompatible python version, let's fix it + $ 2to3 -w configure.py + [...] + RefactoringTool: Files that were modified: + RefactoringTool: configure.py + $ python ./configure.py + [...] + +Setting Distribution Info +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The build allows you to set some information about what distribution +this build of the library comes from. It is particularly relevant to +people packaging the library for wider distribution, to signify what +distribution this build is from. Applications can test this value by +checking the string value of the macro ``BOTAN_DISTRIBUTION_INFO``. It +can be set using the ``--distribution-info`` flag to ``configure.py``, +and otherwise defaults to "unspecified". For instance, a `Gentoo +<http://www.gentoo.org>`_ ebuild might set it with +``--distribution-info="Gentoo ${PVR}"`` where ``${PVR}`` is an ebuild +variable automatically set to a combination of the library and ebuild +versions. + +Local Configuration Settings +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You may want to do something peculiar with the configuration; to +support this there is a flag to ``configure.py`` called +``--with-local-config=<file>``. The contents of the file are +inserted into ``build/build.h`` which is (indirectly) included +into every Botan header and source file. + +Configuration Parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are some configuration parameters which you may want to tweak +before building the library. These can be found in ``config.h``. This +file is overwritten every time the configure script is run (and does +not exist until after you run the script for the first time). + +Also included in ``build/build.h`` are macros which let applications +check which features are included in the current version of the +library. All of them begin with ``BOTAN_HAS_``. For example, if +``BOTAN_HAS_BLOWFISH`` is defined, then an application can include +``<botan/blowfish.h>`` and use the Blowfish class. + +``BOTAN_MP_WORD_BITS``: This macro controls the size of the words used +for calculations with the MPI implementation in Botan. You can choose +8, 16, 32, or 64. Normally this defaults to either 32 or 64, depending +on the processor. Unless you are building for a 8 or 16-bit CPU, this +isn't worth messing with. + +``BOTAN_VECTOR_OVER_ALLOCATE``: The memory container ``SecureVector`` +will over-allocate requests by this amount (in elements). In several +areas of the library, we grow a vector fairly often. By +over-allocating by a small amount, we don't have to do allocations as +often (which is good, because the allocators can be quite slow). If +you *really* want to reduce memory usage, set it to 0. Otherwise, the +default should be perfectly fine. + +``BOTAN_DEFAULT_BUFFER_SIZE``: This constant is used as the size of +buffers throughout Botan. A good rule of thumb would be to use the +page size of your machine. The default should be fine for most +purposes. + +Building Applications +---------------------------------------- + +Unix +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Botan usually links in several different system libraries (such as +``librt`` and ``libz``), depending on which modules are +configured at compile time. In many environments, particularly ones +using static libraries, an application has to link against the same +libraries as Botan for the linking step to succeed. But how does it +figure out what libraries it *is* linked against? + +The answer is to ask the ``botan-config`` script. This +basically solves the same problem all the other ``*-config`` +scripts solve, and in basically the same manner. + +There are 4 options: + +``--prefix[=DIR]``: If no argument, print the prefix where Botan +is installed (such as ``/opt`` or ``/usr/local``). If an +argument is specified, other options given with the same command will +execute as if Botan as actually installed at ``DIR`` and not +where it really is; or at least where ``botan-config`` thinks +it really is. I should mention that it + +``--version``: Print the Botan version number. + +``--cflags``: Print options that should be passed to the compiler +whenever a C++ file is compiled. Typically this is used for setting +include paths. + +``--libs``: Print options for which libraries to link to (this includes +``-lbotan``). + +Your ``Makefile`` can run ``botan-config`` and get the +options necessary for getting your application to compile and link, +regardless of whatever crazy libraries Botan might be linked against. + +Botan also by default installs a file for ``pkg-config``, +namespaced by the major and minor versions. So it can be used, +for instance, as:: + + $ pkg-config botan-1.10 --modversion + 1.10.0 + $ pkg-config botan-1.10 --cflags + -I/usr/local/include + $ pkg-config botan-1.10 --libs + -L/usr/local/lib -lbotan -lm -lbz2 -lpthread -lrt + +MS Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +No special help exists for building applications on Windows. However, +given that typically Windows software is distributed as binaries, this +is less of a problem - only the developer needs to worry about it. As +long as they can remember where they installed Botan, they just have +to set the appropriate flags in their Makefile/project file. + +Language Wrappers +---------------------------------------- + +Building the Python wrappers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Python wrappers for Botan use Boost.Python, so you must have Boost +installed. To build the wrappers, pass the flag +``--with-boost-python`` to ``configure.py``. This will create a second +makefile, ``Makefile.python``, with instructions for building the +Python module. After building the library, execute:: + + $ make -f Makefile.python + +to build the module. Currently only Unix systems are supported, and +the Makefile assumes that the version of Python you want to build +against is the same one you used to run ``configure.py``. + +To install the module, use the ``install`` target. + +Examples of using the Python module can be seen in +``doc/examples/python`` + +Building the Perl XS wrappers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To build the Perl XS wrappers, change your directory to +``src/wrap/perl-xs`` and run ``perl Makefile.PL``, then run +``make`` to build the module and ``make test`` to run the test +suite:: + + $ perl Makefile.PL + Checking if your kit is complete... + Looks good + Writing Makefile for Botan + $ make + cp Botan.pm blib/lib/Botan.pm + AutoSplitting blib/lib/Botan.pm (blib/lib/auto/Botan) + /usr/bin/perl5.8.8 /usr/lib64/perl5/5.8.8/ExtUtils/xsubpp [...] + g++ -c -Wno-write-strings -fexceptions -g [...] + Running Mkbootstrap for Botan () + chmod 644 Botan.bs + rm -f blib/arch/auto/Botan/Botan.so + g++ -shared Botan.o -o blib/arch/auto/Botan/Botan.so \ + -lbotan -lbz2 -lpthread -lrt -lz \ + + chmod 755 blib/arch/auto/Botan/Botan.so + cp Botan.bs blib/arch/auto/Botan/Botan.bs + chmod 644 blib/arch/auto/Botan/Botan.bs + Manifying blib/man3/Botan.3pm + $ make test + PERL_DL_NONLAZY=1 /usr/bin/perl5.8.8 [...] + t/base64......ok + t/filt........ok + t/hex.........ok + t/oid.........ok + t/pipe........ok + t/x509cert....ok + All tests successful. + Files=6, Tests=83, 0 wallclock secs ( 0.08 cusr + 0.02 csys = 0.10 CPU) diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 000000000..65f40314a --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,243 @@ +# -*- coding: utf-8 -*- +# +# botan documentation build configuration file, created by +# sphinx-quickstart on Sun Apr 3 11:41:06 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +sys.path.insert(0, os.pardir) + +# Avoid useless botan_version.pyc (Python 2.6 or higher) +if 'dont_write_bytecode' in sys.__dict__: + sys.dont_write_bytecode = True + +import botan_version + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.0' + +""" +Assert that we are running under Sphinx 1.0.7 or later. Earlier +versions have bugs in the C++ domain that cause crashes. And +needs_sphinx only allows us to assert needing a particular major/minor +version. +""" +def check_sphinx_version(): + import sphinx + + version = map(int, sphinx.__version__.split('.')) + if version[0] == 1 and version[1] == 0 and version[2] < 7: + # Exit rather than throwing to avoid a confusing backtrace + print "This Sphinx is too old - upgrade to at least 1.0.7" + import sys + sys.exit(1) + +check_sphinx_version() + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.txt' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'contents' + +# General information about the project. +project = u'botan' +copyright = u'2000-2011, Jack Lloyd' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '%d.%d' % (botan_version.release_major, botan_version.release_minor) +# The full version, including alpha/beta/rc tags. +release = '%d.%d.%d' % (botan_version.release_major, + botan_version.release_minor, + botan_version.release_patch) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%Y-%m-%d' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = False + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +highlight_language = 'cpp' + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'agogo' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + 'linkcolor': 'blue', + 'headerlinkcolor': 'blue', + 'headercolor1': 'darkblue', + 'headercolor2': 'darkblue', + 'textalign': 'left' + } + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +html_title = 'Botan' + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'botandoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('contents', 'botan.tex', u'botan Reference Manual', + u'Jack Lloyd', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +latex_show_pagerefs = False + +# If true, show URL addresses after external links. +latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + diff --git a/doc/contents.txt b/doc/contents.txt new file mode 100644 index 000000000..633625e14 --- /dev/null +++ b/doc/contents.txt @@ -0,0 +1,42 @@ + +Contents +================================= + +.. toctree:: + :maxdepth: 2 + + index + building + firststep + filters + pubkey + x509 + ssl + bigint + lowlevel + secmem + kdf + pbkdf + passhash + rng + fpe + +.. toctree:: + :hidden: + + license + credits + faq + users + support + download + pgpkey + algos + log + build_log + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/doc/credits.txt b/doc/credits.txt index fde877e7b..076498756 100644 --- a/doc/credits.txt +++ b/doc/credits.txt @@ -1,78 +1,80 @@ -This is at least a partial credits-file of people that have -contributed to the Botan project. It is sorted by name and formatted -to allow easy grepping and beautification by scripts. The fields are: -name (N), email (E), web-address (W), PGP key ID and fingerprint (P), -description (D), and snail-mail address (S). - -Thanks, - Jack Lloyd ----------- - -N: Charles Brockman -W: http://www.securitygenetics.com/ -D: documentation editing -S: Oregon, USA - -N: Martin Doering -D: GF(p) arithmetic - -N: Olivier de Gaalon -D: SQLite encryption codec (src/wrap/sqlite) - -N: Matthew Gregan -D: Binary file I/O support, allocator fixes - -N: Hany Greiss -D: Windows porting - -N: Manuel Hartl -W: http://www.flexsecure.de/ -D: ECDSA, ECDH - -N: Yves Jerschow -D: Optimizations for memory load/store and HMAC -D: Support for IPv4 addresses in X.509 alternative names -S: Germany - -N: Matt Johnston -D: Allocator fixes and optimizations, decompressor fixes - -N: Peter J. Jones -D: Bzip2 compression module -S: Colorado, USA - -N: Justin Karneges -D: Qt support modules (mutexes and types), X.509 API design - -N: Jack Lloyd -W: http://www.randombit.net/ -P: 3F69 2E64 6D92 3BBE E7AE 9258 5C0F 96E8 4EC1 6D6B -D: Original designer/author, maintainer 2001-current -S: Vermont, USA - -N: Joel Low -D: DLL symbol visibility - -N: Christoph Ludwig -D: GP(p) arithmetic - -N: Vaclav Ovsik -D: Perl XS module (src/wrap/perl-xs) - -N: Luca Piccarreta -D: x86/amd64 assembler, BigInt optimizations, Win32 mutex module -S: Italy - -N: Falko Strenzke -W: http://www.flexsecure.de/ -D: GF(p) arithmetic, CVC, Shanks-Tonelli algorithm -S: Darmstadt, Germany + +Credits +======================================== + +This is at least a partial credits-file of people that have contributed +to botan. It is sorted by name and formatted to allow easy grepping +and beautification by scripts. The fields are name (N), email (E), +web-address (W), PGP key ID and fingerprint (P), description (D), and +snail-mail address (S). + +:: + + N: Charles Brockman + W: http://www.securitygenetics.com/ + D: documentation editing + S: Oregon, USA + + N: Martin Doering + E: [email protected] + D: GF(p) arithmetic + + N: Olivier de Gaalon + D: SQLite encryption codec (src/wrap/sqlite) + + N: Matthew Gregan + D: Binary file I/O support, allocator fixes + + N: Hany Greiss + D: Windows porting + + N: Manuel Hartl + E: [email protected] + W: http://www.flexsecure.de/ + D: ECDSA, ECDH + + N: Yves Jerschow + E: [email protected] + D: Optimizations for memory load/store and HMAC + D: Support for IPv4 addresses in X.509 alternative names + S: Germany + + N: Matt Johnston + D: Allocator fixes and optimizations, decompressor fixes + + N: Peter J. Jones + E: [email protected] + D: Bzip2 compression module + S: Colorado, USA + + N: Justin Karneges + D: Qt support modules (mutexes and types), X.509 API design + + N: Jack Lloyd + E: [email protected] + W: http://www.randombit.net/ + P: 3F69 2E64 6D92 3BBE E7AE 9258 5C0F 96E8 4EC1 6D6B + D: Original designer/author, maintainer 2001-current + S: Vermont, USA + + N: Joel Low + D: DLL symbol visibility and Windows DLL support in general + + N: Christoph Ludwig + E: [email protected] + D: GP(p) arithmetic + + N: Vaclav Ovsik + E: [email protected] + D: Perl XS module (src/wrap/perl-xs) + + N: Luca Piccarreta + E: [email protected] + D: x86/amd64 assembler, BigInt optimizations, Win32 mutex module + S: Italy + + N: Falko Strenzke + E: [email protected] + W: http://www.flexsecure.de/ + D: GF(p) arithmetic, CVC, Shanks-Tonelli algorithm + S: Darmstadt, Germany diff --git a/doc/download.txt b/doc/download.txt new file mode 100644 index 000000000..7d189d10a --- /dev/null +++ b/doc/download.txt @@ -0,0 +1,100 @@ + +Getting The Latest Sources +======================================== + +All releases are signed with a :doc:`PGP key <pgpkey>`. + +Unsure which release you want? Check the :ref:`FAQ <devel_vs_stable>`. + +.. only:: not website + + .. note:: + + If you are viewing this documentation offline, a more recent + release `may be available <http://botan.randombit.net/download.html>`_ + +Current Stable Release (1.10) +---------------------------------------- + +The current stable release is `1.10.0 +<http://botan.randombit.net/news/releases/1_10_0.html>`_ which was +released on ?. + +Sources: + +`1.10.0 tar/gz <http://botan.randombit.net/files/Botan-1.10.0.tgz>`_ +(`1.10.0 tar/gz sig <http://botan.randombit.net/files/Botan-1.10.0.tgz.asc>`_), + +`1.10.0 tar/bzip <http://botan.randombit.net/files/Botan-1.10.0.tbz>`_ +(`1.10.0 tar/bzip sig <http://botan.randombit.net/files/Botan-1.10.0.tbz.asc>`_) + +Windows binary installer for use with Visual C++ 2010: + +`1.10.0 x86-32 installer +<http://botan.randombit.net/files/win32/botan-1.10.0_win32.exe>`_ + +`1.10.0 x86-64 installer +<http://botan.randombit.net/files/win32/botan-1.10.0_win64.exe>`_ + +Previous Stable Release (1.8) +---------------------------------------- + +The previous stable release is `1.8.11 +<http://botan.randombit.net/news/releases/1_8_11.html>`_ which was +released on 2010-11-02. + +Sources: + +`1.8.11 tar/gz <http://botan.randombit.net/files/Botan-1.8.11.tgz>`_ +(`1.8.11 tar/gz sig <http://botan.randombit.net/files/Botan-1.8.11.tgz.asc>`_), + +`1.8.11 tar/bzip <http://botan.randombit.net/files/Botan-1.8.11.tbz>`_ +(`1.8.11 tar/bzip sig <http://botan.randombit.net/files/Botan-1.8.11.tbz.asc>`_) + +Windows binary installer for use with Visual C++ 2008: + +`1.8.11 x86-32 installer +<http://botan.randombit.net/files/win32/botan-1.8.11_win32.exe>`_ + +`1.8.11 x86-64 installer +<http://botan.randombit.net/files/win32/botan-1.8.11_win64.exe>`_ + +Accessing Version Control +---------------------------------------- + +Botan's development occurs using a distributed version control system +called `Monotone <http://www.monotone.ca>`_. + +The main branch of development occurs on the branch named +``net.randombit.botan``; this is probably the branch you want. To +download that branch and set up a new workspace, run:: + + $ mtn db init --db=botan.mtn + $ mtn pull --db=botan.mtn randombit.net 'net.randombit.botan' + [...] + $ mtn checkout --db=botan.mtn --branch=net.randombit.botan + [...] + +By default the ``checkout`` command will place the workspace in a directory +with the same name as the branch you are checking out. If you want a +different directory name, just include it after the ``--branch`` option (you +can also rename this directory at any time). + +If this is the first time you've connected to the server, Monotone +will print:: + + mtn: first time connecting to server randombit.net + mtn: I'll assume it's really them, but you might want to double-check + mtn: their key's fingerprint: 8c0b868f2247215c63c96983b1c8ca0f0f0cfd9a + +The fingerprint shown above was the correct one as of September 21, 2010. + +To pull further changes, from anywhere in the workspace run these commands:: + + $ mtn pull + [...] + $ mtn update + [summary of changes] + +The ``mtn update`` command will give you a summary of which files changed; +to view the full changelog, run ``mtn log``. diff --git a/doc/examples/GNUmakefile b/doc/examples/GNUmakefile index a96e8d65d..6238512dc 100644 --- a/doc/examples/GNUmakefile +++ b/doc/examples/GNUmakefile @@ -3,7 +3,7 @@ BOTAN_CONFIG = botan-config CXX = g++-4.5-20091112 CFLAGS = -O2 -ansi -std=c++0x -W -Wall -I../../build/include -LIBS = -L../.. -lbotan +LIBS = -L../.. -lbotan-1.10 SRCS=$(wildcard *.cpp) diff --git a/doc/examples/asn1.cpp b/doc/examples/asn1.cpp index 11e283a64..866e57d75 100644 --- a/doc/examples/asn1.cpp +++ b/doc/examples/asn1.cpp @@ -1,37 +1,3 @@ -/* -* (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> @@ -45,8 +11,18 @@ using namespace Botan; #include <stdio.h> #include <ctype.h> -void decode(BER_Decoder&, u32bit); -void emit(const std::string&, u32bit, u32bit, const std::string& = ""); +// 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 + +void decode(BER_Decoder&, size_t); +void emit(const std::string&, size_t, size_t, const std::string& = ""); std::string type_name(ASN1_Tag); int main(int argc, char* argv[]) @@ -57,7 +33,7 @@ int main(int argc, char* argv[]) return 1; } - Botan::LibraryInitializer init; + LibraryInitializer init; try { DataSource_Stream in(argv[1]); @@ -83,7 +59,7 @@ int main(int argc, char* argv[]) return 0; } -void decode(BER_Decoder& decoder, u32bit level) +void decode(BER_Decoder& decoder, size_t level) { BER_Object obj = decoder.get_next_object(); @@ -91,7 +67,7 @@ void decode(BER_Decoder& decoder, u32bit level) { const ASN1_Tag type_tag = obj.type_tag; const ASN1_Tag class_tag = obj.class_tag; - const u32bit length = obj.value.size(); + const size_t length = obj.value.size(); /* hack to insert the tag+length back in front of the stuff now that we've gotten the type info */ @@ -142,8 +118,8 @@ void decode(BER_Decoder& decoder, u32bit level) { bool not_text = false; - for(u32bit j = 0; j != bits.size(); j++) - if(!isgraph(bits[j]) && !isspace(bits[j])) + for(size_t i = 0; i != bits.size(); ++i) + if(!isgraph(bits[i]) && !isspace(bits[i])) not_text = true; Pipe pipe(((not_text) ? new Hex_Encoder : 0)); @@ -176,8 +152,8 @@ void decode(BER_Decoder& decoder, u32bit level) rep = BigInt::encode(number, BigInt::Hexadecimal); std::string str; - for(u32bit j = 0; j != rep.size(); j++) - str += (char)rep[j]; + for(size_t i = 0; i != rep.size(); ++i) + str += (char)rep[i]; emit(type_name(type_tag), level, length, str); } @@ -198,8 +174,8 @@ void decode(BER_Decoder& decoder, u32bit level) data.decode(bits, type_tag); bool not_text = false; - for(u32bit j = 0; j != bits.size(); j++) - if(!isgraph(bits[j]) && !isspace(bits[j])) + for(size_t i = 0; i != bits.size(); ++i) + if(!isgraph(bits[i]) && !isspace(bits[i])) not_text = true; Pipe pipe(((not_text) ? new Hex_Encoder : 0)); @@ -213,14 +189,14 @@ void decode(BER_Decoder& decoder, u32bit level) 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)); + for(size_t i = 0; i != bits.size(); ++i) + for(size_t j = 0; j != 8; ++j) + bit_set.push_back((bool)((bits[bits.size()-i-1] >> (7-j)) & 1)); std::string bit_str; - for(u32bit j = 0; j != bit_set.size(); j++) + for(size_t i = 0; i != bit_set.size(); ++i) { - bool the_bit = bit_set[bit_set.size()-j-1]; + bool the_bit = bit_set[bit_set.size()-i-1]; if(!the_bit && bit_str.size() == 0) continue; @@ -260,15 +236,15 @@ void decode(BER_Decoder& decoder, u32bit level) } } -void emit(const std::string& type, u32bit level, u32bit length, +void emit(const std::string& type, size_t level, size_t length, const std::string& value) { - const u32bit LIMIT = 128; - const u32bit BIN_LIMIT = 64; + const size_t LIMIT = 128; + const size_t BIN_LIMIT = 64; int written = 0; - written += printf(" d=%2d, l=%4d: ", level, length); - for(u32bit j = INITIAL_LEVEL; j != level; j++) + written += printf(" d=%2d, l=%4d: ", (int)level, (int)length); + for(size_t i = INITIAL_LEVEL; i != level; ++i) written += printf(" "); written += printf("%s ", type.c_str()); diff --git a/doc/examples/bcrypt.cpp b/doc/examples/bcrypt.cpp index 27a98cf33..4154b26ad 100644 --- a/doc/examples/bcrypt.cpp +++ b/doc/examples/bcrypt.cpp @@ -1,10 +1,3 @@ -/* -* Bcrypt example -* (C) 2011 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - #include <botan/botan.h> #include <botan/bcrypt.h> #include <iostream> diff --git a/doc/examples/ca.cpp b/doc/examples/ca.cpp index 25a3b5a03..6fd2eb15b 100644 --- a/doc/examples/ca.cpp +++ b/doc/examples/ca.cpp @@ -1,20 +1,3 @@ -/* -* (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> using namespace Botan; diff --git a/doc/examples/dh.cpp b/doc/examples/dh.cpp index 652c7b136..8d163303a 100644 --- a/doc/examples/dh.cpp +++ b/doc/examples/dh.cpp @@ -1,9 +1,3 @@ -/* -* (C) 2009-2010 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - #include <botan/botan.h> #include <botan/dh.h> #include <botan/pubkey.h> @@ -14,41 +8,36 @@ using namespace Botan; int main() { - Botan::LibraryInitializer init; - try { + LibraryInitializer init; + AutoSeeded_RNG rng; // Alice and Bob agree on a DH domain to use - DL_Group shared_domain("modp/ietf/1024"); + DL_Group shared_domain("modp/ietf/2048"); - // Alice creates a DH key and sends (the public part) to Bob + // Alice creates a DH key DH_PrivateKey private_a(rng, shared_domain); - // Alice sends to Bob her public key: - MemoryVector<byte> public_a = private_a.public_value(); - // Bob creates a key with a matching group DH_PrivateKey private_b(rng, shared_domain); + // 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(); - PK_Key_Agreement ka1(private_a, "KDF2(SHA-1)"); - PK_Key_Agreement ka2(private_b, "KDF2(SHA-1)"); - - /* - * Preferably, include some salt or parameter that binds this key - * generation to the current session (for instance a session - * identifier, if guaranteed unique, would be a good choice). Or - * anything else that both sides can agree on that will never - * repeat. - */ - const std::string ka_salt = "alice and bob agree on a key"; + // Now Alice performs the key agreement operation + PK_Key_Agreement ka_alice(private_a, "KDF2(SHA-256)"); + SymmetricKey alice_key = ka_alice.derive_key(32, public_b, session_param); - SymmetricKey alice_key = ka1.derive_key(32, public_b, ka_salt); - SymmetricKey bob_key = ka2.derive_key(32, public_a, ka_salt); + // Bob does the same: + PK_Key_Agreement ka_bob(private_b, "KDF2(SHA-256)"); + SymmetricKey bob_key = ka_bob.derive_key(32, public_a, session_param); if(alice_key == bob_key) { diff --git a/doc/examples/dsa_kgen.cpp b/doc/examples/dsa_kgen.cpp index fe3157370..fc5b7b501 100644 --- a/doc/examples/dsa_kgen.cpp +++ b/doc/examples/dsa_kgen.cpp @@ -1,13 +1,3 @@ -/* -* (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> @@ -20,24 +10,24 @@ using namespace Botan; 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 { + if(argc != 1 && argc != 2) + { + std::cout << "Usage: " << argv[0] << " [passphrase]" << std::endl; + return 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; + } + + Botan::LibraryInitializer init; + AutoSeeded_RNG rng; DL_Group group(rng, DL_Group::DSA_Kosherizer, 2048, 256); diff --git a/doc/examples/dsa_sign.cpp b/doc/examples/dsa_sign.cpp index 5f02c0dc1..3511eacfa 100644 --- a/doc/examples/dsa_sign.cpp +++ b/doc/examples/dsa_sign.cpp @@ -1,10 +1,3 @@ -/* -* DSA signature generation example -* (C) 2009 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - #include <iostream> #include <iomanip> #include <fstream> @@ -14,6 +7,7 @@ #include <botan/botan.h> #include <botan/pubkey.h> #include <botan/dsa.h> +#include <botan/base64.h> using namespace Botan; const std::string SUFFIX = ".sig"; @@ -66,12 +60,10 @@ int main(int argc, char* argv[]) DataSource_Stream in(message); byte buf[4096] = { 0 }; - while(u32bit got = in.read(buf, sizeof(buf))) + while(size_t 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; + sigfile << base64_encode(signer.signature(rng)) << "\n"; } catch(std::exception& e) { diff --git a/doc/examples/dsa_ver.cpp b/doc/examples/dsa_ver.cpp index a666259c1..9cb85740e 100644 --- a/doc/examples/dsa_ver.cpp +++ b/doc/examples/dsa_ver.cpp @@ -1,18 +1,3 @@ -/* -* (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> @@ -45,28 +30,30 @@ int main(int argc, char* argv[]) 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; - } + try { + Botan::LibraryInitializer init; - std::ifstream sigfile(argv[3]); - if(!sigfile) - { - std::cout << "Couldn't read the signature file." << 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; + } + + 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"; @@ -79,10 +66,10 @@ int main(int argc, char* argv[]) DataSource_Stream in(message); byte buf[4096] = { 0 }; - while(u32bit got = in.read(buf, sizeof(buf))) + while(size_t got = in.read(buf, sizeof(buf))) ver.update(buf, got); - bool ok = ver.check_signature(sig); + const bool ok = ver.check_signature(sig); if(ok) std::cout << "Signature verified\n"; diff --git a/doc/examples/eax_tv.txt b/doc/examples/eax.vec index 95cd7c1ab..95cd7c1ab 100644 --- a/doc/examples/eax_tv.txt +++ b/doc/examples/eax.vec diff --git a/doc/examples/eax_test.cpp b/doc/examples/eax_test.cpp index 32311800d..b43861132 100644 --- a/doc/examples/eax_test.cpp +++ b/doc/examples/eax_test.cpp @@ -236,7 +236,7 @@ void run_tests(std::istream& in) int main() { - std::ifstream in("eax_tv.txt"); + std::ifstream in("eax.vec"); Botan::LibraryInitializer init; diff --git a/doc/examples/ecdsa.cpp b/doc/examples/ecdsa.cpp index df1e1b93a..1607107eb 100644 --- a/doc/examples/ecdsa.cpp +++ b/doc/examples/ecdsa.cpp @@ -21,7 +21,7 @@ int main() { AutoSeeded_RNG rng; - EC_Domain_Params params("1.3.132.0.8"); + EC_Domain_Params params("secp160r1"); ECDSA_PrivateKey ecdsa(rng, params); diff --git a/doc/examples/fpe.cpp b/doc/examples/fpe.cpp index 9b18d4879..029a761e7 100644 --- a/doc/examples/fpe.cpp +++ b/doc/examples/fpe.cpp @@ -1,17 +1,6 @@ -/* -* (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/botan.h> +#include <botan/fpe_fe1.h> #include <botan/sha160.h> -#include <botan/init.h> using namespace Botan; @@ -81,7 +70,7 @@ u64bit encrypt_cc_number(u64bit cc_number, u64bit cc_ranked = cc_rank(cc_number); - BigInt c = fpe_encrypt(n, cc_ranked, key, sha1(acct_name)); + BigInt c = FPE::fe1_encrypt(n, cc_ranked, key, sha1(acct_name)); if(c.bits() > 50) throw std::runtime_error("FPE produced a number too large"); @@ -100,7 +89,7 @@ u64bit decrypt_cc_number(u64bit enc_cc, u64bit cc_ranked = cc_rank(enc_cc); - BigInt c = fpe_decrypt(n, cc_ranked, key, sha1(acct_name)); + BigInt c = FPE::fe1_decrypt(n, cc_ranked, key, sha1(acct_name)); if(c.bits() > 50) throw std::runtime_error("FPE produced a number too large"); @@ -130,7 +119,7 @@ int main(int argc, char* argv[]) 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. */ diff --git a/doc/examples/pkcs10.cpp b/doc/examples/pkcs10.cpp index 3f5ec8e05..b5ad1d1dd 100644 --- a/doc/examples/pkcs10.cpp +++ b/doc/examples/pkcs10.cpp @@ -1,9 +1,3 @@ -/* -* (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> @@ -31,9 +25,6 @@ int main(int argc, char* argv[]) 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]); @@ -45,18 +36,8 @@ int main(int argc, char* argv[]) 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); + PKCS10_Request req = X509::create_cert_req(opts, priv_key, + "SHA-256", rng); std::ofstream req_file("req.pem"); req_file << req.PEM_encode(); diff --git a/doc/python/cipher.py b/doc/examples/python/cipher.py index 1be2759ae..1be2759ae 100755 --- a/doc/python/cipher.py +++ b/doc/examples/python/cipher.py diff --git a/doc/python/cryptobox.py b/doc/examples/python/cryptobox.py index f76ed6bc3..f76ed6bc3 100755 --- a/doc/python/cryptobox.py +++ b/doc/examples/python/cryptobox.py diff --git a/doc/python/nisttest.py b/doc/examples/python/nisttest.py index 3ea8fda0f..1260b1226 100755 --- a/doc/python/nisttest.py +++ b/doc/examples/python/nisttest.py @@ -47,7 +47,7 @@ def main(): results[test] = result return results - results = load_results('results.txt') + results = load_results('results.vec') for root, dirs, files in os.walk('../../checks/nist_tests/tests'): if files: diff --git a/doc/python/results.txt b/doc/examples/python/results.vec index 7a3824001..7a3824001 100644 --- a/doc/python/results.txt +++ b/doc/examples/python/results.vec diff --git a/doc/python/rng_test.py b/doc/examples/python/rng_test.py index 06c79b84e..06c79b84e 100755 --- a/doc/python/rng_test.py +++ b/doc/examples/python/rng_test.py diff --git a/doc/python/rsa.py b/doc/examples/python/rsa.py index 8ca95ff8b..8ca95ff8b 100755 --- a/doc/python/rsa.py +++ b/doc/examples/python/rsa.py diff --git a/doc/examples/readme.txt b/doc/examples/readme.txt deleted file mode 100644 index fb6a03ddf..000000000 --- a/doc/examples/readme.txt +++ /dev/null @@ -1,77 +0,0 @@ -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/rsa_kgen.cpp b/doc/examples/rsa_kgen.cpp index f4566263b..a1f0fe71d 100644 --- a/doc/examples/rsa_kgen.cpp +++ b/doc/examples/rsa_kgen.cpp @@ -1,15 +1,3 @@ -/* -* (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> @@ -29,25 +17,25 @@ int main(int argc, char* argv[]) return 1; } - u32bit bits = std::atoi(argv[1]); + const size_t 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 { + 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; + } + AutoSeeded_RNG rng; RSA_PrivateKey key(rng, bits); diff --git a/doc/examples/self_sig.cpp b/doc/examples/self_sig.cpp index 6710cfb51..64b778b71 100644 --- a/doc/examples/self_sig.cpp +++ b/doc/examples/self_sig.cpp @@ -1,17 +1,3 @@ -/* -* (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> @@ -49,7 +35,7 @@ int main(int argc, char* argv[]) { AutoSeeded_RNG rng; - RSA_PrivateKey key(rng, 1024); + RSA_PrivateKey key(rng, 2048); std::ofstream priv_key("private.pem"); priv_key << PKCS8::PEM_encode(key, rng, argv[1]); diff --git a/doc/examples/socket.h b/doc/examples/socket.h new file mode 100644 index 000000000..f7ce98fea --- /dev/null +++ b/doc/examples/socket.h @@ -0,0 +1,257 @@ +/* +* 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> + +#if defined(_MSC_VER) + #define SOCKET_IS_WINSOCK 1 +#endif + +#if !defined(SOCKET_IS_WINSOCK) + #define SOCKET_IS_WINSOCK 0 +#endif + +#if SOCKET_IS_WINSOCK + #include <winsock.h> + + typedef SOCKET socket_t; + const socket_t invalid_socket = INVALID_SOCKET; + #define socket_error_code WSAGetLastError() + typedef int ssize_t; + + class SocketInitializer + { + public: + SocketInitializer() + { + WSADATA wsadata; + WSAStartup(MAKEWORD(2, 2), &wsadata); + } + + ~SocketInitializer() + { + WSACleanup(); + } + }; +#else + #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> + + typedef int socket_t; + const socket_t invalid_socket = -1; + #define socket_error_code errno + #define closesocket close + + class SocketInitializer {}; +#endif + +#if !defined(MSG_NOSIGNAL) + #define MSG_NOSIGNAL 0 +#endif + +#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 != invalid_socket) + { + if(::closesocket(sockfd) != 0) + throw std::runtime_error("Socket::close failed"); + sockfd = invalid_socket; + } + } + + Socket(socket_t fd, const std::string& peer_id = "") : + peer(peer_id), sockfd(fd) + { + } + + Socket(const std::string&, unsigned short); + ~Socket() { close(); } + private: + std::string peer; + socket_t sockfd; + }; + +class Server_Socket + { + public: + /** + * Accept a new connection + */ + Socket* accept() + { + socket_t retval = ::accept(sockfd, 0, 0); + if(retval == invalid_socket) + throw std::runtime_error("Server_Socket: accept failed"); + return new Socket(retval); + } + + void close() + { + if(sockfd != invalid_socket) + { + if(::closesocket(sockfd) != 0) + throw std::runtime_error("Server_Socket::close failed"); + sockfd = invalid_socket; + } + } + + Server_Socket(unsigned short); + ~Server_Socket() { close(); } + private: + socket_t sockfd; + }; + +/** +* Unix Socket Constructor +*/ +Socket::Socket(const std::string& host, unsigned short port) : peer(host) + { + sockfd = invalid_socket; + + 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"); + + socket_t fd = ::socket(PF_INET, SOCK_STREAM, 0); + if(fd == invalid_socket) + 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) + { + ::closesocket(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 == invalid_socket) + throw std::runtime_error("Socket::read: Socket not connected"); + + size_t got = 0; + + while(length) + { + ssize_t this_time = ::recv(sockfd, (char*)buf + got, + length, MSG_NOSIGNAL); + + if(this_time == 0) + break; + + if(this_time == -1) + { + if(socket_error_code == 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 == invalid_socket) + throw std::runtime_error("Socket::write: Socket not connected"); + + size_t offset = 0; + while(length) + { + ssize_t sent = ::send(sockfd, (const char*)buf + offset, + length, MSG_NOSIGNAL); + + if(sent == -1) + { + if(socket_error_code == 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 = invalid_socket; + + socket_t fd = ::socket(PF_INET, SOCK_STREAM, 0); + if(fd == invalid_socket) + 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) + { + ::closesocket(fd); + throw std::runtime_error("Server_Socket: bind failed"); + } + + if(::listen(fd, 100) != 0) // FIXME: totally arbitrary + { + ::closesocket(fd); + throw std::runtime_error("Server_Socket: listen failed"); + } + + sockfd = fd; + } + +#endif diff --git a/doc/examples/tls_client.cpp b/doc/examples/tls_client.cpp index 10ead20cc..cedfe1ca8 100644 --- a/doc/examples/tls_client.cpp +++ b/doc/examples/tls_client.cpp @@ -1,12 +1,6 @@ -/* -* (C) 2008 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/init.h> +#include <botan/botan.h> #include <botan/tls_client.h> -#include <botan/unx_sock.h> +#include "socket.h" using namespace Botan; @@ -41,23 +35,24 @@ int main(int argc, char* argv[]) try { - LibraryInitializer init; + LibraryInitializer botan_init; std::string host = argv[1]; u32bit port = argc == 3 ? Botan::to_u32bit(argv[2]) : 443; printf("Connecting to %s:%d...\n", host.c_str(), port); - Unix_Socket sock(argv[1], port); + SocketInitializer socket_init; + + Socket sock(argv[1], port); - std::auto_ptr<Botan::RandomNumberGenerator> rng( - Botan::RandomNumberGenerator::make_rng()); + AutoSeeded_RNG 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); + policy, rng); printf("Handshake extablished...\n"); @@ -68,17 +63,18 @@ int main(int argc, char* argv[]) std::string http_command = "GET / HTTP/1.0\r\n\r\n"; #endif - tls.write((const byte*)http_command.c_str(), http_command.length()); + tls.write((const Botan::byte*)http_command.c_str(), + http_command.length()); - u32bit total_got = 0; + size_t total_got = 0; while(true) { if(tls.is_closed()) break; - byte buf[16+1] = { 0 }; - u32bit got = tls.read(buf, sizeof(buf)-1); + Botan::byte buf[128+1] = { 0 }; + size_t got = tls.read(buf, sizeof(buf)-1); printf("%s", buf); fflush(0); diff --git a/doc/examples/tls_server.cpp b/doc/examples/tls_server.cpp index da13953f8..153b26d04 100644 --- a/doc/examples/tls_server.cpp +++ b/doc/examples/tls_server.cpp @@ -1,17 +1,12 @@ -/* -* (C) 2008-2010 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - #include <botan/botan.h> #include <botan/tls_server.h> -#include <botan/unx_sock.h> #include <botan/rsa.h> #include <botan/dsa.h> #include <botan/x509self.h> +#include "socket.h" + using namespace Botan; #include <stdio.h> @@ -34,9 +29,9 @@ class Server_TLS_Policy : public TLS_Policy return true; } }; + int main(int argc, char* argv[]) { - int port = 4433; if(argc == 2) @@ -44,7 +39,8 @@ int main(int argc, char* argv[]) try { - LibraryInitializer init; + LibraryInitializer botan_init; + SocketInitializer socket_init; AutoSeeded_RNG rng; @@ -57,7 +53,7 @@ int main(int argc, char* argv[]) X509_Certificate cert = X509::create_self_signed_cert(options, key, "SHA-1", rng); - Unix_Server_Socket listener(port); + Server_Socket listener(port); Server_TLS_Policy policy; @@ -86,12 +82,12 @@ int main(int argc, char* argv[]) printf("Writing some text\n"); char msg[] = "Foo\nBar\nBaz\nQuux\n"; - tls.write((const byte*)msg, strlen(msg)); + tls.write((const Botan::byte*)msg, strlen(msg)); printf("Now trying a read...\n"); char buf[1024] = { 0 }; - u32bit got = tls.read((byte*)buf, sizeof(buf)-1); + u32bit got = tls.read((Botan::byte*)buf, sizeof(buf)-1); printf("%d: '%s'\n", got, buf); tls.close(); diff --git a/doc/examples/x509info.cpp b/doc/examples/x509info.cpp deleted file mode 100644 index b22b4ebd8..000000000 --- a/doc/examples/x509info.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* -* 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/faq.txt b/doc/faq.txt new file mode 100644 index 000000000..4ff5457bb --- /dev/null +++ b/doc/faq.txt @@ -0,0 +1,209 @@ + +Frequently Asked Questions +======================================== + +What is this thing? +---------------------------------------- + +Botan is a library written in C++ which provides a fairly high level +and C++-ish interface to a number of different crypto algorithms. In +addition to the bare algorithms there is also support for number of +standards and de-facto standards like X.509v3 certificates, and +various useful constructs like format-preserving encryption, all or +nothing transforms, and secret splitting. + +.. _devel_vs_stable: + +Which release should I use? +---------------------------------------- + +The library is normally released along two different trees, termed +stable and development. The stable tree is a branch off the main line, +and typically only sees bug fixes; almost all new development occurs +in the unstable/development releases. The primary issue is not +stability of the program (bugs of course do occur, and are more likely +to occur in code that is more in flux), but rather stability of API +and ABI. In particular, you should not expect any level of ABI +stability between releases on the development branch, and API changes +may be made without notice. Feel free to send comments on API changes, +or API problems, to the list. + +If you don't want to have to worry about tracking a moving target, and +just want something that works, you'll probably prefer using the +stable releases. If you want to get the latest features, the +development releases are the obvious choice. + +If you want to ship a binary that is usable out of the box on a Linux +distro that ships botan, you'll probably want to match versions with +that distro; as of this writing most ship with 1.8. + +If you're building an application that will embed botan into it +(without relying on a shared library), you want to use an amalgamation +build, which basically turns botan into a single header and a single +source file which you can easily include in your existing application +build. In this case you can pick which ever tree you prefer. + +The self-test program can't locate the library +----------------------------------------------- + +Are you sure either the current working directory ('.') or the +directory botan is building into are in the dynamic library path? On +many Unix systems this is controlled by the ``LD_LIBRARY_PATH`` +variable. You can add the currently directory to the list of +directories to search with this Bourne shell command:: + + $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. + +If you install the library into a well known location like +``/usr/local/lib``, then probably no particular +``LD_LIBRARY_PATH`` needs to be set. + +My program aborts with any message +---------------------------------------- + +Does your main function wrap all code inside a try/catch block? If an +exception is thrown and is not caught, many C++ runtimes simply crash +the process without providing any sort of diagnostic. + +Is the library thread-safe? +---------------------------------------- + +Yes, botan is thread safe. However, because mutual exclusion depends +on OS specific code, you must load a module to help. POSIX threads and +Win32 critical sections are both supported out of the box, other +thread libraries are very easy to add. To enable thread safe +operation, include "thread_safe" in the string you pass to +``Botan::LibraryInitializer`` constructor. If for whatever reason a +working mutex implementation cannot be found, LibraryInitializer will +throw an exception rather than continue operating in a bad state. + +How do I load this key generated by OpenSSL into botan? +-------------------------------------------------------- + +The encrypted key format used by the ``openssl`` command line tool is +undocumented and apparently specific to OpenSSL. The easiest approach +is to convert it to the (standard) PKCS #8 format, using:: + + openssl pkcs8 -topk8 -in my_key.pem + +Add ``-nocrypt`` to the command line if you want the resulting PKCS #8 +file to be unencrypted, otherwise it will ask you for a new password +to use. + +For unencrypted keys, you can also manually decode the parameters +using the existing PEM and BER support; see `this post +<http://lists.randombit.net/pipermail/botan-devel/2010-June/001156.html>`_ +to the dev list for an example. + +Is botan FIPS 140 certified? +---------------------------------------- + +No version of botan has been certified under FIPS 140. This is +unlikely to happen unless/until an organization is willing to fund and +shepherd the validation process, which typically requires several +months and many thousands of dollars. + +Is this thing safe to use? +---------------------------------------- + +The primary author/maintainer (Jack Lloyd) has 5+ years of experience +reviewing code for security flaws, and has additionally performed +several FIPS 140 validations of hardware and software crypto +implementations. However the library has never undergone an +*impartial* third-party security review, and thus it is entirely +possible/probable that a number of exploitable flaws remain in the +source. (If your company is interested in handling such a review, +please contact the maintainers). + +There has been one known security flaw. Between versions 0.7.8 +(released Feb 2002) and 1.3.7 (released Dec 2003), the ``es_unix`` +module, which runs Unix programs to gather entropy for seeding a +random number generator, ran programs by invoking the ``popen`` +library function with commands with no leading directory names. This +means setuid or setgid programs that used this entropy source could be +tricked into executing arbitrary programs via manipulation of the PATH +variable. Later versions will only search through specific (presumed +safe) directories like ``/usr/bin``; the list of directories to search +can be controlled by the application. + +Is botan vulnerable to timing attacks? +---------------------------------------- + +Botan's public key implementations do make some attempt to defend +against timing attacks; random blinding is used to protect all RSA, +Rabin-Williams, ElGamal, and Diffie-Hellman private key operations. + +Public key algorithms implemented using the Chinese Remainder Theorem +(RSA and Rabin-Williams) are subject to a catastrophic failure: if a +computational error (either induced by an attacker or merely +accidental) occurs during the private key operation, the private key +can be revealed. Other, more subtle, fault attacks are possible against +other schemes. For this reason, private key operations are checked +for consistency with the public key - if the results are not +consistent, then an exception is thrown indicating an error has +occurred rather than release information that might compromise the +key. + +AES implementations are usually quite vulnerable to timing attacks. +The table based implementation of AES included in botan uses small +tables in the first and last rounds which makes such attacks somewhat +more difficult. Alternate implementations of AES using SSSE3 and +AES-NI instruction sets are also included, and run in constant time, +but of course require a processor that supports these instruction +sets. + +I think I've found a security flaw. What should I do? +------------------------------------------------------------ + +You can do any combination of: + +* Contact the current lead maintainer personally; currently + `Jack Lloyd <http://www.randombit.net>`_ + (`personal PGP key` <http://www.randombit.net/pgpgkey.html`_) + +* Email the `development list + <http://lists.randombit.net/mailman/listinfo/botan-devel>`_ + +* File a bug in `Bugzilla <http://bugs.randombit.net/>`_ + +Does botan support SSL/TLS, SSH, S/MIME, OpenPGP... +------------------------------------------------------------ + +Support for SSL/TLS is included in version 1.9.4 and later. Currently +SSLv3 and TLS 1.0 and 1.1 are supported. + +`NetSieben SSH <http://netsieben.com/products/ssh/>`_ is an open +source SSHv2 implementation that uses botan. + +A preliminary and very incomplete implementation of CMS (the crypto +layer underlying S/MIME) is included in ``src/cms``, but it needs a +lot of love and attention before being truly useful. + +There is currently no support for OpenPGP. + +Will it work on my platform XYZ?? +---------------------------------------- + +The most common stumbling block is a compiler that is buggy or can't +handle modern C++ (specifically, C++98). Check out the `build list +<http://botan.randombit.net/builds.html>`_ for a sense of which +platforms are actively being tested. + +I'm not feeling this, what can I use instead? +------------------------------------------------------------ + +* `Crypto++ <http://www.cryptopp.com/>`_ is another C++ crypto + library. Its API is more heavily based on templates and in general + has a very different design philosophy from botan - so if you feel + botan's API is not a good match, you may well like Crypto++. + +* `OpenSSL <http://www.openssl.org>`_ is written in C and mostly + targeted to being an SSL/TLS implementation but there is a lot of + other stuff in there as well. + +* `XySSL <http://www.ohloh.net/projects/xyssl>`_ is a C library + providing a very small footprint crypto library and SSL + implementation. + +* `Adam Shostack <http://www.homeport.org/~adam/crypto/>`_ maintains a + (somewhat out of date) list of open source crypto libraries. diff --git a/doc/filters.txt b/doc/filters.txt new file mode 100644 index 000000000..2355005aa --- /dev/null +++ b/doc/filters.txt @@ -0,0 +1,780 @@ + +Information Flow: Pipes and Filters +======================================== + +Many common uses of cryptography involve processing one or more +streams of data. Botan provides services that make setting up data +flows through various operations, such as compression, encryption, and +base64 encoding. Each of these operations is implemented in what are +called *filters* in Botan. A set of filters are created and placed into +a *pipe*, and information "flows" through the pipe until it reaches +the end, where the output is collected for retrieval. If you're +familiar with the Unix shell environment, this design will sound quite +familiar. + +Here is an example that uses a pipe to base64 encode some strings:: + + Pipe pipe(new Base64_Encoder); // pipe owns the pointer + pipe.start_msg(); + pipe.write("message 1"); + pipe.end_msg(); // flushes buffers, increments message number + + // process_msg(x) is start_msg() && write(x) && end_msg() + pipe.process_msg("message2"); + + std::string m1 = pipe.read_all_as_string(0); // "message1" + std::string m2 = pipe.read_all_as_string(1); // "message2" + +Bytestreams in the pipe are grouped into messages; blocks of data that +are processed in an identical fashion (ie, with the same sequence of +filter operations). Messages are delimited by calls to ``start_msg`` +and ``end_msg``. Each message in a pipe has its own identifier, which +currently is an integer that increments up from zero. + +The ``Base64_Encoder`` was allocated using ``new``; but where was it +deallocated? When a filter object is passed to a ``Pipe``, the pipe +takes ownership of the object, and will deallocate it when it is no +longer needed. + +There are two different ways to make use of messages. One is to send +several messages through a ``Pipe`` without changing the ``Pipe`` +configuration, so you end up with a sequence of messages; one use of +this would be to send a sequence of identically encrypted UDP packets, +for example (note that the *data* need not be identical; it is just +that each is encrypted, encoded, signed, etc in an identical +fashion). Another is to change the filters that are used in the +``Pipe`` between each message, by adding or removing filters; +functions that let you do this are documented in the Pipe API section. + +Botan has about 40 filters that perform different operations on data. +Here's code that uses one of them to encrypt a string with AES:: + + AutoSeeded_RNG rng, + SymmetricKey key(rng, 16); // a random 128-bit key + InitializationVector iv(rng, 16); // a random 128-bit IV + + // The algorithm we want is specified by a string + Pipe pipe(get_cipher("AES-128/CBC", key, iv, ENCRYPTION)); + + pipe.process_msg("secrets"); + pipe.process_msg("more secrets"); + + MemoryVector<byte> c1 = pipe.read_all(0); + + byte c2[4096] = { 0 }; + size_t got_out = pipe.read(c2, sizeof(c2), 1); + // use c2[0...got_out] + +Note the use of ``AutoSeeded_RNG``, which is a random number +generator. If you want to, you can explicitly set up the random number +generators and entropy sources you want to, however for 99% of cases +``AutoSeeded_RNG`` is preferable. + +``Pipe`` also has convenience methods for dealing with +``std::iostream``. Here is an example of those, using the +``Bzip_Compression`` filter (included as a module; if you have bzlib +available, check the build instructions for how to enable it) to +compress a file:: + + std::ifstream in("data.bin", std::ios::binary) + std::ofstream out("data.bin.bz2", std::ios::binary) + + Pipe pipe(new Bzip_Compression); + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + out << pipe; + +However there is a hitch to the code above; the complete contents of +the compressed data will be held in memory until the entire message +has been compressed, at which time the statement ``out << pipe`` is +executed, and the data is freed as it is read from the pipe and +written to the file. But if the file is very large, we might not have +enough physical memory (or even enough virtual memory!) for that to be +practical. So instead of storing the compressed data in the pipe for +reading it out later, we divert it directly to the file:: + + std::ifstream in("data.bin", std::ios::binary) + std::ofstream out("data.bin.bz2", std::ios::binary) + + Pipe pipe(new Bzip_Compression, new DataSink_Stream(out)); + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + +This is the first code we've seen so far that uses more than one +filter in a pipe. The output of the compressor is sent to the +``DataSink_Stream``. Anything written to a ``DataSink_Stream`` is +written to a file; the filter produces no output. As soon as the +compression algorithm finishes up a block of data, it will send it +along to the sink filter, which will immediately write it to the +stream; if you were to call ``pipe.read_all()`` after +``pipe.end_msg()``, you'd get an empty vector out. This is +particularly useful for cases where you are processing a large amount +of data, as it means you don't have to store everything in memory at +once. + +Here's an example using two computational filters:: + + AutoSeeded_RNG rng, + SymmetricKey key(rng, 32); + InitializationVector iv(rng, 16); + + Pipe encryptor(get_cipher("AES/CBC/PKCS7", key, iv, ENCRYPTION), + new Base64_Encoder); + + encryptor.start_msg(); + file >> encryptor; + encryptor.end_msg(); // flush buffers, complete computations + std::cout << encryptor; + +You can read from a pipe while you are still writing to it, which +allows you to bound the amount of memory that is in use at any one +time. A common idiom for this is:: + + pipe.start_msg(); + SecureBuffer<byte, 4096> buffer; + while(infile.good()) + { + infile.read((char*)&buffer[0], buffer.size()); + const size_t got_from_infile = infile.gcount(); + pipe.write(buffer, got_from_infile); + + if(infile.eof()) + pipe.end_msg(); + + while(pipe.remaining() > 0) + { + const size_t buffered = pipe.read(buffer, buffer.size()); + outfile.write((const char*)&buffer[0], buffered); + } + } + if(infile.bad() || (infile.fail() && !infile.eof())) + throw Some_Exception(); + +Fork +--------------------------------- + +It is common that you might receive some data and want to perform more +than one operation on it (ie, encrypt it with Serpent and calculate +the SHA-256 hash of the plaintext at the same time). That's where +``Fork`` comes in. ``Fork`` is a filter that takes input and passes it +on to *one or more* filters that are attached to it. ``Fork`` changes +the nature of the pipe system completely: instead of being a linked +list, it becomes a tree or acyclic graph. + +Each filter in the fork is given its own output buffer, and thus its +own message. For example, if you had previously written two messages +into a pipe, then you start a new one with a fork that has three +paths of filter's inside it, you add three new messages to the +pipe. The data you put into the pipe is duplicated and sent +into each set of filter and the eventual output is placed into a +dedicated message slot in the pipe. + +Messages in the pipe are allocated in a depth-first manner. This is only +interesting if you are using more than one fork in a single pipe. +As an example, consider the following:: + + Pipe pipe(new Fork( + new Fork( + new Base64_Encoder, + new Fork( + NULL, + new Base64_Encoder + ) + ), + new Hex_Encoder + ) + ); + +In this case, message 0 will be the output of the first +``Base64_Encoder``, message 1 will be a copy of the input (see below +for how fork interprets NULL pointers), message 2 will be the output +of the second ``Base64_Encoder``, and message 3 will be the output of +the ``Hex_Encoder``. This results in message numbers being allocated +in a top to bottom fashion, when looked at on the screen. However, +note that there could be potential for bugs if this is not +anticipated. For example, if your code is passed a filter, and you +assume it is a "normal" one that only uses one message, your message +offsets would be wrong, leading to some confusion during output. + +If Fork's first argument is a null pointer, but a later argument is +not, then Fork will feed a copy of its input directly through. Here's +a case where that is useful:: + + // have std::string ciphertext, auth_code, key, iv, mac_key; + + Pipe pipe(new Base64_Decoder, + get_cipher("AES-128", key, iv, DECRYPTION), + new Fork( + 0, // this message gets ciphertext + new MAC_Filter("HMAC(SHA-1)", mac_key) + ) + ); + + pipe.process_msg(ciphertext); + std::string plaintext = pipe.read_all_as_string(0); + SecureVector<byte> mac = pipe.read_all(1); + + if(mac != auth_code) + error(); + +Here we wanted to not only decrypt the message, but send the decrypted +text through an additional computation, in order to compute the +authentication code. + +Any filters that are attached to the pipe after the fork are +implicitly attached onto the first branch created by the fork. For +example, let's say you created this pipe:: + + Pipe pipe(new Fork(new Hash_Filter("SHA-256"), + new Hash_Filter("SHA-512")), + new Hex_Encoder); + +And then called ``start_msg``, inserted some data, then +``end_msg``. Then ``pipe`` would contain two messages. The first one +(message number 0) would contain the SHA-256 sum of the input in hex +encoded form, and the other would contain the SHA-512 sum of the input +in raw binary. In many situations you'll want to perform a sequence of +operations on multiple branches of the fork; in which case, use +the filter described in :ref:`chain`. + +.. _chain: + +Chain +--------------------------------- + +A ``Chain`` filter creates a chain of filters and encapsulates them +inside a single filter (itself). This allows a sequence of filters to +become a single filter, to be passed into or out of a function, or to +a ``Fork`` constructor. + +You can call ``Chain``'s constructor with up to four ``Filter`` +pointers (they will be added in order), or with an array of filter +pointers and a ``size_t`` that tells ``Chain`` how many filters are in +the array (again, they will be attached in order). Here's the example +from the last section, using chain instead of relying on the implicit +passthrough the other version used:: + + Pipe pipe(new Fork( + new Chain(new Hash_Filter("SHA-256"), new Hex_Encoder), + new Hash_Filter("SHA-512") + ) + ); + +Sources and Sinks +---------------------------------------- + +Data Sources +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A ``DataSource`` is a simple abstraction for a thing that stores +bytes. This type is used heavily in the areas of the API related to +ASN.1 encoding/decoding. The following types are ``DataSource``: +``Pipe``, ``SecureQueue``, and a couple of special purpose ones: +``DataSource_Memory`` and ``DataSource_Stream``. + +You can create a ``DataSource_Memory`` with an array of bytes and a +length field. The object will make a copy of the data, so you don't +have to worry about keeping that memory allocated. This is mostly for +internal use, but if it comes in handy, feel free to use it. + +A ``DataSource_Stream`` is probably more useful than the memory based +one. Its constructors take either a ``std::istream`` or a +``std::string``. If it's a stream, the data source will use the +``istream`` to satisfy read requests (this is particularly useful to +use with ``std::cin``). If the string version is used, it will attempt +to open up a file with that name and read from it. + +Data Sinks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A ``DataSink`` (in ``data_snk.h``) is a ``Filter`` that takes +arbitrary amounts of input, and produces no output. This means it's +doing something with the data outside the realm of what +``Filter``/``Pipe`` can handle, for example, writing it to a file +(which is what the ``DataSink_Stream`` does). There is no need for +``DataSink``s that write to a ``std::string`` or memory buffer, +because ``Pipe`` can handle that by itself. + +Here's a quick example of using a ``DataSink``, which encrypts +``in.txt`` and sends the output to ``out.txt``. There is +no explicit output operation; the writing of ``out.txt`` is +implicit:: + + DataSource_Stream in("in.txt"); + Pipe pipe(get_cipher("AES-128/CTR-BE", key, iv), + new DataSink_Stream("out.txt")); + pipe.process_msg(in); + +A real advantage of this is that even if "in.txt" is large, only as +much memory is needed for internal I/O buffers will be used. + +The Pipe API +--------------------------------- + +Initializing Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, ``Pipe`` will do nothing at all; any input placed into the +``Pipe`` will be read back unchanged. Obviously, this has limited +utility, and presumably you want to use one or more filters to somehow +process the data. First, you can choose a set of filters to initialize +the ``Pipe`` via the constructor. You can pass it either a set of up +to four filter pointers, or a pre-defined array and a length:: + + Pipe pipe1(new Filter1(/*args*/), new Filter2(/*args*/), + new Filter3(/*args*/), new Filter4(/*args*/)); + Pipe pipe2(new Filter1(/*args*/), new Filter2(/*args*/)); + + Filter* filters[5] = { + new Filter1(/*args*/), new Filter2(/*args*/), new Filter3(/*args*/), + new Filter4(/*args*/), new Filter5(/*args*/) /* more if desired... */ + }; + Pipe pipe3(filters, 5); + +This is by far the most common way to initialize a ``Pipe``. However, +occasionally a more flexible initialization strategy is necessary; +this is supported by 4 member functions. These functions may only be +used while the pipe in question is not in use; that is, either before +calling ``start_msg``, or after ``end_msg`` has been called (and no +new calls to ``start_msg`` have been made yet). + +.. cpp:function:: void Pipe::prepend(Filter* filter) + + Calling ``prepend`` will put the passed filter first in the list of + transformations. For example, if you prepend a filter implementing + encryption, and the pipe already had a filter that hex encoded the + input, then the next message processed would be first encrypted, + and *then* hex encoded. + +.. cpp:function:: void Pipe::append(Filter* filter) + + Like ``prepend``, but places the filter at the end of the message + flow. This doesn't always do what you expect if there is a fork. + +.. cpp:function:: void Pipe::pop() + + Removes the first filter in the flow. + +.. cpp:function:: void Pipe::reset() + + Removes all the filters that the pipe currently holds - it is reset + to an empty/no-op state. Any data that is being retained by the + pipe is retained after a ``reset``, and ``reset`` does not affect + message numbers (discussed later). + +Giving Data to a Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Input to a ``Pipe`` is delimited into messages, which can be read from +independently (ie, you can read 5 bytes from one message, and then all of +another message, without either read affecting any other messages). + +.. cpp:function:: void Pipe::start_msg() + + Starts a new message; if a message was already running, an exception is + thrown. After this function returns, you can call ``write``. + +.. cpp:function:: void Pipe::write(const byte* input, size_t length) + +.. cpp:function:: void Pipe::write(const MemoryRegion<byte>& input) + +.. cpp:function:: void Pipe::write(const std::string& input) + +.. cpp:function:: void Pipe::write(DataSource& input) + +.. cpp:function:: void Pipe::write(byte input) + + All versions of ``write`` write the input into the filter sequence. + If a message is not currently active, an exception is thrown. + +.. cpp:function:: void Pipe::end_msg() + + End the currently active message + +Sometimes, you may want to do only a single write per message. In this +case, you can use the ``process_msg`` series of functions, which start +a message, write their argument into the pipe, and then end the +message. In this case you would not make any explicit calls to +``start_msg``/``end_msg``. + +Pipes can also be used with the ``>>`` operator, and will accept a +``std::istream``, or on Unix systems with the ``fd_unix`` module, a +Unix file descriptor. In either case, the entire contents of the file +will be read into the pipe. + +Getting Output from a Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Retrieving the processed data from a pipe is a bit more complicated, +for various reasons. The pipe will separate each message into a +separate buffer, and you have to retrieve data from each message +independently. Each of the reader functions has a final parameter that +specifies what message to read from. If this parameter is set to +``Pipe::DEFAULT_MESSAGE``, it will read the current default message +(``DEFAULT_MESSAGE`` is also the default value of this parameter). + +Functions in ``Pipe`` related to reading include: + +.. cpp:function:: size_t Pipe::read(byte* out, size_t len) + + Reads up to ``len`` bytes into ``out``, and returns the number of + bytes actually read. + +.. cpp:function:: size_t Pipe::peek(byte* out, size_t len) + + Acts exactly like `read`, except the data is not actually read; the + next read will return the same data. + +.. cpp:function:: SecureVector<byte> Pipe::read_all() + + Reads the entire message into a buffer and returns it + +.. cpp:function:: std::string Pipe::read_all_as_string() + + Like ``read_all``, but it returns the data as a ``std::string``. + No encoding is done; if the message contains raw binary, so will + the string. + +.. cpp:function:: size_t Pipe::remaining() + + Returns how many bytes are left in the message + +.. cpp:function:: Pipe::message_id Pipe::default_msg() + + Returns the current default message number + +.. cpp:function:: Pipe::message_id Pipe::message_count() + + Returns the total number of messages currently in the pipe + +.. cpp:function:: Pipe::set_default_msg(Pipe::message_id msgno) + + Sets the default message number (which must be a valid message + number for that pipe). The ability to set the default message number + is particularly important in the case of using the file output + operations (``<<`` with a ``std::ostream`` or Unix file descriptor), + because there is no way to specify the message explicitly when using + the output operator. + +Pipe I/O for Unix File Descriptors +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is a minor feature, but it comes in handy sometimes. In all +installations of the library, Botan's ``Pipe`` object overloads the +``<<`` and ``>>`` operators for C++ iostream objects, +which is usually more than sufficient for doing I/O. + +However, there are cases where the iostream hierarchy does not map well to +local 'file types', so there is also the ability to do I/O directly with Unix +file descriptors. This is most useful when you want to read from or write to +something like a TCP or Unix-domain socket, or a pipe, since for simple file +access it's usually easier to just use C++'s file streams. + +If ``BOTAN_EXT_PIPE_UNIXFD_IO`` is defined, then you can use the +overloaded I/O operators with Unix file descriptors. For an example of this, +check out the ``hash_fd`` example, included in the Botan distribution. + +Filter Catalog +--------------------------------- + +This section documents most of the useful filters included in the +library. + +Keyed Filters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A few sections ago, it was mentioned that ``Pipe`` can process +multiple messages, treating each of them the same. Well, that was a +bit of a lie. There are some algorithms (in particular, block ciphers +not in ECB mode, and all stream ciphers) that change their state as +data is put through them. + +Naturally, you might well want to reset the keys or (in the case of +block cipher modes) IVs used by such filters, so multiple messages can +be processed using completely different keys, or new IVs, or new keys +and IVs, or whatever. And in fact, even for a MAC or an ECB block +cipher, you might well want to change the key used from message to +message. + +Enter ``Keyed_Filter``, which acts as an abstract interface for any +filter that is uses keys: block cipher modes, stream ciphers, MACs, +and so on. It has two functions, ``set_key`` and ``set_iv``. Calling +``set_key`` will set (or reset) the key used by the algorithm. Setting +the IV only makes sense in certain algorithms -- a call to ``set_iv`` +on an object that doesn't support IVs will cause an exception. You +must call ``set_key`` *before* calling ``set_iv``. + +Here's a example:: + + Keyed_Filter *aes, *hmac; + Pipe pipe(new Base64_Decoder, + // Note the assignments to the cast and hmac variables + aes = get_cipher("AES-128/CBC", aes_key, iv), + new Fork( + 0, // Read the section 'Fork' to understand this + new Chain( + hmac = new MAC_Filter("HMAC(SHA-1)", mac_key, 12), + new Base64_Encoder + ) + ) + ); + pipe.start_msg(); + // use pipe for a while, decrypt some stuff, derive new keys and IVs + pipe.end_msg(); + + aes->set_key(aes_key2); + aes->set_iv(iv2); + hmac->set_key(mac_key2); + + pipe.start_msg(); + // use pipe for some other things + pipe.end_msg(); + +There are some requirements to using ``Keyed_Filter`` that you must +follow. If you call ``set_key`` or ``set_iv`` on a filter that is +owned by a ``Pipe``, you must do so while the ``Pipe`` is +"unlocked". This refers to the times when no messages are being +processed by ``Pipe`` -- either before ``Pipe``'s ``start_msg`` is +called, or after ``end_msg`` is called (and no new call to +``start_msg`` has happened yet). Doing otherwise will result in +undefined behavior, probably silently getting invalid output. + +And remember: if you're resetting both values, reset the key *first*. + +Cipher Filters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Getting a hold of a ``Filter`` implementing a cipher is very +easy. Make sure you're including the header ``lookup.h``, and +then call ``get_cipher``. You will pass the return value +directly into a ``Pipe``. There are a couple different functions +which do varying levels of initialization: + +.. cpp:function:: Keyed_Filter* get_cipher(std::string cipher_spec, \ + SymmetricKey key, InitializationVector iv, Cipher_Dir dir) + +.. cpp:function:: Keyed_Filter* get_cipher(std::string cipher_spec, \ + SymmetricKey key, Cipher_Dir dir) + +The version that doesn't take an IV is useful for things that don't +use them, like block ciphers in ECB mode, or most stream ciphers. If +you specify a cipher spec that does want a IV, and you use the version +that doesn't take one, an exception will be thrown. The ``dir`` +argument can be either ``ENCRYPTION`` or ``DECRYPTION``. + +The cipher_spec is a string that specifies what cipher is to be +used. The general syntax for "cipher_spec" is "STREAM_CIPHER", +"BLOCK_CIPHER/MODE", or "BLOCK_CIPHER/MODE/PADDING". In the case of +stream ciphers, no mode is necessary, so just the name is +sufficient. A block cipher requires a mode of some sort, which can be +"ECB", "CBC", "CFB(n)", "OFB", "CTR-BE", or "EAX(n)". The argument to +CFB mode is how many bits of feedback should be used. If you just use +"CFB" with no argument, it will default to using a feedback equal to +the block size of the cipher. EAX mode also takes an optional bit +argument, which tells EAX how large a tag size to use~--~generally +this is the size of the block size of the cipher, which is the default +if you don't specify any argument. + +In the case of the ECB and CBC modes, a padding method can also be +specified. If it is not supplied, ECB defaults to not padding, and CBC +defaults to using PKCS #5/#7 compatible padding. The padding methods +currently available are "NoPadding", "PKCS7", "OneAndZeros", and +"CTS". CTS padding is currently only available for CBC mode, but the +others can also be used in ECB mode. + +Some example "cipher_spec arguments are: "AES-128/CBC", +"Blowfish/CTR-BE", "Serpent/XTS", and "AES-256/EAX". + +"CTR-BE" refers to counter mode where the counter is incremented as if +it were a big-endian encoded integer. This is compatible with most +other implementations, but it is possible some will use the +incompatible little endian convention. This version would be denoted +as "CTR-LE" if it were supported. + +"EAX" is a new cipher mode designed by Wagner, Rogaway, and +Bellare. It is an authenticated cipher mode (that is, no separate +authentication is needed), has provable security, and is free from +patent entanglements. It runs about half as fast as most of the other +cipher modes (like CBC, OFB, or CTR), which is not bad considering you +don't need to use an authentication code. + +Hashes and MACs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Hash functions and MACs don't need anything special when it comes to +filters. Both just take their input and produce no output until +``end_msg`` is called, at which time they complete the hash or MAC and +send that as output. + +These filters take a string naming the type to be used. If for some +reason you name something that doesn't exist, an exception will be thrown. + +.. cpp:function:: Hash_Filter::Hash_Filter(std::string hash, size_t outlen = 0) + + This constructor creates a filter that hashes its input with + ``hash``. When ``end_msg`` is called on the owning pipe, the hash is + completed and the digest is sent on to the next filter in the + pipeline. The parameter ``outlen`` specifies how many bytes of the + hash output will be passed along to the next filter when ``end_msg`` + is called. By default, it will pass the entire hash. + + Examples of names for ``Hash_Filter`` are "SHA-1" and "Whirlpool". + +.. cpp:function:: MAC_Filter::MAC_Filter(std::string mac, SymmetricKey key, size_t outlen = 0) + + This constructor takes a name for a mac, such as "HMAC(SHA-1)" or + "CMAC(AES-128)", along with a key to use. The optional ``outlen`` + works the same as in ``Hash_Filter``. + +PK Filters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are four classes in this category, ``PK_Encryptor_Filter``, +``PK_Decryptor_Filter``, ``PK_Signer_Filter``, and +``PK_Verifier_Filter``. Each takes a pointer to an object of the +appropriate type (``PK_Encryptor``, ``PK_Decryptor``, etc) that is +deleted by the destructor. These classes are found in ``pk_filts.h``. + +Three of these, for encryption, decryption, and signing are much the +same in terms of dataflow - ach of them buffers its input until the +end of the message is marked with a call to the ``end_msg`` +function. Then they encrypt, decrypt, or sign the entire input as a +single blob and send the output (the ciphertext, the plaintext, or the +signature) into the next filter. + +Signature verification works a little differently, because it needs to +know what the signature is in order to check it. You can either pass +this in along with the constructor, or call the function +``set_signature`` -- with this second method, you need to keep +a pointer to the filter around so you can send it this command. In +either case, after ``end_msg`` is called, it will try to +verify the signature (if the signature has not been set by either +method, an exception will be thrown here). It will then send a single +byte onto the next filter -- a 1 or a 0, which specifies whether the +signature verified or not (respectively). + +For more information about PK algorithms (including creating the +appropriate objects to pass to the constructors), see :doc:`pubkey`. + +Encoders +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Often you want your data to be in some form of text (for sending over +channels that aren't 8-bit clean, printing it, etc). The filters +``Hex_Encoder`` and ``Base64_Encoder`` will convert arbitrary binary +data into hex or base64 formats. Not surprisingly, you can use +``Hex_Decoder`` and ``Base64_Decoder`` to convert it back into its +original form. + +Both of the encoders can take a few options about how the data should +be formatted (all of which have defaults). The first is a ``bool`` +which says if the encoder should insert line breaks. This defaults to +false. Line breaks don't matter either way to the decoder, but it +makes the output a bit more appealing to the human eye, and a few +transport mechanisms (notably some email systems) limit the maximum +line length. + +The second encoder option is an integer specifying how long such lines +will be (obviously this will be ignored if line-breaking isn't being +used). The default tends to be in the range of 60-80 characters, but +is not specified. If you want a specific value, set it. Otherwise the +default should be fine. + +Lastly, ``Hex_Encoder`` takes an argument of type ``Case``, which can +be ``Uppercase`` or ``Lowercase`` (default is ``Uppercase``). This +specifies what case the characters A-F should be output as. The base64 +encoder has no such option, because it uses both upper and lower case +letters for its output. + +You can find the declarations for these types in ``hex_filt.h`` and +``b64_filt.h``. + +Compressors +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are two compression algorithms supported by Botan, zlib and +bzip2. Only lossless compression algorithms are currently supported by +Botan, because they tend to be the most useful for +cryptography. However, it is very reasonable to consider supporting +something like GSM speech encoding (which is lossy), for use in +encrypted voice applications. + +You should always compress *before* you encrypt, because encryption seeks +to hide the redundancy that compression is supposed to try to find and remove. + +To test for Bzip2, check to see if ``BOTAN_HAS_COMPRESSOR_BZIP2`` is +defined. If so, you can include ``botan/bzip2.h``, which will declare +a pair of ``Filter`` objects: ``Bzip2_Compression`` and +``Bzip2_Decompression``. + +You should be prepared to take an exception when using the +decompressing filter, for if the input is not valid bzip2 data, that +is what you will receive. You can specify the desired level of +compression to ``Bzip2_Compression``'s constructor as an integer +between 1 and 9, 1 meaning worst compression, and 9 meaning the +best. The default is to use 9, since small values take the same amount +of time, just use a little less memory. + +Zlib compression works much like Bzip2 compression. The only +differences in this case are that the macro is +``BOTAN_HAS_COMPRESSOR_ZLIB``, the header you need to include is +called ``botan/zlib.h`` (remember that you shouldn't just ``#include +<zlib.h>``, or you'll get the regular zlib API, which is not what you +want). The Botan classes for zlib compression/decompression are called +``Zlib_Compression`` and ``Zlib_Decompression``. + +Like Bzip2, a ``Zlib_Decompression`` object will throw an exception if +invalid (in the sense of not being in the Zlib format) data is passed +into it. + +While the zlib compression library uses the same compression algorithm +as the gzip and zip programs, the format is different. The zlib format +is defined in RFC 1950. + +Writing New Filters +--------------------------------- + +The system of filters and pipes was designed in an attempt to make it +as simple as possible to write new filter types. There are four +functions that need to be implemented by a class deriving from +``Filter``: + +.. cpp:function:: void Filter::write(const byte* input, size_t length) + + This function is what is called when a filter receives input for it + to process. The filter is not required to process the data right + away; many filters buffer their input before producing any output. A + filter will usually have ``write`` called many times during its + lifetime. + +.. cpp:function:: void Filter::send(byte* output, size_t length) + + Eventually, a filter will want to produce some output to send along + to the next filter in the pipeline. It does so by calling ``send`` + with whatever it wants to send along to the next filter. There is + also a version of ``send`` taking a single byte argument, as a + convenience. + +.. cpp:function:: void Filter::start_msg() + + Implementing this function is optional. Implement it if your filter + would like to do some processing or setup at the start of each + message, such as allocating a data structure. + +.. cpp:function:: void Filter::end_msg() + + Implementing this function is optional. It is called when it has + been requested that filters finish up their computations. The filter + should finish up with whatever computation it is working on (for + example, a compressing filter would flush the compressor and + ``send`` the final block), and empty any buffers in preparation for + processing a fresh new set of input. + +Additionally, if necessary, filters can define a constructor that +takes any needed arguments, and a destructor to deal with deallocating +memory, closing files, etc. + diff --git a/doc/fips140.tex b/doc/fips140.tex deleted file mode 100644 index 8b2004508..000000000 --- a/doc/fips140.tex +++ /dev/null @@ -1,156 +0,0 @@ -\documentclass{article} - -\setlength{\textwidth}{6.5in} -\setlength{\textheight}{9in} - -\setlength{\headheight}{0in} -\setlength{\topmargin}{0in} -\setlength{\headsep}{0in} - -\setlength{\oddsidemargin}{0in} -\setlength{\evensidemargin}{0in} - -\title{\textbf{Botan FIPS 140-2 Security Policy}} -\author{Jack Lloyd \\ - \texttt{[email protected]}} -\date{} - -\newcommand{\filename}[1]{\texttt{#1}} -\newcommand{\module}[1]{\texttt{#1}} - -\newcommand{\type}[1]{\texttt{#1}} -\newcommand{\function}[1]{\textbf{#1}} -\newcommand{\macro}[1]{\texttt{#1}} - -\begin{document} - -\maketitle - -\tableofcontents - -\parskip=5pt -%\baselineskip=15pt - -\pagebreak - -\section{Introduction} - -\emph{Note that this is a draft, and almost certainly does not comply with what -FIPS 140-2 wants (also it's incomplete). In any case, there is no way for me to -afford paying the validation lab, so this is all theoretical.} - -\emph{I would welcome comments from people who are familiar with the FIPS 140 -process. I am currently basing this off a few dozen other security policies and -the FIPS itself.} - -\subsection{Purpose} - -This document is a security policy for the Botan C++ crypto library for use in -a FIPS 140-2 Level 1 validation process. It describes how to configure and use -the library to comply with the requirements of FIPS 140-2. - -This document is non-proprietary, and may be freely reproduced and distributed -in unmodified form. - -\subsection{Product Description} - -The Botan C++ crypto library (hereafter ``Botan'' or ``the library'') is an -open source C++ class library providing a general-purpose interface to a wide -variety of cryptographic algorithms and formats (such as X.509v3 and PKCS -\#10). It runs on most Win32 and POSIX-like systems, including Windows -NT/2000/XP, MacOS X, Linux, Solaris, FreeBSD, and QNX. However, only versions -running on \emph{(goal:)} Windows XP, Linux, and Solaris have been validated by -FIPS 140-2 at this time. - -\subsection{Algorithms} - -The library contains the following FIPS Approved algorithms: RSA, DSA, DES, -TripleDES, Skipjack, AES, SHA-1, HMAC, the X9.19 DES MAC, and the FIPS 186-2 -SHA-1 RNG. Other (non-Approved) algorithms, such as MD5 and Diffie-Hellman, are -also included. - -\section{Initialization} - -Certain tests are only performed if the flag ``fips140'' is passed as part of -the initialization process to the library (the argument to -\type{LibraryInitializer} or \function{Init::initialize}). Known answer tests -and key generation self-checks for RSA and DSA are always performed, regardless -of this setting. This flag must be passed by any application which desires -using the FIPS 140 mode of operation. - -\section{Roles and Services} - -Botan supports two roles, the User and the Crypto Officer. Authentication is -not performed by the module; all authentication is implicitly done by the -operating system. - -\subsection{User Role} - -The user has the ability to access the services of the module. This role is -implicitly selected whenever the module's services are accessed. - -\subsection{Crypto Officer Role} - -The crypto officer has all of the powers of the user, and in addition has the -power to install and uninstall the module and to configure the operating -system. This role is implicitly selected whenever these actions are performed. - -\section{Key Management} - -\subsection{Key Import/Export} - -Symmetric keys can be imported and exported in either unencrypted, encrypted, -or split-knowledge forms, as the application desires. Private keys for -asymmetric algorithms can be imported and exported as either encrypted or -unencrypted PKCS \#8 structures. The library natively supports PKCS \#5 -encryption with TripleDES for encrypting private keys. - -\subsection{Key Storage} - -In no case does the library itself import or export keys from/to an external -storage device; all such operations are done explicitly by the application. It -is the responsibly of the operator to ensure than any such operations comply -with the requirements of FIPS 140-2 Level 1. - -\subsection{Key Generation} - -Keys for symmetric algorithms (such as DES, AES, and HMAC) are generated by an -Approved RNG, by generating a random byte string of the appropriate size, and -using it as a key. - -DSA keys are generated as specified in FIPS 186-2 (or not?). RSA keys are -generated as specified in ANSI X9.31 (\emph{I think...}). Diffie-Hellman keys -are generated in a manner compatible with ANSI X9.42. All newly created DSA and -RSA keys are checked with a pairwise consistency test before being returned to -the caller. A pairwise consistency check can be performed on any RSA, DSA, or -Diffie-Hellman key by calling the \function{check\_key} member function with -an argument of \type{true}. - -\subsection{Key Establishment} - -Botan supports using RSA or Diffie-Hellman to establish keys. RSA can be used -with PKCS \#1 v1.5 or OAEP padding. None of these methods are FIPS Approved, -but Annex D of FIPS 140-2 allows for their use until such time as a FIPS -Approved asymmetric key establishment method is established. - -\subsection{Key Protection / Zeroization} - -Keys are protected against external access by the operating system's memory and -process protection mechanisms. If the library is used by multiple processes at -once, the OS virtual memory mechanisms ensure that each version will have it's -own data space (and thus, keys are not shared among multiple processes). - -All keys and other sensitive materials are zeroed in memory before being -released to the system. - -On Windows systems the \function{VirtualLock} system call is used to notify the -operating system that the memory containing potentially sensitive keying -material is not swapped to disk, preventing an attacker from applying disk -forenistics techniques to recovery data. - -On Unix systems, Botan allocates memory from file-backed memory mappings, which -are thoroughly erased when the memory is freed. - -\section{References} - -\end{document} diff --git a/doc/firststep.txt b/doc/firststep.txt new file mode 100644 index 000000000..fb4eb583e --- /dev/null +++ b/doc/firststep.txt @@ -0,0 +1,107 @@ + +Getting Started +======================================== + +All declarations in the library are contained within the namespace +``Botan``, so you need to either prefix types with ``Botan::`` or add +a ``using`` declaration in your code. All examples will assume a +``using`` declaration. + +All library headers are included like so:: + + #include <botan/botan.h> + +Initializing the Library +---------------------------------------- + +There is a set of core services that the library needs access to while +it is performing requests. To ensure these are set up, you must create +an object of type + +.. cpp:class:: LibraryInitializer + +prior to making any other library calls. Typically this will be named +something like ``init`` or ``botan_init``. The object lifetime must +exceed that of all other Botan objects your application creates; for +this reason the best place to create the ``LibraryInitializer`` is at +the start of your ``main`` function, since this guarantees that it +will be created first and destroyed last (via standard C++ RAII +rules). The initializer does things like setting up the memory +allocation system and algorithm lookup tables, finding out if there is +a high resolution timer available to use, and similar such +matters. With no arguments, the library is initialized with various +default settings. So (unless you are writing threaded code; see +below), all you need is:: + + Botan::LibraryInitializer init; + +at the start of your ``main``. + +The constructor takes an optional string that specifies arguments. +Currently the only possible argument is "thread_safe", which must have +an boolean argument (for instance "thread_safe=false" or +"thread_safe=true"). If "thread_safe" is specified as true the library +will attempt to register a mutex type to properly guard access to +shared resources. However these locks do not protect individual Botan +objects: explicit locking must be used if you wish to share a single +object between threads. + +If you do not create a ``LibraryInitializer`` object, all library +operations will fail, because it will be unable to do basic things +like allocate memory or get random bits. You should never create more +than one ``LibraryInitializer``. + +Pitfalls +---------------------------------------- + +There are a few things to watch out for to prevent problems when using +the library. + +Never allocate any kind of Botan object globally. The problem with +doing this is that the constructor for such an object will be called +before the library is initialized. Many Botan objects will, in their +constructor, make one or more calls into the library global state +object. Access to this object is checked, so an exception should be +thrown (rather than a memory access violation or undetected +uninitialized object access). A rough equivalent that will work is to +keep a global pointer to the object, initializing it after creating +your ``LibraryInitializer``. Merely making the +``LibraryInitializer`` also global will probably not help, because +C++ does not make very strong guarantees about the order that such +objects will be created. + +The same rule applies for making sure the destructors of all your +Botan objects are called before the ``LibraryInitializer`` is +destroyed. This implies you can't have static variables that are Botan +objects inside functions or classes; in many C++ runtimes, these +objects will be destroyed after main has returned. + +The memory object classes (``MemoryRegion``, ``MemoryVector``, +``SecureVector``) are extremely primitive, and meant only for +secure storage of potentially sensitive data like keys. They do not +meet the requirements for an STL container object and you should not +try to use them with STL algorithms. For a general-purpose container, +use ``std::vector``. + +Use a ``try``/``catch`` block inside your ``main`` function, and catch +any ``std::exception`` throws (remember to catch by reference, as +``std::exception::what`` is polymorphic):: + + int main() + { + try + { + LibraryInitializer init; + + // ... + } + catch(std::exception& e) + { + std::cerr << e.what() << "\n"; + } + } + +This is not strictly required, but if you don't, and Botan throws an +exception, the runtime will call ``std::terminate``, which usually +calls ``abort`` or something like it, leaving you (or worse, a user of +your application) wondering what went wrong. diff --git a/doc/fpe.txt b/doc/fpe.txt new file mode 100644 index 000000000..5c035f0b7 --- /dev/null +++ b/doc/fpe.txt @@ -0,0 +1,58 @@ + +Format Preserving Encryption +======================================== + +.. versionadded:: 1.9.17 + +Format preserving encryption (FPE) refers to a set of techniques for +encrypting data such that the ciphertext has the same format as the +plaintext. For instance, you can use FPE to encrypt credit card +numbers with valid checksums such that the ciphertext is also an +credit card number with a valid checksum, or similiarly for bank +account numbers, US Social Security numbers, or even more general +mappings like English words onto other English words. + +The scheme currently implemented in botan is called FE1, and described +in the paper `Format Preserving Encryption +<http://eprint.iacr.org/2009/251>`_ by Mihir Bellare, Thomas +Ristenpart, Phillip Rogaway, and Till Stegers. FPE is an area of +ongoing standardization and it is likely that other schemes will be +included in the future. + +To use FE1, use these functions, from ``fpe_fe1.h``: + +.. cpp:function:: BigInt FPE::fe1_encrypt(const BigInt& n, const BigInt& X, \ + const SymmetricKey& key, const MemoryRegion<byte>& tweak) + + Encrypts the value *X* modulo the value *n* using the *key* and + *tweak* specified. Returns an integer less than *n*. The *tweak* is + a value that does not need to be secret that parameterizes the + encryption function. For instance, if you were encrypting a + database column with a single key, you could use a per-row-unique + integer index value as the tweak. + + To encrypt an arbitrary value using FE1, you need to use a ranking + method. Basically, the idea is to assign an integer to every value + you might encrypt. For instance, a 16 digit credit card number + consists of a 15 digit code plus a 1 digit checksum. So to encrypt + a credit card number, you first remove the checksum, encrypt the 15 + digit value modulo 10\ :sup:`15`, and then calculate what the + checksum is for the new (ciphertext) number. + +.. cpp:function:: BigInt FPE::fe1_decrypt(const BigInt& n, const BigInt& X, \ + const SymmetricKey& key, const MemoryRegion<byte>& tweak) + + Decrypts an FE1 ciphertext produced by :cpp:func:`fe1_encrypt`; the + *n*, *key* and *tweak* should be the same as that provided to the + encryption function. Returns the plaintext. + + Note that there is not any implicit authentication or checking of + data, so if you provide an incorrect key or tweak the result is + simply a random integer. + +This example encrypts a credit card number with a valid +`Luhn checksum <http://en.wikipedia.org/wiki/Luhn_algorithm>`_ to +another number with the same format, including a correct checksum. + +.. literalinclude:: examples/fpe.cpp + diff --git a/doc/indent.el b/doc/indent.el index 9811bf848..7fa2540b0 100644 --- a/doc/indent.el +++ b/doc/indent.el @@ -2,19 +2,14 @@ ; get everything perfectly correct, but it's pretty close. Copy this code into ; your .emacs file, or use M-x eval-buffer. Make sure to also set ; indent-tabs-mode to nil so spaces are inserted instead. - +; ; This style is basically Whitesmiths style with 3 space indents (the Emacs ; "whitesmith" style seems more like a weird Whitesmiths/Allman mutant style). - +; ; To activate using this style, open the file you want to edit and run this: -; M-x c-set-style <RET> and then enter "botan". Alternately, put something -; like this in your .emacs file to make it the default style: +; M-x c-set-style <RET> and then enter "botan". -; (add-hook 'c++-mode-common-hook -; (function (lambda() -; (c-add-style "botan" botan t)))) - -(setq botan '( +(setq botan-style '( (c-basic-offset . 3) (c-comment-only-line-offset . 0) (c-offsets-alist @@ -55,3 +50,6 @@ (label . 0) ) )) + +(add-hook 'c++-mode-common-hook + (function (lambda () (c-add-style "botan" botan-style nil)))) diff --git a/doc/index.txt b/doc/index.txt new file mode 100644 index 000000000..430a71f20 --- /dev/null +++ b/doc/index.txt @@ -0,0 +1,90 @@ + +Welcome +======================================== + +Botan is a :doc:`BSD-licensed <license>` crypto library for C++. It +provides applications with most any :doc:`cryptographic algorithm +<algos>` you might be looking for, along with :doc:`SSL/TLS <ssl>`, +:doc:`X.509 certificates and CRLs <x509>`, a :doc:`pipeline-style +message processing system <filters>`, and a wide variety of other +features. A third party open source implementation of `SSHv2 +<http://www.netsieben.com/products/ssh/>`_ that uses botan is also +available. In addition to C++ you can use botan from Python or Perl, +though the current bindings only wrap portions of the library. + +See the :doc:`faq` for a list of common questions and answers. + +.. only:: html and website + + See :doc:`download` for information about getting the latest version. + +The core of botan is written in C++98 with no dependencies besides the +STL and the rest of the ISO standard library, but the library also +includes optional modules which make further assumptions about their +environment, providing features such as compression (using zlib or +bzip2), entropy gathering, and secure memory allocation. Assembly +implementations of key algorithms like SHA-1 and multiple precision +integer routines for x86 and x86-64 processors are also included. + +It runs on most common operating systems and can be used with a number +of different commercial and open source compilers. The :doc:`build log +<build_log>` contains information about recently tested targets. It is +already included in most major package distributions, including +\ +`Fedora <https://admin.fedoraproject.org/pkgdb/acls/name/botan>`_, +`EPEL <http://download.fedora.redhat.com/pub/epel/beta/6/SRPMS/repoview/botan.html>`_ (for RHEL/CentOS), +`Debian <http://packages.debian.org/search?keywords=libbotan>`_, +`Ubuntu <http://packages.ubuntu.com/search?keywords=botan>`_, +`Gentoo <http://packages.gentoo.org/package/botan>`_, +`Arch Linux <http://www.archlinux.org/packages/extra/x86_64/botan/>`_, +`Slackbuild <http://slackbuilds.org/result/?search=Botan>`_, +`FreeBSD <http://www.freshports.org/security/botan>`_, +`NetBSD <ftp://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/security/botan/README.html>`_, +`Cygwin <http://cygwin.com/packages/botan/>`_, +`MacPorts <http://www.macports.org/ports.php?by=name&substr=botan>`_, +`OpenPKG <http://www.openpkg.org/product/packages/?package=botan>`_, and +`T2 SDE <http://www.t2-project.org/packages/botan.html>`_ and has +more than a few :doc:`known users <users>`. + +It was started as a personal project by `Jack Lloyd +<http:://www.randombit.net>`_,who continues to be the maintainer and +release manager. Since the first release in 2001, a number of +:doc:`individuals and organizations <credits>` have contributed bug +fixes and new features. Check out the :doc:`release notes <log>` and +`news archive <http://botan.randombit.net/news>`_ for more project +history. + +If you need help or have questions, send a mail to the `development +mailing list +<http://lists.randombit.net/mailman/listinfo/botan-devel/>`_. +"Philosophical" bug reports, announcements of programs using the +library, and related topics are also welcome. :doc:`Commercial support +options <support>` are also available. If you find what you believe to +be a bug, please file a ticket in `Bugzilla +<http://bugs.randombit.net/>`_. + +A useful reference while reading this manual is the `Doxygen +documentation <http://botan.randombit.net/doxygen>`_. + +Recommended Reading +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It's a very good idea if you have some knowledge of cryptography +*before* trying to use the library. This is an area where it is very +easy to make mistakes, and where things are often subtle and/or +counterintuitive. Obviously the library tries to provide things at a +high level precisely to minimize the number of ways things can go +wrong, but naive use will almost certainly not result in a secure +system. + +Especially recommended are: + +- *Cryptography Engineering* + Niels Ferguson, Bruce Schneier, and Tadayoshi Kohno + +- *Security Engineering -- A Guide to Building Dependable Distributed Systems* + Ross Anderson + +- *Handbook of Applied Cryptography* + Alfred J. Menezes, Paul C. Van Oorschot, and Scott A. Vanstone + (`available online <http://www.cacr.math.uwaterloo.ca/hac/>`_) diff --git a/doc/insito_manual.pdf b/doc/insito_manual.pdf Binary files differdeleted file mode 100644 index b07146992..000000000 --- a/doc/insito_manual.pdf +++ /dev/null diff --git a/doc/internals.tex b/doc/internals.tex deleted file mode 100644 index 5b1650f6e..000000000 --- a/doc/internals.tex +++ /dev/null @@ -1,179 +0,0 @@ -\documentclass{article} - -\setlength{\textwidth}{6.75in} % 1 inch side margins -\setlength{\textheight}{9in} % ~1 inch top and bottom margins - -\setlength{\headheight}{0in} -\setlength{\topmargin}{0in} -\setlength{\headsep}{0in} - -\setlength{\oddsidemargin}{0in} -\setlength{\evensidemargin}{0in} - -\title{Botan Internals} -\author{Jack Lloyd ([email protected])} -\date{August 20, 2006} - -\newcommand{\filename}[1]{\texttt{#1}} -\newcommand{\manpage}[2]{\texttt{#1}(#2)} - -\newcommand{\function}[1]{\textbf{#1}} -\newcommand{\type}[1]{\texttt{#1}} -\renewcommand{\arg}[1]{\textsl{#1}} - -\begin{document} - -\maketitle - -\tableofcontents - -\parskip=5pt - -\section{Introduction} - -This document is intended to document some of the trickier and/or more -complicated parts of Botan. This is not going to be terribly useful if -you just want to use the library, but for people wishing to understand -how it works, or contribute new code to it, it will hopefully prove -helpful. - -I've realized that a lot of things Botan does internally are pretty -hard to understand, and that a lot of things are only inside my head, -which is a bad place for them to be (things tend to get lost in there, -not to mention the possibility that I'll get hit by a truck next -week). - -This document is currently very incomplete. I'll be working on it as I -have time. - -\pagebreak - -\section{Filter} - -\type{Filter} is one of the core abstractions of the library. It is -used to represent any sort of transformation. Nearly all -\type{Filter}s are linear; they take input from a single source and -send their output (if any) to another single \type{Filter}. The one -exception is \type{Fanout\_Filter}, which uses friend access to -\type{Filter} in order to allow for multiple \type{Filter}s to attach -to its output. This special access is used by the Chain and Fork -filters; Chain encapsulates one or more \type{Filter}s into a single -Filter, and Fork sends its input to a set of several \type{Filter} -objects. - -The majority of the relations between filters is maintained by the -\type{Pipe} object which ``owns'' the \type{Filter}s. - -\section{Pipe} - -\type{Pipe} is, conceptually, a tree structure of \type{Filter} -objects. There is a single unique top, and an arbitrary number of -leaves (which are \type{SecureQueue} objects). \type{SecureQueue} is a -simple \type{Filter} that buffers its input. - -Writing into the pipe writes into the top of the tree. The filter at -the top of the tree writes its output into the next \type{Filter}, and -so on until eventually data trickles down into the bottommost -\type{Filter}s, where the data is stored for later retrieval. - -When a new message is started, \type{Pipe} searches through the tree -of \type{Filter}s and finds places where the \arg{next} field of the -\type{Filter} is NULL. This implies that it was the lowest layer of -the \type{Filter} tree that the user added. It then adds -\type{SecureQueue} objects onto these \type{Filter}s. These queues are -also stored in an deque; this is so \type{Pipe} can read from them -later without doing a tree traversal each time. - -\type{Pipe} will, if asked, destroy the existing tree structure, in -order to create a new one. However, the queue objects are not deleted, -because \type{Pipe} might be asked to read from them later (while -\type{Pipe} could delete all the messages in this case, the principle -of least astonishment suggested keeping them). - -What I wrote about \type{Pipe} keeing the queues in a deque is a -lie. Sort of. It keeps them in an object called -\type{Output\_Buffers}, which keeps them in a -deque. \type{Output\_Buffers} is intended to abstract away how message -queues are stored from \type{Pipe}. After a queue has been added to -the output buffers object, \type{Pipe} keeps no references to it -whatsoever; all access is mediated by the \type{Output\_Buffers}. -This allows queues which have been read to be deleted, rather than -leaving empty queue objects all over the place. - -\section{Library Initialization} - -WRITEME - -\section{Lookup Mechanism} - -Most objects know their name, and they know how to create a new copy -of themselves. We build mapping tables that map from an algorithm name -into a single instance of that algorithm. The tables themselves can be -found in \filename{src/lookup.cpp}. - -There are a set of functions named \function{add\_algorithm} that can -be used to populate the tables. We get something out of the table with -\function{retrieve\_x}, where x is the name of a type -(\texttt{block\_cipher}, \texttt{hash}, etc). This returns a const -pointer to the single unique instance of the algorithm that the lookup -tables know about. If it doesn't know about it, it falls back on -calling a function called \function{try\_to\_get\_x}. These functions -live in \filename{src/algolist.cpp}. They are mostly used to handle -algorithms which need (or at least can have) arguments passed to them, -like \type{HMAC} and \type{SAFER\_SK}. It will return NULL if it can't -find the algorithm at all. - -When it's asked for an algorithm it doesn't know about (ie, isn't in -the mapping tables), the retrieval functions will ask the try-to-get -functions if \emph{they} know about it. If they do, then the object -returned will be stored into the table for later retrieval. - -The functions \function{get\_x} call the retrieval functions. If we -get back NULL, an exception is thrown. Otherwise it will call the -\function{clone} method to get a new copy of the algorithm, which it -returns. - -The various functions like \function{output\_length\_of} call the -retrieval function for each type of object that the parameter in -question (in this case, \texttt{OUTPUT\_LENGTH}) might be meaningful -for. If it manages to get back an object, it will return (in this -case) the \texttt{OUTPUT\_LENGTH} field of the object. No allocations -are required to call this function: all of its operations work -directly on the copies living in the lookup tables. - -\section{Allocators} - -A big (slow) mess. - -\section{BigInt} - -Read ``Handbook of Applied Cryptography''. - -\section{PEM/BER Identification} - -We have a specific algorithm for figuring out if something is PEM or -BER. Previous versions (everything before 1.3.0) requried that the -caller specify which one it was, and they had to be right. Now we use -a hueristic (aka, an algorithm that sometimes doesn't work right) to -figure it out. If the first character is not 0x30 (equal to ASCII -'0'), then it can't possibly be BER (because everything we care about -is enclosed in an ASN.1 SEQUENCE, which for BER/DER is encoded as -beginning with 0x30). Roughly 99.9% of PEM blocks \emph{won't} have a -random 0 character in front of them, so we are mostly safe (unless -someone does it on purpose, in which case, please hit them for me). -But to be sure, if there is a 0, then we search the first \emph{N} -bytes of the block for the string ``-----BEGIN ``, which marks the -typical start of a PEM block. The specific \emph{N} depends on the -variable ``base/pem\_search'', which defaults to 4 kilobytes. - -So, you can actually fool it either way: that a PEM file is really -BER, or that a BER file is actually PEM. To fool it that a BER file is -PEM, just have the string ``-----BEGIN `` somewhere (I can't imagine -this string shows up in certificates or CRLs too often, so if it is -there it means somebody is being a jerk). If a file starts with 0 and -has at least ``base/pem\_search'' byte more junk in the way, it won't -notice that its PEM at all. In either case, of course, the loading -will fail, and you'll get a nice exception saying that the decoding -failed. - -\end{document} diff --git a/doc/kdf.txt b/doc/kdf.txt new file mode 100644 index 000000000..da916dcb3 --- /dev/null +++ b/doc/kdf.txt @@ -0,0 +1,37 @@ + +.. _key_derivation_function: + +Key Derivation Functions +======================================== + +Key derivation functions are used to turn some amount of shared secret +material into uniform random keys suitable for use with symmetric +algorithms. An example of an input which is useful for a KDF is a +shared secret created using Diffie-Hellman key agreement. + +.. cpp:class:: KDF + + .. cpp:function:: SecureVector<byte> derive_key( \ + size_t key_len, const MemoryRegion<byte>& secret, \ + const std::string& salt = "") const + + .. cpp:function:: SecureVector<byte> derive_key( \ + size_t key_len, const MemoryRegion<byte>& secret, \ + const MemoryRegion<byte>& salt) const + + .. cpp:function:: SecureVector<byte> derive_key( \ + size_t key_len, const MemoryRegion<byte>& secret, \ + const byte* salt, size_t salt_len) const + + .. cpp:function:: SecureVector<byte> derive_key( \ + size_t key_len, const byte* secret, size_t secret_len, \ + const std::string& salt) const + + All variations on the same theme. Deterministically creates a + uniform random value from *secret* and *salt*. Typically *salt* is + a lable or identifier, such as a session id. + +You can create a :cpp:class:`KDF` using + +.. cpp:function:: KDF* get_kdf(const std::string& algo_spec) + diff --git a/doc/license.txt b/doc/license.txt index f1b261eab..aefcee395 100644 --- a/doc/license.txt +++ b/doc/license.txt @@ -1,42 +1,49 @@ -Botan (http://botan.randombit.net/) is distributed under these terms: - -Copyright (C) 1999-2011 Jack Lloyd - 2001 Peter J Jones - 2004-2007 Justin Karneges - 2004 Vaclav Ovsik - 2005 Matthew Gregan - 2005-2006 Matt Johnston - 2006 Luca Piccarreta - 2007 Yves Jerschow - 2007-2008 FlexSecure GmbH - 2007-2008 Technische Universitat Darmstadt - 2007-2008 Falko Strenzke - 2007-2008 Martin Doering - 2007 Manuel Hartl - 2007 Christoph Ludwig - 2007 Patrick Sona - 2010 Olivier de Gaalon -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright -notice, this list of conditions, and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions, and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +.. _license: +.. highlight:: none + +License +======================================== + +Botan (http://botan.randombit.net/) is distributed under these terms:: + + Copyright (C) 1999-2011 Jack Lloyd + 2001 Peter J Jones + 2004-2007 Justin Karneges + 2004 Vaclav Ovsik + 2005 Matthew Gregan + 2005-2006 Matt Johnston + 2006 Luca Piccarreta + 2007 Yves Jerschow + 2007-2008 FlexSecure GmbH + 2007-2008 Technische Universitat Darmstadt + 2007-2008 Falko Strenzke + 2007-2008 Martin Doering + 2007 Manuel Hartl + 2007 Christoph Ludwig + 2007 Patrick Sona + 2010 Olivier de Gaalon + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/doc/log.txt b/doc/log.txt index 9313ac2f6..b9c6c9230 100644 --- a/doc/log.txt +++ b/doc/log.txt @@ -1,1525 +1,2072 @@ -* 1.9.15-dev, ????-??-?? - - Pipe will delete empty output queues as soon as they are no longer - needed, even if earlier messages still have data unread. - -* 1.9.14, 2011-03-01 - - Add support for bcrypt, OpenBSD's password hashing scheme - - Add support for NIST's AES key wrapping algorithm - - Fix an infinite loop in zlib filters introduced in 1.9.11 (PR 142) - -* 1.9.13, 2011-02-19 - - Update Keccak to the round 3 variant - - Fix ordering in GOST 34.10 signatures to match DNSSEC specifications - - Use size_t instead of u32bit for small integers in DER/BER codecs - - Add new build option --distribution-info - - Fix problems in the amalgamation build - - Fix building under Clang 2.9 and Sun Studio 12 - -* 1.9.12, 2010-12-13 - - Add the Keccak hash function - - Fix compilation problems in Python wrappers - - Fix compilation problem in OpenSSL engine - - Update SQLite3 database encryption codec - -* 1.9.11, 2010-11-29 - - Many SSL/TLS APIs have changed. This API is still unstable. - - The SSL interface requires TR1 (uses std::tr1::function) - - Fix SSL handshake failures when using RC4 ciphersuites - - Fix a number of CRL encoding and decoding bugs - - Counter mode now always encrypts 256 blocks in parallel - - Code where u32bit was used to represent a length now uses size_t - - Use small tables in the first round of AES - - Removed AES class: app must choose AES-128, AES-192, or AES-256 - - Add hex encoding/decoding functions that can be used without a Pipe - - Add base64 encoding functions that can be used without a Pipe - - Add to_string function to X509_Certificate - - Add support for dynamic engine loading on Windows - - Replace BlockCipher::BLOCK_SIZE attribute with function block_size() - - Replace HashFunction::HASH_BLOCK_SIZE attribute with hash_block_size() - - Changed semantics of MemoryRegion::resize and clear to match STL - - Removed MemoryRegion::append, replaced by push_back and operator+= - - Move PBKDF lookup to engine system - - The IDEA key schedule has been changed to run in constant time - - Avoid a possible timing vulnerability in Montgomery reduction - - Add Algorithm and Key_Length_Specification classes - - Switch default PKCS #8 encryption algorithm from AES-128 to AES-256 - - Update Skein-512 to match the v1.3 specification - - Allow using PBKDF2 with empty passphrases - - Add compile-time deprecation warnings for GCC, Clang, and MSVC - - Support use of HMAC(SHA-256) and CMAC(Blowfish) in passhash9 - - Improve support for Intel Atom processors - - Fix compilation problems under Sun Studio and Clang - -* 1.8.11, 2010-11-02 - - Fix a number of CRL encoding and decoding bugs - - When building a debug library under VC++, use the debug runtime - - Fix compilation under Sun Studio on Linux and Solaris - - Add several functions for compatability with 1.9 - - In the examples, read most input files as binary - - The Perl build script has been removed in this release - -* 1.8.10, 2010-08-31 - - Switch default PKCS #8 encryption algorithm from 3DES to AES-256 - - Increase default hash iterations from 2048 to 10000 in PBES1 and PBES2 - - Use small tables in the first round of AES - - Add PBKDF typedef and get_pbkdf for better compatability with 1.9 - - Add version of S2K::derive_key taking salt and iteration count - - Enable the /proc-walking entropy source on NetBSD - - Fix the doxygen makefile target - -* 1.9.10, 2010-08-12 - - Add a constant time AES implementation using SSSE3 - - Add support for loading new Engines at runtime - - Use GCC byteswap intrinsics where possible - - Drop support for building with Python 2.4 - - Fix benchmarking of block ciphers in ECB mode - - Consolidate the two x86 assembly engines - - Rename S2K to PBKDF - -* 1.9.9, 2010-06-28 - - Add new X509::BER_encode and PKCS8::BER_encode - - Give all Filter objects a name() function - - Add Keyed_Filter::valid_iv_length - - Increase default iteration counts for private key encryption - - Fix compilation of mp_asm64 on 64-bit MIPS with GCC 4.4 and later - - Fix compilation under Apple's GCC 4.2 - - Expand and update the Doxygen documentation - -* 1.8.9, 2010-06-16 - - Use constant time multiplication in IDEA - - Avoid possible timing attack against OAEP decoding - - Add new X509::BER_encode and PKCS8::BER_encode - - Enable DLL builds under Windows - - Add Win32 installer support - - Add support for the Clang compiler - - Fix problem in semcem.h preventing build under Clang or GCC 3.4 - - Fix bug that prevented creation of DSA groups under 1024 bits - - Fix crash in GMP_Engine if library is shutdown and reinitialized - - Work around problem with recent binutils in x86-64 SHA-1 - - The Perl build script is no longer supported and refuses to run by default - -* 1.9.8, 2010-06-14 - - Add support for wide multiplications on 64-bit Windows - - Use constant time multiplication in IDEA - - Avoid possible timing attack against OAEP decoding - - Removed FORK-256; rarely used and it has been broken - - Rename --use-boost-python to --with-boost-python - - Skip building shared libraries on MinGW/Cygwin - - Fix creation of 512 and 768 bit DL groups using the DSA kosherizer - - Fix compilation on GCC versions before 4.3 (missing cpuid.h) - - Fix compilation under the Clang compiler - -* 1.9.7, 2010-04-27 - - TLS: Support reading SSLv2 client hellos - - TLS: Add support for SEED ciphersuites (RFC 4162) - - Add Comb4P hash combiner function - - Fix checking of EMSA_Raw signatures with leading 0 bytes - -* 1.9.6, 2010-04-09 - - TLS: Add support for TLS v1.1 - - TLS: Support server name indicator extension - - TLS: Fix server handshake - - TLS: Fix server using DSA certificates - - TLS: Avoid timing channel between CBC padding check and MAC verification - -* 1.9.5, 2010-03-29 - - Numerous ECC optimizations - - Fix GOST 34.10-2001 X.509 key loading - - Allow PK_Signer's fault protection checks to be toggled off - - Avoid using pool-based locking allocator if we can't mlock - - Remove all runtime options - - New BER_Decoder::{decode_and_check, decode_octet_string_bigint} - - Remove SecureBuffer in favor of SecureVector length parameter - - HMAC_RNG: Perform a poll along with user-supplied entropy - - Fix crash in MemoryRegion if Allocator::get failed - - Fix small compilation problem on FreeBSD - -* 1.9.4, 2010-03-09 - - Add the Ajisai SSLv3/TLSv1.0 implementation - - Add GOST 34.10-2001 public key signature scheme - - Add SIMD implementation of Noekeon - - Add SSE2 implementation of IDEA - - Extend Salsa20 to support longer IVs (XSalsa20) - - Perform XTS encryption and decryption in parallel where possible - - Perform CBC decryption in parallel where possible - - Add SQLite3 db encryption codec, contributed by Olivier de Gaalon - - Add a block cipher cascade construction - - Add support for password hashing for authentication (passhash9.h) - - Add support for Win32 high resolution system timers - - Major refactoring and API changes in the public key code - - Use consistency checking (anti-fault attack) for all signature schemes - - Changed S2K interface: derive_key now takes salt, iteration count - - Remove dependency on TR1 for ECC and CVC code - - Renamed ECKAEG to its more usual name, ECDH - - Fix crash in GMP_Engine if library is shutdown and reinitialized - - Fix an invalid memory read in MD4 - - Fix Visual C++ static builds - - Remove Timer class entirely - - Switch default PKCS #8 encryption algorithm from 3DES to AES-128 - - New option --gen-amalgamation for creating a SQLite-style amalgamation - - Many headers are now explicitly internal-use-only and are not installed - - Greatly improve the Win32 installer - - Several fixes for Visual C++ debug builds - -* 1.9.3, 2009-11-19 - - Add new AES implementation using Intel's AES instruction intrinsics - - Add an implementation of format preserving encryption - - Allow use of any hash function in X.509 certificate creation - - Optimizations for MARS, Skipjack, and AES - - Set macros for available SIMD instructions in build.h - - Add support for using InnoSetup to package Windows builds - - By default build a DLL on Windows - -* 1.9.2, 2009-11-03 - - Add SIMD version of XTEA - - Support both SSE2 and AltiVec SIMD for Serpent and XTEA - - Optimizations for SHA-1 and SHA-2 - - Add AltiVec runtime detection - - Fix x86 CPU identification with Intel C++ and Visual C++ - -* 1.8.8, 2009-11-03 - - Alter Skein-512 to match the tweaked 1.2 specification - - Fix use of inline asm for access to x86 bswap function - - Allow building the library without AES enabled - - Add 'powerpc64' alias to ppc64 arch for Gentoo ebuild - -* 1.9.1, 2009-10-23 - - Better support for Python and Perl wrappers - - Add an implementation of Blue Midnight Wish (Round 2 tweak version) - - Modify Skein-512 to match the tweaked 1.2 specification - - Add threshold secret sharing (draft-mcgrew-tss-02) - - Add runtime cpu feature detection for x86/x86-64 - - Add code for general runtime self testing for hashes, MACs, and ciphers - - Optimize XTEA; twice as fast as before on Core2 and Opteron - - Convert CTR_BE and OFB from filters to stream ciphers - - New parsing code for SCAN algorithm names - - Enable SSE2 optimizations under Visual C++ - - Remove all use of C++ exception specifications - - Add support for GNU/Hurd and Clang/LLVM - -* 1.9.0, 2009-09-09 - - Add support for parallel invocation of block ciphers where possible - - Add SSE2 implementation of Serpent - - Add Rivest's package transform (an all or nothing transform) - - Minor speedups to the Turing key schedule - - Fix processing multiple messages in XTS mode - - Add --no-autoload option to configure.py, for minimized builds - - The previously used configure.pl script is no longer supported - -* 1.8.7, 2009-09-09 - - Fix processing multiple messages in XTS mode - - Add --no-autoload option to configure.py, for minimized builds - -* 1.8.6, 2009-08-13 - - Add Cryptobox, a set of simple password-based encryption routines - - Only read world-readable files when walking /proc for entropy - - Fix building with TR1 disabled - - Fix x86 bswap support for Visual C++ - - Fixes for compilation under Sun C++ - - Add support for Dragonfly BSD (contributed by Patrick Georgi) - - Add support for the Open64 C++ compiler - - Build fixes for MIPS systems running Linux - - Minor changes to license, now equivalent to the FreeBSD/NetBSD license - -* 1.8.5, 2009-07-23 - - Change configure.py to work on stock Python 2.4 - - Avoid a crash in Skein_512::add_data processing a zero-length input - - Small build fixes for SPARC, ARM, and HP-PA processors - - The test suite now returns an error code from main() if any tests failed - -* 1.8.4, 2009-07-12 - - Fix a bug in nonce generation in the Miller-Rabin test - -* 1.8.3, 2009-07-11 - - Add a new Python configuration script - - Add the Skein-512 SHA-3 candidate hash function - - Add the XTS block cipher mode from IEEE P1619 - - Fix random_prime when generating a prime of less than 7 bits - - Improve handling of low-entropy situations during PRNG seeding - - Change random device polling to prefer /dev/urandom over /dev/random - - Use an input insensitive implementation of same_mem instead of memcmp - - Correct DataSource::discard_next to return the number of discarded bytes - - Provide a default value for AutoSeeded_RNG::reseed - - Fix Gentoo bug 272242 - -* 1.8.2, 2009-04-07 - - Make entropy polling more flexible and in most cases faster - - GOST 28147 now supports multiple sbox parameters - - Added the GOST 34.11 hash function - - Fix botan-config problems on MacOS X - -* 1.8.1, 2009-01-20 - - Avoid a valgrind warning in es_unix.cpp on 32-bit Linux - - Fix memory leak in PKCS8 load_key and encrypt_key - - Relicense api.tex from CC-By-SA 2.5 to BSD - - Fix botan-config on MacOS X, Solaris - -* 1.8.0, 2008-12-08 - - Fix compilation on Solaris with GCC - -* 1.7.24, 2008-12-01 - - Fix a compatibility problem with SHA-512/EMSA3 signature padding - - Fix bug preventing EGD/PRNGD entropy poller from working - - Fix integer overflow in Pooling_Allocator::get_more_core (bug id #27) - - Add EMSA3_Raw, a variant of EMSA3 called CKM_RSA_PKCS in PKCS #11 - - Add support for SHA-224 in EMSA2 and EMSA3 PK signature padding schemes - - Add many more test vectors for RSA with EMSA2, EMSA3, and EMSA4 - - Wrap private structs in SSE2 SHA-1 code in anonymous namespace - - Change configure.pl's CPU autodetection output to be more consistent - - Disable using OpenSSL's AES due to crashes of unknown cause - - Fix warning in /proc walking entropy poller - - Fix compilation with IBM XLC for Cell 0.9-200709 - -* 1.7.23, 2008-11-23 - - Change to use TR1 (thus enabling ECDSA) with GCC and ICC - - Optimize almost all hash functions, especially MD4 and Tiger - - Add configure.pl options --{with,without}-{bzip2,zlib,openssl,gnump} - - Change Timer to be pure virtual, and add ANSI_Clock_Timer - - Cache socket descriptors in the EGD entropy source - - Avoid bogging down startup in /proc walking entropy source - - Remove Buffered_EntropySource helper class - - Add a Default_Benchmark_Timer typedef in benchmark.h - - Add examples using benchmark.h and Algorithm_Factory - - Add ECC tests from InSiTo - - Minor documentation updates - -* 1.7.22, 2008-11-17 - - Add provider preferences to Algorithm_Factory - - Fix memory leaks in PBE_PKCS5v20 and get_pbe introduced in 1.7.21 - - Optimize AES encryption and decryption (about 10% faster) - - Enable SSE2 optimized SHA-1 implementation on Intel Prescott CPUs - - Fix nanoseconds overflow in benchmark code - - Remove Engine::add_engine - -* 1.7.21, 2008-11-11 - - Make algorithm lookup much more configuable - - Add facilities for runtime performance testing of algorithms - - Drop use of entropy estimation in the PRNGs - - Increase intervals between HMAC_RNG automatic reseeding - - Drop InitializerOptions class, all options but thread safety - -* 1.7.20, 2008-11-09 - - Namespace pkg-config file by major and minor versions - - Cache device descriptors in Device_EntropySource - - Split base.h into {block_cipher,stream_cipher,mac,hash}.h - - Removed get_mgf function from lookup.h - -* 1.7.19, 2008-11-06 - - Add HMAC_RNG, based on a design by Hugo Krawczyk - - Optimized the Turing stream cipher (about 20% faster on x86-64) - - Modify Randpool's reseeding algorithm to poll more sources - - Add a new AutoSeeded_RNG in auto_rng.h - - OpenPGP_S2K changed to take hash object instead of name - - Add automatic identification for Intel's Prescott processors - -* 1.7.18, 2008-10-22 - - Add Doxygen comments from InSiTo - - Add ECDSA and ECKAEG benchmarks - - Add configure.pl switch --with-tr1-implementation - - Fix configure.pl's --with-endian and --with-unaligned-mem options - - Added support for pkg-config - - Optimize byteswap with x86 inline asm for Visual C++ by Yves Jerschow - - Use const references to avoid copying overhead in CurveGFp, GFpModulus - -* 1.7.17, 2008-10-12 - - Add missing ECDSA object identifiers - - Fix error in x86 and x86-64 assembler affecting GF(p) math - - Remove Boost dependency from GF(p) math - - Modify botan-config to not print -L/usr/lib or -L/usr/local/lib - - Add BOTAN_DLL macro to over 30 classes missing it - - Rename the two SHA-2 base classes for consistency - -* 1.7.16, 2008-10-09 - - Add several missing pieces needed for ECDSA and ECKAEG - - Add Card Verifiable Certificates from InSiTo - - Add SHA-224 from InSiTo - - Add BSI variant of EMSA1 from InSiTo - - Add GF(p) and ECDSA tests from InSiTo - - Split ECDSA and ECKAEG into distinct modules - - Allow OpenSSL and GNU MP engines to be built with public key algos disabled - - Rename sha256.h to sha2_32.h and sha_64.h to sha2_64.h - -* 1.7.15, 2008-10-07 - - Add GF(p) arithmetic from InSiTo - - Add ECDSA and ECKAEG implementations from InSiTo - - Minimize internal dependencies, allowing for smaller build configurations - - Add new User Manual and Architecture Guide from FlexSecure GmbH - - Alter configure.pl options for better autotools compatibility - - Update build instructions for recent changes to configure.pl - - Fix CPU detection using /proc/cpuinfo - -* 1.7.14, 2008-09-30 - - Split library into parts allowing modular builds - - Add (very preliminary) CMS support to the main library - - Some constructors now require object pointers instead of names - - Support multiple implementations of the same algorithm - - Build support for Pentium-M processors, from Derek Scherger - - Build support for MinGW/MSYS, from Zbigniew Zagorski - - Use inline assembly for bswap on 32-bit x86 - -* 1.7.13, 2008-09-27 - - Add SSLv3 MAC, SSLv3 PRF, and TLS v1.0 PRF from Ajisai - - Allow all examples to compile even if compression not enabled - - Make CMAC's polynomial doubling operation a public class method - - Use the -m64 flag when compiling with Sun Forte on x86-64 - - Clean up and slightly optimize CMAC::final_result - -* 1.7.12, 2008-09-18 - - Add x86 assembly for Visual Studio C++, by Luca Piccarreta - - Add a Perl XS module, by Vaclav Ovsik - - Add SWIG-based wrapper for Botan - - Add SSE2 implementation of SHA-1, by Dean Gaudet - - Remove the BigInt::sig_words cache due to bugs - - Combined the 4 Blowfish sboxes, suggested by Yves Jerschow - - Changed BigInt::grow_by and BigInt::grow_to to be non-const - - Add private assignment operators to classes that don't support assignment - - Benchmark RSA encryption and signatures - - Added test programs for random_prime and ressol - - Add high resolution timers for IA-64, HP-PA, S390x - - Reduce use of the RNG during benchmarks - - Fix builds on STI Cell PPU - - Add support for IBM's XLC compiler - - Add IETF 8192 bit MODP group - -* 1.7.11, 2008-09-11 - - Added the Salsa20 stream cipher - - Optimized Montgomery reduction, Karatsuba squaring - - Added 16x16->32 word Comba multiplication and squaring - - Use a much larger Karatsuba cutoff point - - Remove bigint_mul_add_words - - Inlined several BigInt functions - - Add useful information to the generated build.h - - Rename alg_{ia32,amd64} modules to asm_{ia32,amd64} - - Fix the Windows build - -* 1.7.10, 2008-09-05 - - Public key benchmarks run using a selection of random keys - - New benchmark timer options are clock_gettime, gettimeofday, times, clock - - Including reinterpret_cast optimization for xor_buf in default header - - Split byte swapping and word rotation functions into distinct headers - - Add IETF modp 6144 group and 2048 and 3072 bit DSS groups - - Optimizes BigInt right shift - - Add aliases in DL_Group::Format enum - - BigInt now caches the significant word count - -* 1.7.9, 2008-08-27 - - Make clear() in most algorithm base classes a pure virtual - - Add noexec stack marker for GNU linker in assembly code - - Avoid string operations in ressol - - Compilation fixes for MinGW and Visual Studio C++ 2008 - - Some autoconfiguration fixes for Windows - -* 1.6.5, 2008-08-27 - - Add noexec stack marker for GNU linker in assembly code - - Fix autoconfiguration problem on x86 with GCC 4.2 and 4.3 - -* 1.7.8, 2008-07-15 - - Added the block cipher Noekeon - - Remove global deref_alias function - - X509_Store takes timeout options as constructor arguments - - Add Shanks-Tonelli algorithm, contributed by FlexSecure GmbH - - Extend random_prime() for generating primes of any bit length - - Remove Config class - - Allow adding new entropy via base RNG interface - - Reseeding a X9.31 PRNG also reseeds the underlying PRNG - -* 1.7.7, 2008-06-28 - - Remove the global PRNG object - - The PK filter objects were removed - - Add a test suite for the ANSI X9.31 PRNG - - Much cleaner and (mostly) thread-safe reimplementation of es_ftw - - Remove both default arguments to ANSI_X931_RNG's constructor - - Remove the randomizing version of OctetString::change - - Make the cipher and MAC to use in Randpool configurable - - Move RandomNumberGenerator declaration to rng.h - - RSA_PrivateKey will not generate keys smaller than 1024 bits - - Fix an error decoding BER UNIVERSAL types with special taggings - -* 1.7.6, 2008-05-05 - - Initial support for Windows DLLs, from Joel Low - - Reset the position pointer when a new block is generated in X9.32 PRNG - - Timer objects are now treated as entropy sources - - Moved several ASN.1-related enums from enums.h to an appropriate header - - Removed the AEP module, due to inability to test - - Removed Global_RNG and rng.h - - Removed system_clock - - Removed Library_State::UI and the pulse callback logic - -* 1.7.5, 2008-04-12 - - The API of X509_CA::sign_request was altered to avoid race conditions - - New type Pipe::message_id to represent the Pipe message number - - Remove the Named_Mutex_Holder for a small performance gain - - Removed several unused or rarely used functions from Config - - Ignore spaces inside of a decimal string in BigInt::decode - - Allow using a std::istream to initialize a DataSource_Stream object - - Fix compilation problem in zlib compression module - - The chunk sized used by Pooling_Allocator is now a compile time setting - - The size of random blinding factors is now a compile time setting - - The install target no longer tries to set a particular owner/group - -* 1.7.4, 2008-03-10 - - Use unaligned memory read/writes on systems that allow it, for performance - - Assembly for x86-64 for accessing the bswap instruction - - Use larger buffers in ARC4 and WiderWAKE for significant throughput increase - - Unroll loops in SHA-160 for a few percent increase in performance - - Fix compilation with GCC 3.2 in es_ftw and es_unix - - Build fix for NetBSD systems - - Prevent es_dev from being built except on Unix systems - -* 1.6.4, 2008-03-08 - - Fix a compilation problem with Visual Studio C++ 2003 - -* 1.7.3, 2008-01-23 - - New invocation syntax for configure.pl with several new options - - Support for IPv4 addresses in a subject alternative name - - New fast poll for the generic Unix entropy source (es_unix) - - The es_file entropy source has been replaced by the es_dev module - - The malloc allocator does not inherit from Pooling_Allocator anymore - - The path that es_unix will search in are now fully user-configurable - - Truncate X9.42 PRF output rather than allow counter overflow - - PowerPC is now assumed to be big-endian - -* 1.7.2, 2007-10-13 - - Initialize the global library state lazily - - Add plain CBC-MAC for backwards compatibility with old systems - - Clean up some of the self test code - - Throw a sensible exception if a DL_Group is not found - - Truncate KDF2 output rather than allowing counter overflow - - Add newly assigned OIDs for SHA-2 and DSA with SHA-224/256 - - Fix a Visual Studio compilation problem in x509stat.cpp - -* 1.7.1, 2007-07-23 - - Fix a race condition in the algorithm object cache - - HMAC key schedule optimization - - The build header sets a macro defining endianness, if known - - New word load/store abstraction allowing further optimization - - Modify most of the library to avoid use the C-style casts - - Use higher resolution timers in symmetric benchmarks - -* 1.6.3, 2007-07-23 - - Fix a race condition in the algorithm lookup cache - - Fix problems building the memory pool on some versions of Visual C++ - -* 1.7.0, 2007-05-19 - - DSA parameter generation now follows FIPS 186-3 - - Added OIDs for Rabin-Williams and Nyberg-Rueppel - - Somewhat better support for out of tree builds - - Minor optimizations for RC2 and Tiger - - Documentation updates - - Update the todo list - -* 1.6.2, 2007-03-24 - - Fix autodection on Athlon64s running Linux - - Fix builds on QNX and compilers using STLport - - Remove a call to abort() that crept into production - -* 1.6.1, 2007-01-20 - - Fix some base64 decoder bugs - - Add a new option to base64 encoding, to always append a newline - - Fix some build problems under Visual Studio with debug enabled - - Fix a bug in BER_Decoder that was triggered under some compilers - -* 1.6.0, 2006-12-17 - - Minor cleanups versus 1.5.13 - -* 1.5.13, 2006-12-10 - - Compilation fixes for the bzip2, zlib, and GNU MP modules - - Better support for Intel C++ and EKOpath C++ on x86-64 - -* 1.5.12, 2006-10-27 - - Cleanups in the initialization routines - - Add some x86-64 assembly for multiply-add - - Fix problems generating very small (below 384 bit) RSA keys - - Support out of tree builds - - Bring some of the documentation up to date - - More improvements to the Python bindings - -* 1.5.11, 2006-09-10 - - Removed the Algorithm base class - - Various cleanups in the public key inheritance hierarchy - - Major overhaul of the configure/build setup - - Added x86 assembler implementations of Serpent and low-level MPI code - - Optimizations for the SHA-1 x86 assembler - - Various improvements to the Python wrappers - - Work around a Visual Studio compiler bug - -* 1.5.10, 2006-08-13 - - Add x86 assembler versions of MD4, MD5, and SHA-1 - - Expand InitializerOptions' language to support on/off switches - - Fix definition of OID 2.5.4.8; was accidentally changed in 1.5.9 - - Fix possible resource leaks in the mmap allocator - - Slightly optimized buffering in MDx_HashFunction - - Initialization failures are dealt with somewhat better - - Add an example implementing Pollard's Rho algorithm - - Better option handling in the test/benchmark tool - - Expand the xor_ciph example to support longer keys - - Some updates to the documentation - -* 1.5.9, 2006-07-12 - - Fixed bitrot in the AEP engine - - Fix support for marking certificate/CRL extensions as critical - - Significant cleanups in the library state / initialization code - - LibraryInitializer takes an explicit InitializerOptions object - - Make Mutex_Factory an abstract class, add Default_Mutex_Factory - - Change configuration access to using global_state() - - Add support for global named mutexes throughout the library - - Add some STL wrappers for the delete operator - - Change how certificates are created to be more flexible and general - -* 1.5.8, 2006-06-23 - - Many internal cleanups to the X.509 cert/CRL code - - Allow for application code to support new X.509 extensions - - Change the return type of X509_Certificate::{subject,issuer}_info - - Allow for alternate character set handling mechanisms - - Fix a bug that was slowing squaring performance somewhat - - Fix a very hard to hit overflow bug in the C version of word3_muladd - - Minor cleanups to the assembler modules - - Disable es_unix module on FreeBSD due to build problem on FreeBSD 6.1 - - Support for GCC 2.95.x has been dropped in this release - -* 1.5.7, 2006-05-28 - - Further, major changes to the BER/DER coding system - - Updated the Qt mutex module to use Mutex_Factory - - Moved the library global state object into an anonymous namespace - - Drop the Visual C++ x86 assembly module due to bugs - -* 1.5.6, 2006-03-01 - - The low-level DER/BER coding system was redesigned and rewritten - - Portions of the certificate code were cleaned up internally - - Use macros to substantially clean up the GCC assembly code - - Added 32-bit x86 assembly for Visual C++ (by Luca Piccarreta) - - Avoid a couple of spurious warnings under Visual C++ - - Some slight cleanups in X509_PublicKey::key_id - -* 1.5.5, 2006-02-04 - - Fixed a potential infinite loop in the memory pool code (Matt Johnston) - - Made Pooling_Allocator::Memory_Block an actual class of sorts - - Some small optimizations to the division and modulo computations - - Cleaned up the implementation of some of the BigInt operators - - Reduced use of dynamic memory allocation in low-level BigInt functions - - A few simplifications in the Randpool mixing function - - Removed power(), as it was not particularly useful (or fast) - - Fixed some annoying bugs in the benchmark code - - Added a real credits file - -* 1.5.4, 2006-01-29 - - Integrated x86 and amd64 assembly code, contributed by Luca Piccarreta - - Fixed a memory access off-by-one in the Karatsuba code - - Changed Pooling_Allocator's free list search to a log(N) algorithm - - Merged ModularReducer with its only subclass, Barrett_Reducer - - Fixed sign-handling bugs in some of the division and modulo code - - Renamed the module description files to modinfo.txt - - Further cleanups in the initialization code - - Removed BigInt::add and BigInt::sub - - Merged all the division-related functions into just divide() - - Modified the <mp_asmi.h> functions to allow for better optimizations - - Made the number of bits polled from an EntropySource user configurable - - Avoid including <algorithm> in <botan/secmem.h> - - Fixed some build problems with Sun Forte - - Removed some dead code from bigint_modop - - Fix the definition of same_mem - -* 1.5.3, 2006-01-24 - - Many optimizations in the low-level multiple precision integer code - - Added hooks for assembly implementations of the MPI code - - Support for the X.509 issuer alternative name extension in new certs - - Fixed a bug in the decompression modules; found and patched by Matt Johnston - - New Windows mutex module (mux_win32), by Luca Piccarreta - - Changed the Windows timer module to use QueryPerformanceCounter - - mem_pool.cpp was using std::set iterators instead of std::multiset ones - - Fixed a bug in X509_CA preventing users from disabling particular extensions - - Fixed the mp_asm64 module, which was entirely broken in 1.5.2 - - Fixed some module build problems on FreeBSD and Tru64 - -* 1.5.2, 2006-01-15 - - Fixed an off-by-one memory read in MISTY1::key() - - Fixed a nasty memory leak in Output_Buffers::retire() - - Reimplemented the memory allocator from scratch - - Improved memory caching in Montgomery exponentiation - - Optimizations for multiple precision addition and subtraction - - Fixed a build problem in the hardware timer module on 64-bit PowerPC - - Changed default Karatsuba cutoff to 12 words (was 14) - - Removed MemoryRegion::bits(), which was unused and incorrect - - Changed maximum HMAC keylength to 1024 bits - - Various minor Makefile and build system changes - - Avoid using std::min in <secmem.h> to bypass Windows libc macro pollution - - Switched checks/clock.cpp back to using clock() by default - - Enabled the symmetric algorithm tests, which were accidentally off in 1.5.1 - - Removed the Default_Mutex's unused clone() member function - -* 1.4.12, 2006-01-15 - - Fixed an off-by-one memory read in MISTY1::key() - - Fixed a nasty memory leak in Output_Buffers::retire() - - Changed maximum HMAC keylength to 1024 bits - - Fixed a build problem in the hardware timer module on 64-bit PowerPC - -* 1.5.1, 2006-01-08 - - Implemented Montgomery exponentiation - - Implemented generalized Karatsuba multiplication and squaring - - Implemented Comba squaring for 4, 6, and 8 word inputs - - Added new Modular_Exponentiator and Power_Mod classes - - Removed FixedBase_Exp and FixedExponent_Exp - - Fixed a performance regression in get_allocator introduced in 1.5.0 - - Engines can now offer S2K algorithms and block cipher padding methods - - Merged the remaining global 'algolist' code into Default_Engine - - The low-level MPI code is linked as C again - - Replaced BigInt's get_nibble with the more general get_substring - - Some documentation updates - -* 1.5.0, 2006-01-01 - - Moved all global/shared library state into a single object - - Mutex objects are created through mutex factories instead of a global - - Removed ::get_mutex(), ::initialize_mutex(), and Mutex::clone() - - Removed the RNG_Quality enum entirely - - There is now only a single global-use PRNG - - Removed the no_aliases and no_oids options for LibraryInitializer - - Removed the deprecated algorithms SEAL, ISAAC, and HAVAL - - Change es_ftw to use unbuffered I/O - -* 1.4.11, 2005-12-31 - - Changed Whirlpool diffusion matrix to match updated algorithm spec - - Fixed several engine module build errors introduced in 1.4.10 - - Fixed two build problems in es_capi; reported by Matthew Gregan - - Added a constructor to DataSource_Memory taking a std::string - - Placing the same Filter in multiple Pipes triggers an exception - - The configure script accepts --docdir and --libdir - - Merged doc/rngs.txt into the main API document - - Thanks to Joel Low for several bug reports on early tarballs of 1.4.11 - -* 1.4.10, 2005-12-18 - - Added an implementation of KASUMI, the block cipher used in 3G phones - - Refactored Pipe; output queues are now managed by a distinct class - - Made certain Filter facilities only available to subclasses of Fanout_Filter - - There is no longer any overhead in Pipe for a message that has been read out - - It is now possible to generate RSA keys as small as 128 bits - - Changed some of the core classes to derive from Algorithm as a virtual base - - Changed Randpool to use HMAC instead of a plain hash as the mixing function - - Fixed a bug in the allocators; found and fixed by Matthew Gregan - - Enabled the use of binary file I/O, when requested by the application - - The OpenSSL engine's block cipher code was missing some deallocation calls - - Disabled the es_ftw module on NetBSD, due to header problems there - - Fixed a problem preventing tm_hard from building on MacOS X on PowerPC - - Some cleanups for the modules that use inline assembler - - config.h is now stored in build/ instead of build/include/botan/ - - The header util.h was split into bit_ops.h, parsing.h, and util.h - - Cleaned up some redundant include directives - -* 1.4.9, 2005-11-06 - - Added the IBM-created AES candidate algorithm MARS - - Added the South Korean block cipher SEED - - Added the stream cipher Turing - - Added the new hash function FORK-256 - - Deprecated the ISAAC stream cipher - - Twofish and RC6 are significantly faster with GCC - - Much better support for 64-bit PowerPC - - Added support for high-resolution PowerPC timers - - Fixed a bug in the configure script causing problems on FreeBSD - - Changed ANSI X9.31 to support arbitrary block ciphers - - Make the configure script a bit less noisy - - Added more test vectors for some algorithms, including all the AES finalists - - Various cosmetic source code cleanups - -* 1.4.8, 2005-10-16 - - Resolved a bad performance problem in the allocators; fix by Matt Johnston - - Worked around a Visual Studio 2003 compilation problem introduced in 1.4.7 - - Renamed OMAC to CMAC to match the official NIST naming - - Added single byte versions of update() to PK_Signer and PK_Verifier - - Removed the unused reverse_bits and reverse_bytes functions - -* 1.4.7, 2005-09-25 - - Fixed major performance problems with recent versions of GNU C++ - - Added an implementation of the X9.31 PRNG - - Removed the X9.17 and FIPS 186-2 PRNG algorithms - - Changed defaults to use X9.31 PRNGs as global PRNG objects - - Documentation updates to reflect the PRNG changes - - Some cleanups related to the engine code - - Removed two useless headers, base_eng.h and secalloc.h - - Removed PK_Verifier::valid_signature - - Fixed configure/build system bugs affecting MacOS X builds - - Added support for the EKOPath x86-64 compiler - - Added missing destructor for BlockCipherModePaddingMethod - - Fix some build problems with Visual C++ 2005 beta - - Fix some build problems with Visual C++ 2003 Workshop - -* 1.4.6, 2005-03-13 - - Fix an error in the shutdown code introduced in 1.4.5 - - Setting base/pkcs8_tries to 0 disables the builtin fail-out - - Support for XMPP identifiers in X.509 certificates - - Duplicate entries in X.509 DNs are removed - - More fixes for Borland C++, from Friedemann Kleint - - Add a workaround for buggy iostreams - -* 1.4.5, 2005-02-26 - - Add support for AES encryption of private keys - - Minor fixes for PBES2 parameter decoding - - Internal cleanups for global state variables - - GCC 3.x version detection was broken in non-English locales - - Work around a Sun Forte bug affecting mem_pool.h - - Several fixes for Borland C++ 5.5, from Friedemann Kleint - - Removed inclusion of init.h into base.h - - Fixed a major bug in reading from certificate stores - - Cleaned up a couple of mutex leaks - - Removed some left-over debugging code - - Removed SSL3_MAC, SSL3_PRF, and TLS_PRF - -* 1.4.4, 2004-12-02 - - Further tweaks to the pooling allocator - - Modified EMSA3 to support SSL/TLS signatures - - Changes to support Qt/QCA, from Justin Karneges - - Moved mux_qt module code into mod_qt - - Fixes for HP-UX from Mike Desjardins - -* 1.4.3, 2004-11-06 - - Split up SecureAllocator into Allocator and Pooling_Allocator - - Memory locking allocators are more likely to be used - - Fixed the placement of includes in some modules - - Fixed broken installation procedure - - Fixes in configure script to support alternate install programs - - Modules can specify the minimum version they support - -* 1.4.2, 2004-10-31 - - Fixed a major CRL handling bug - - Cipher and hash operations can be offloaded to engines - - Added support for cipher and hash offload in OpenSSL engine - - Improvements for 64-bit CPUs without a widening multiply instruction - - Support for SHA2-* and Whirlpool with EMSA2 - - Fixed a long-standing build problem with conflicting include files - - Fixed some examples that hadn't been updated for 1.4.x - - Portability fixes for Solaris, *BSD, HP-UX, and others - - Lots of fixes and cleanups in the configure script - - Updated the Gentoo ebuild file - -* 1.4.1, 2004-10-10 - - Fixed major errors in the X.509 and PKCS #8 copy_key functions - - Added a LAST_MESSAGE meta-message number for Pipe - - Added new aliases (3DES and DES-EDE) for Triple-DES - - Added some new functions to PK_Verifier - - Cleaned up the KDF interface - - Disabled tm_posix on *BSD due to header issues - - Fixed a build problem on PowerPC with GNU C++ pre-3.4 - -* 1.4.0, 2004-06-26 - - Added the FIPS 186 RNG back - - Added copy_key functions for X.509 public keys and PKCS #8 private keys - - Fixed PKCS #1 signatures with RIPEMD-128 - - Moved some code around to avoid warnings with Sun ONE compiler - - Fixed a bug in botan-config affecting OpenBSD - - Fixed some build problems on Tru64, HP-UX - - Fixed compile problems with Intel C++, Compaq C++ - -* 1.3.14, 2004-06-12 - - Added support for AEP's AEP1000/AEP2000 crypto cards - - Added a Mutex module using Qt, from Justin Karneges - - Added support for engine loading in LibraryInitializer - - Tweaked SecureAllocator, giving 20% better performance under heavy load - - Added timer and memory locking modules for Win32 (tm_win32, ml_win32) - - Renamed PK_Engine to Engine_Core - - Improved the Karatsuba cutoff points - - Fixes for compiling with GCC 3.4 and Sun C++ 5.5 - - Fixes for Linux/s390, OpenBSD, and Solaris - - Added support for Linux/s390x - - The configure script was totally broken for 'generic' OS - - Removed Montgomery reduction due to bugs - - Removed an unused header, pkcs8alg.h - - check --validate returns an error code if any tests failed - - Removed duplicate entry in Unix command list for es_unix - - Moved the Cert_Usage enumeration into X509_Store - - Added new timing methods for PK benchmarks, clock_gettime and RDTSC - - Fixed a few minor bugs in the configure script - - Removed some deprecated functions from x509cert.h and pkcs10.h - - Removed the 'minimal' module, has to be updated for Engine support - - Changed MP_WORD_BITS macro to BOTAN_MP_WORD_BITS to clean up namespace - - Documentation updates - -* 1.3.13, 2004-05-15 - - Major fixes for Cygwin builds - - Minor MacOS X install fixes - - The configure script is a little better at picking the right modules - - Removed ml_unix from the 'unix' module set for Cygwin compatibility - - Fixed a stupid compile problem in pkcs10.h - -* 1.3.12, 2004-05-02 - - Added ability to remove old entries from CRLs - - Swapped the first two arguments of X509_CA::update_crl() - - Added an < operator for MemoryRegion, so it can be used as a std::map key - - Changed X.509 searching by DNS name from substring to full string compares - - Renamed a few X509_Certificate and PKCS10_Request member functions - - Fixed a problem when decoding some PKCS #10 requests - - Hex_Decoder would not check inputs, reported by Vaclav Ovsik - - Changed default CRL expire time from 30 days to 7 days - - X509_CRL's default PEM header is now "X509 CRL", for OpenSSL compatibility - - Corrected errors in the API doc, fixes from Ken Perano - - More documentation about the Pipe/Filter code - -* 1.3.11, 2004-04-01 - - Fixed two show-stopping bugs in PKCS10_Request - - Added some sanity checks in Pipe/Filter - - The DNS and URI entries would get swapped in subjectAlternativeNames - - MAC_Filter is now willing to not take a key at creation time - - Setting the expiration times of certs and CRLs is more flexible - - Fixed problems building on AIX with GCC - - Fixed some problems in the tutorial pointed out by Dominik Vogt - - Documentation updates - -* 1.3.10, 2004-03-27 - - Added support for OpenPGP's ASCII armor format - - Cleaned up the RNG system; seeding is much more flexible - - Added simple autoconfiguration abilities to configure.pl - - Fixed a GCC 2.95.x compile problem - - Updated the example configuration file - - Documentation updates - -* 1.3.9, 2004-03-07 - - Added an engine using OpenSSL (requires 0.9.7 or later) - - X509_Certificate would lose email addresses stored in the DN - - Fixed a missing initialization in a BigInt constructor - - Fixed several Visual C++ compile problems - - Fixed some BeOS build problems - - Fixed the WiderWake benchmark - -* 1.3.8, 2003-12-30 - - Internal changes to PK algorithms to divide data and algorithms - - DSA/DH/NR/ElGamal constructors accept taking just the private key again - - ElGamal keys now support being imported/exported as ASN.1 objects - - Much more consistent and complete error checking in PK algorithms - - Support for arbitrary backends (engines) for PK operations - - Added Montgomery reductions - - Added an engine that uses GNU MP (requires 4.1 or later) - - Removed the obsolete mp_gmp module - - Moved several initialization/shutdown functions to init.h - - Major refactoring of the memory containers - - New non-locking container, MemoryVector - - Fixed 64-bit problems in BigInt::set_bit/clear_bit - - Renamed PK_Key::check_params() to check_key() - - Some incompatible changes to OctetString - - Added version checking macros in version.h - - Removed the fips140 module pending rewrite - - Added some functions and hooks to help GUIs - - Moved more shared code into MDx_HashFunction - - Added a policy hook for specifying the encoding of X.509 strings - -* 1.3.7, 2003-12-12 - - Fixed a big security problem in es_unix - - Fixed several stability problems in es_unix - - Expanded the list of programs es_unix will try to use - - SecureAllocator now only preallocates blocks in special cases - - Added a special case in Global_RNG::seed for forcing a full poll - - Removed the FIPS 186 RNG added in 1.3.5 pending further testing - - Configure updates for PowerPC CPUs - - Removed the (never tested) VAX support - - Added support for S/390 Linux - -* 1.3.6, 2003-12-07 - - Added a new module 'minimal', which disables most algorithms - - SecureAllocator allocates a few blocks at startup - - A few minor MPI cleanups - - RPM spec file cleanups and fixes - -* 1.3.5, 2003-11-30 - - Major improvements in ASN.1 string handling - - Added partial support for ASN.1 UTF8 STRINGs and BMP STRINGs - - Added partial support for the X.509v3 certificate policies extension - - Centralized the handling of character set information - - Added FIPS 140-2 startup self tests - - Added a module (fips140) for doing extra FIPS 140-2 tests - - Added FIPS 186-2 RNG - - Improved ASN.1 BIT STRING handling - - Removed a memory leak in PKCS10_Request - - The encoding of DirectoryString now follows PKIX guidelines - - Fixed some of the character set dependencies - - Fixed a DER encoding error for tags greater than 30 - - The BER decoder can now handle tags larger than 30 - - Fixed tm_hard.cpp to recognize SPARC on more systems - - Workarounds for a GCC 2.95.x bug in x509find.cpp - - RPM changed to install into /usr instead of /usr/local - - Added support for QNX - -* 1.2.8, 2003-11-21 - - Merged several important bug fixes from 1.3.x - -* 1.3.4, 2003-11-21 - - Added a module that does certain MPI operations using GNU MP - - Added the X9.42 Diffie-Hellman PRF - - The Zlib and Bzip2 objects now use custom allocators - - Added member functions for directly hashing/MACing SecureVectors - - Minor optimizations to the MPI addition and subtraction algorithms - - Some cleanups in the low-level MPI code - - Created separate AES-{128,192,256} objects - -* 1.3.3, 2003-11-17 - - The library can now be repeatedly initialized and shutdown without crashing - - Fixed an off-by-one error in the CTS code - - Fixed an error in the EMSA4 verification code - - Fixed a memory leak in mutex.cpp (pointed out by James Widener) - - Fixed a memory leak in Pthread_Mutex - - Fixed several memory leaks in the testing code - - Bulletproofed the EMSA/EME/KDF/MGF retrieval functions - - Minor cleanups in SecureAllocator - - Removed a needless mutex guarding the (stateless) global timer - - Fixed a piece of bash-specific code in botan-config - - X.509 objects report more information about decoding errors - - Cleaned up some of the exception handling - - Updated the example config file with new OIDSs - - Moved the build instructions into a separate document, building.tex - -* 1.3.2, 2003-11-13 - - Fixed a bug preventing DSA signatures from verifying on X.509 objects - - Made the X509_Store search routines more efficient and flexible - - Added a function to X509_PublicKey to do easy public/private key matching - - Added support for decoding indefinite length BER data - - Changed Pipe's peek() to take an offset - - Removed Filter::set_owns in favor of the new incr_owns function - - Removed BigInt::zero() and BigInt::one() - - Renamed the PEM related options from base/pem_* to pem/* - - Added an option to specify the line width when encoding PEM - - Removed the "rng/safe_longterm" option; it's always on now - - Changed the cipher used for RNG super-encryption from ARC4 to WiderWake4+1 - - Cleaned up the base64/hex encoders and decoders - - Added an ASN.1/BER decoder as an example - - AES had its internals marked 'public' in previous versions - - Changed the value of the ASN.1 NO_OBJECT enum - - Various new hacks in the configure script - - Removed the already nominal support for SunOS - -* 1.3.1, 2003-11-04 - - Generalized a few pieces of the DER encoder - - PKCS8::load_key would fail if handed an unencrypted key - - Added a failsafe so PKCS #8 key decoding can't go into an infinite loop - -* 1.3.0, 2003-11-02 - - Major redesign of the PKCS #8 private key import/export system - - Added a small amount of UI interface code for getting passphrases - - Added heuristics that tell if a key, cert, etc is stored as PEM or BER - - Removed CS-Cipher, SHARK, ThreeWay, MD5-MAC, and EMAC - - Removed certain deprecated constructors of RSA, DSA, DH, RW, NR - - Made PEM decoding more forgiving of extra text before the header - -* 1.2.7, 2003-10-31 - - Added support for reading configuration files - - Added constructors so NR and RW keys can be imported easily - - Fixed mp_asm64, which was completely broken in 1.2.6 - - Removed tm_hw_ia32 module; replaced by tm_hard - - Added support for loading certain oddly formed RSA certificates - - Fixed spelling of NON_REPUDIATION enum - - Renamed the option default_to_ca to v1_assume_ca - - Fixed a minor bug in X.509 certificate generation - - Fixed a latent bug in the OID lookup code - - Updated the RPM spec file - - Added to the tutorial - -* 1.2.6, 2003-07-04 - - Major performance increase for PK algorithms on most 64-bit systems - - Cleanups in the low-level MPI code to support asm implementations - - Fixed build problems with some versions of Compaq's C++ compiler - - Removed useless constructors for NR public and private keys - - Removed support for the patch_file directive in module files - - Removed several deprecated functions - -* 1.2.5, 2003-06-22 - - Fixed a tricky and long-standing memory leak in Pipe - - Major cleanups and fixes in the memory allocation system - - Removed alloc_mlock, which has been superseded by the ml_unix module - - Removed a denial of service vulnerability in X509_Store - - Fixed compilation problems with VS .NET 2003 and Codewarrior 8 - - Added another variant of PKCS8::load_key, taking a memory buffer - - Fixed various minor/obscure bugs which occurred when MP_WORD_BITS != 32 - - BigInt::operator%=(word) was a no-op if the input was a power of 2 - - Fixed portability problems in BigInt::to_u32bit - - Fixed major bugs in SSL3-MAC - - Cleaned up some messes in the PK algorithms - - Cleanups and extensions for OMAC and EAX - - Made changes to the entropy estimation function - - Added a 'beos' module set for use on BeOS - - Officially deprecated a few X509:: and PKCS8:: functions - - Moved the contents of primes.h to numthry.h - - Moved the contents of x509opt.h to x509self.h - - Removed the (empty) desx.h header - - Documentation updates - -* 1.2.4, 2003-05-29 - - Fixed a bug in EMSA1 affecting NR signature verification - - Fixed a few latent bugs in BigInt related to word size - - Removed an unused function, mp_add2_nc, from the MPI implementation - - Reorganized the core MPI files - -* 1.2.3, 2003-05-20 - - Fixed a bug that prevented DSA/NR key generation - - Fixed a bug that prevented importing some root CA certs - - Fixed a bug in the BER decoder when handing optional bit or byte strings - - Fixed the encoding of authorityKeyIdentifier in X509_CA - - Added a sanity check in PBKDF2 for zero length passphrases - - Added versions of X509::load_key and PKCS8::load_key that take a file name - - X509_CA generates 128 bit serial numbers now - - Added tests to check PK key generation - - Added a simplistic X.509 CA example - - Cleaned up some of the examples - -* 1.2.2, 2003-05-13 - - Add checks to prevent any BigInt bugs from revealing an RSA or RW key - - Changed the interface of Global_RNG::seed - - Major improvements for the es_unix module - - Added another Win32 entropy source, es_win32 - - The Win32 CryptoAPI entropy source can now poll multiple providers - - Improved the BeOS entropy source - - Renamed pipe_unixfd module to fd_unix - - Fixed a file descriptor leak in the EGD module - - Fixed a few locking bugs - -* 1.2.1, 2003-05-06 - - Added ANSI X9.23 compatible CBC padding - - Added an entropy source using Win32 CryptoAPI - - Removed the Pipe I/O operators taking a FILE* - - Moved the BigInt encoding/decoding functions into the BigInt class - - Integrated several fixes for VC++ 7 (from Hany Greiss) - - Fixed the configure.pl script for Windows builds - -* 1.2.0, 2003-04-28 - - Tweaked the Karatsuba cut-off points - - Increased the allowed keylength of HMAC and Blowfish - - Removed the 'mpi_ia32' module, pending rewrite - - Workaround a GCC 2.95.x bug in eme1.cpp - -* 1.1.13, 2003-04-22 - - Added OMAC - - Added EAX authenticated cipher mode - - Diffie-Hellman would not do blinding in some cases - - Optimized the OFB and CTR modes - - Corrected Skipjack's word ordering, as per NIST clarification - - Support for all subject/issuer attribute types required by RFC 3280 - - The removeFromCRL CRL reason code is now handled correctly - - Increased the flexibility of the allocators - - Renamed Rijndael to AES, created aes.h, deleted rijndael.h - - Removed support for the 'no_timer' LibraryInitializer option - - Removed 'es_pthr' module, pending further testing - - Cleaned up get_ciph.cpp - -* 1.1.12, 2003-04-15 - - Fixed a ASN.1 string encoding bug - - Fixed a pair of X509_DN encoding problems - - Base64_Decoder and Hex_Decoder can now validate input - - Removed support for the LibraryInitializer option 'egd_path' - - Added tests for DSA X.509 and PKCS #8 key formats - - Removed a long deprecated feature of DH_PrivateKey's constructor - - Updated the RPM .spec file - - Major documentation updates - -* 1.1.11, 2003-04-07 - - Added PKCS #10 certificate requests - - Changed X509_Store searching interface to be more flexible - - Added a generic Certificate_Store interface - - Added a function for generating self-signed X.509 certs - - Cleanups and changes to X509_CA - - New examples for PKCS #10 and self-signed certificates - - Some documentation updates - -* 1.1.10, 2003-04-03 - - X509_CA can now generate new X.509 CRLs - - Added blinding for RSA, RW, DH, and ElGamal to prevent timing attacks - - More certificate and CRL extensions/attributes are supported - - Better DN handling in X.509 certificates/CRLs - - Added a DataSink hierarchy (suggested by Jim Darby) - - Consolidated SecureAllocator and ManagedAllocator - - Many cleanups and generalizations - - Added a (slow) pthreads based EntropySource - - Fixed some threading bugs - -* 1.1.9, 2003-02-25 - - Added support for using X.509v2 CRLs - - Fixed several bugs in the path validation algorithm - - Certificates can be verified for a particular usage - - Algorithm for comparing distinguished names now follows X.509 - - Cleaned up the code for the es_beos, es_ftw, es_unix modules - - Documentation updates - -* 1.1.8, 2003-01-29 - - Fixes for the certificate path validation algorithm in X509_Store - - Fixed a bug affecting X509_Certificate::is_ca_cert() - - Added a general configuration interface for policy issues - - Cleanups and API changes in the X.509 CA, cert, and store code - - Made various options available for X509_CA users - - Changed X509_Time's interface to work around time_t problems - - Fixed a theoretical weakness in Randpool's entropy mixing function - - Fixed problems compiling with GCC 2.95.3 and GCC 2.96 - - Fixed a configure bug (reported by Jon Wilson) affecting MinGW - -* 1.1.7, 2003-01-12 - - Fixed an obscure but dangerous bug in SecureVector::swap - - Consolidated SHA-384 and SHA-512 to save code space - - Added SSL3-MAC and SSL3-PRF - - Documentation updates, including a new tutorial - -* 1.0.2, 2003-01-12 - - Fixed an obscure SEGFAULT causing bug in Pipe - - Fixed an obscure but dangerous bug in SecureVector::swap - -* 1.1.6, 2002-12-10 - - Initial support for X.509v3 certificates and CAs - - Major redesign/rewrite of the ASN.1 encoding/decoding code - - Added handling for DSA/NR signatures encoded as DER SEQUENCEs - - Documented the generic cipher lookup interface - - Added an (untested) entropy source for BeOS - - Various cleanups and bug fixes - -* 1.1.5, 2002-11-17 - - Added the discrete logarithm integrated encryption system (DLIES) - - Various optimizations for BigInt - - Added support for assembler optimizations in modules - - Added BigInt x86 optimizations module (mpi_ia32) - -* 1.1.4, 2002-11-10 - - Speedup of 15-30% for PK algorithms - - Implemented the PBES2 encryption scheme - - Fixed a potential bug in decoding RSA and RW private keys - - Changed the DL_Group class interface to handle different formats better - - Added support for PKCS #3 encoded DH parameters - - X9.42 DH parameters use a PEM label of 'X942 DH PARAMETERS' - - Added key pair consistency checking - - Fixed a compatibility problem with gcc 2.96 (pointed out by Hany Greiss) - - A botan-config script is generated at configure time - - Documentation updates - -* 1.1.3, 2002-11-03 - - Added a generic public/private key loading interface - - Fixed a small encoding bug in RSA, RW, and DH - - Changed the PK encryption/decryption interface classes - - ECB supports using padding methods - - Added a function-based interface for library initialization - - Added support for RIPEMD-128 and Tiger PKCS#1 v1.5 signatures - - The cipher mode benchmarks now use 128-bit AES instead of DES - - Removed some obsolete typedefs - - Removed OpenCL support (opencl.h, the OPENCL_* macros, etc) - - Added tests for PKCS #8 encoding/decoding - - Added more tests for ECB and CBC - -* 1.1.2, 2002-10-21 - - Support for PKCS #8 encoded RSA, DSA, and DH private keys - - Support for Diffie-Hellman X.509 public keys - - Major reorganization of how X.509 keys are handled - - Added PKCS #5 v2.0's PBES1 encryption scheme - - Added a generic cipher lookup interface - - Added the WiderWake4+1 stream cipher - - Added support for sync-able stream ciphers - - Added a 'paranoia level' option for the LibraryInitializer - - More security for RNG output meant for long term keys - - Added documentation for some of the new 1.1.x features - - CFB's feedback argument is now specified in bits - - Renamed CTR class to CTR_BE - - Updated the RSA and DSA examples to use X.509 and PKCS #8 key formats - -* 1.1.1, 2002-10-15 - - Added the Korean hash function HAS-160 - - Partial support for RSA and DSA X.509 public keys - - Added a mostly functional BER encoder/decoder - - Added support for non-deterministic MAC functions - - Initial support for PEM encoding/decoding - - Internal cleanups in the PK algorithms - - Several new convenience functions in Pipe - - Fixed two nasty bugs in Pipe - - Messed with the entropy sources for es_unix - - Discrete logarithm groups are checked for safety more closely now - - For compatibility with GnuPG, ElGamal now supports DSA-style groups - -* 1.1.0, 2002-09-14 - - Added entropy estimation to the RNGs - - Improved the overall design of both Randpool and ANSI_X917_RNG - - Added a separate RNG for nonce generation - - Added window exponentiation support in power_mod - - Added a get_s2k function and the PKCS #5 S2K algorithms - - Added the TLSv1 PRF - - Replaced BlockCipherModeIV typedef with InitializationVector class - - Renamed PK_Key_Agreement_Scheme to PK_Key_Agreement - - Renamed SHA1 -> SHA_160 and SHA2_x -> SHA_x - - Added support for RIPEMD-160 PKCS#1 v1.5 signatures - - Changed the key agreement scheme interface - - Changed the S2K and KDF interfaces - - Better SCAN compatibility for HAVAL, Tiger, MISTY1, SEAL, RC5, SAFER-SK - - Added support for variable-pass Tiger - - Major speedup for Rabin-Williams key generation - -* 1.0.1, 2002-09-14 - - Fixed a minor bug in Randpool::random() - - Added some new aliases and typedefs for 1.1.x compatibility - - The 4096-bit RSA benchmark key was decimal instead of hex - - EMAC was returning an incorrect name - -* 1.0.0, 2002-08-26 - - Octal I/O of BigInt is now supported - - Fixed portability problems in the es_egd module - - Generalized IV handling in the block cipher modes - - Added Karatsuba multiplication and k-ary exponentiation - - Fixed a problem in the multiplication routines - -* 0.9.2, 2002-08-18 - - DH_PrivateKey::public_value() was returning the wrong value - - Various BigInt optimizations - - The filters.h header now includes hex.h and base64.h - - Moved Counter mode to ctr.h - - Fixed a couple minor problems with VC++ 7 - - Fixed problems with the RPM spec file - -* 0.9.1, 2002-08-10 - - Grand rename from OpenCL to Botan - - Major optimizations for the PK algorithms - - Added ElGamal encryption - - Added Whirlpool - - Tweaked memory allocation parameters - - Improved the method of seeding the global RNG - - Moved pkcs1.h to eme_pkcs.h - - Added more test vectors for some algorithms - - Fixed error reporting in the BigInt tests - - Removed Default_Timer, it was pointless - - Added some new example applications - - Removed some old examples that weren't that interesting - - Documented the compression modules - -* 0.9.0, 2002-08-03 - - EMSA4 supports variable salt size - - PK_* can take a string naming the encoding method to use - - Started writing some internals documentation - -* 0.8.7, 2002-07-30 - - Fixed bugs in EME1 and EMSA4 - - Fixed a potential crash at shutdown - - Cipher modes returned an ill-formed name - - Removed various deprecated types and headers - - Cleaned up the Pipe interface a bit - - Minor additions to the documentation - - First stab at a Visual C++ makefile (doc/Makefile.vc7) - -* 0.8.6, 2002-07-25 - - Added EMSA4 (aka PSS) - - Brought the manual up to date; many corrections and additions - - Added a parallel hash function construction - - Lookup supports all available algorithms now - - Lazy initialization of the lookup tables - - Made more discrete logarithm groups available through get_dl_group() - - StreamCipher_Filter supports seeking (if the underlying cipher does) - - Minor optimization for GCD calculations - - Renamed SAFER_SK128 to SAFER_SK - - Removed many previously deprecated functions - - Some now-obsolete functions, headers, and types have been deprecated - - Fixed some bugs in DSA prime generation - - DL_Group had a constructor for DSA-style prime gen but it wasn't defined - - Reversed the ordering of the two arguments to SEAL's constructor - - Fixed a threading problem in the PK algorithms - - Fixed a minor memory leak in lookup.cpp - - Fixed pk_types.h (it was broken in 0.8.5) - - Made validation tests more verbose - - Updated the check and example applications - -* 0.8.5, 2002-07-21 - - Major changes to constructors for DL-based cryptosystems (DSA, NR, DH) - - Added a DL_Group class - - Reworking of the pubkey internals - - Support in lookup for aliases and PK algorithms - - Renamed CAST5 to CAST_128 and CAST256 to CAST_256 - - Added EMSA1 - - Reorganization of header files - - LibraryInitializer will install new allocator types if requested - - Fixed a bug in Diffie-Hellman key generation - - Did a workaround in pipe.cpp for GCC 2.95.x on Linux - - Removed some debugging code from init.cpp that made FTW ES useless - - Better checking for invalid arguments in the PK algorithms - - Reduced Base64 and Hex default line length (if line breaking is used) - - Fixes for HP's aCC compiler - - Cleanups in BigInt - -* 0.8.4, 2002-07-14 - - Added Nyberg-Rueppel signatures - - Added Diffie-Hellman key exchange (kex interface is subject to change) - - Added KDF2 - - Enhancements to the lookup API - - Many things formerly taking pointers to algorithms now take names - - Speedups for prime generation - - LibraryInitializer has support for seeding the global RNG - - Reduced SAFER-SK128 memory consumption - - Reversed the ordering of public and private key values in DSA constructor - - Fixed serious bugs in MemoryMapping_Allocator - - Fixed memory leak in Lion - - FTW_EntropySource was not closing the files it read - - Fixed line breaking problem in Hex_Encoder - -* 0.8.3, 2002-06-09 - - Added DSA and Rabin-Williams signature schemes - - Added EMSA3 - - Added PKCS#1 v1.5 encryption padding - - Added Filters for PK algorithms - - Added a Keyed_Filter class - - LibraryInitializer processes arguments now - - Major revamp of the PK interface classes - - Changed almost all of the Filters for non-template operation - - Changed HMAC, Lion, Luby-Rackoff to non-template classes - - Some fairly minor BigInt optimizations - - Added simple benchmarking for PK algorithms - - Added hooks for fixed base and fixed exponent modular exponentiation - - Added some examples for using RSA - - Numerous bugfixes and cleanups - - Documentation updates - -* 0.8.2, 2002-05-18 - - Added an (experimental) algorithm lookup interface - - Added code for directly testing BigInt - - Added SHA2-384 - - Optimized SHA2-512 - - Major optimization for Adler32 (thanks to Dan Nicolaescu) - - Various minor optimizations in BigInt and related areas - - Fixed two bugs in X9.19 MAC, both reported by Darren Starsmore - - Fixed a bug in BufferingFilter - - Made a few fixes for MacOS X - - Added a workaround in configure.pl for GCC 2.95.x - - Better support for PowerPC, ARM, and Alpha - - Some more cleanups - -* 0.8.1, 2002-05-06 - - Major code cleanup (check doc/deprecated.txt) - - Various bugs fixed, including several portability problems - - Renamed MessageAuthCode to MessageAuthenticationCode - - A replacement for X917 is in x917_rng.h - - Changed EMAC to non-template class - - Added ANSI X9.19 compatible CBC-MAC - - TripleDES now supports 128 bit keys - -* 0.8.0, 2002-04-24 - - Merged BigInt: many bugfixes and optimizations since alpha2 - - Added RSA (rsa.h) - - Added EMSA2 (emsa2.h) - - Lots of new interface code for public key algorithms (pk_base.h, pubkey.h) - - Changed some interfaces, including SymmetricKey, to support the global rng - - Fixed a serious bug in ManagedAllocator - - Renamed RIPEMD128 to RIPEMD_128 and RIPEMD160 to RIPEMD_160 - - Removed some deprecated stuff - - Added a global random number generator (rng.h) - - Added clone functions to most of the basic algorithms - - Added a library initializer class (init.h) - - Version macros in version.h - - Moved the base classes from opencl.h to base.h - - Renamed the bzip2 module to comp_bzip2 and zlib to comp_zlib - - Documentation updates for the new stuff (still incomplete) - - Many new deprecated things: check doc/deprecated.txt - -* 0.7.10, 2002-04-07 - - Added EGD_EntropySource module (es_egd) - - Added a file tree walking EntropySource (es_ftw) - - Added MemoryLocking_Allocator module (alloc_mlock) - - Renamed the pthr_mux, unix_rnd, and mmap_mem modules - - Changed timer mechanism; the clock method can be switched on the fly. - - Renamed MmapDisk_Allocator to MemoryMapping_Allocator - - Renamed ent_file.h to es_file.h (ent_file.h is around, but deprecated) - - Fixed several bugs in MemoryMapping_Allocator - - Added more default sources for Unix_EntropySource - - Changed SecureBuffer to use same allocation methods as SecureVector - - Added bigint_divcore into mp_core to support BigInt alpha2 release - - Removed some Pipe functions deprecated since 0.7.8 - - Some fixes for the configure program - -* 0.7.9, 2002-03-19 - - Memory allocation substantially revamped - - Added memory allocation method based on mmap(2) in the mmap_mem module - - Added ECB and CTS block cipher modes (ecb.h, cts.h) - - Added a Mutex interface (mutex.h) - - Added module pthr_mux, implementing the Mutex interface - - Added Threaded Filter interface (thr_filt.h) - - All algorithms can now by keyed with SymmetricKey objects - - More testing occurs with --validate (expected failures) - - Fixed two bugs reported by Hany Greiss, in Luby-Rackoff and RC6 - - Fixed a buffering bug in Bzip_Decompress and Zlib_Decompress - - Made X917 safer (and about 1/3 as fast) - - Documentation updates - -* 0.7.8, 2002-02-28 - - More capabilities for Pipe, inspired by SysV STREAMS, including peeking, - better buffering, and stack ops. NOT BACKWARDS COMPATIBLE: SEE DOCUMENTATION - - Added a BufferingFilter class - - Added popen() based EntropySource for generic Unix systems (unix_rnd) - - Moved 'devrand' module into main distribution (ent_file.h), renamed to - File_EntropySource, and changed interface somewhat. - - Made Randpool somewhat more conservative and also 25% faster - - Minor fixes and updates for the configure script - - Added some tweaks for memory allocation - - Documentation updates for the new Pipe interface - - Fixed various minor bugs - - Added a couple of new example programs (stack and hasher2) - -* 0.7.7, 2001-11-24 - - Filter::send now works in the constructor of a Filter subclass - - You may now have to include <opencl/pipe.h> explicitly in some code - - Added preliminary PK infrastructure classes in pubkey.h and pkbase.h - - Enhancements to SecureVector (append, destroy functions) - - New infrastructure for secure memory allocation - - Added IEEE P1363 primitives MGF1, EME1, KDF1 - - Rijndael optimizations and cleanups - - Changed CipherMode<B> to BlockCipherMode(B*) - - Fixed a nasty bug in pipe_unixfd - - Added portions of the BigInt code into the main library - - Support for VAX, SH, POWER, PowerPC-64, Intel C++ - -* 0.7.6, 2001-10-14 - - Fixed several serious bugs in SecureVector created in 0.7.5 - - Square optimizations - - Fixed shared objects on MacOS X and HP-UX - - Fixed static libs for KCC 4.0; works with KCC 3.4g as well - - Full support for Athlon and K6 processors using GCC - - Added a table of prime numbers < 2**16 (primes.h) - - Some minor documentation updates - -* 0.7.5, 2001-08-19 - - Split checksum.h into adler32.h, crc24.h, and crc32.h - - Split modes.h into cbc.h, cfb.h, and ofb.h - - CBC_wPadding* has been replaced by CBC_Encryption and CBC_Decryption - - Added OneAndZeros and NoPadding methods for CBC - - Added Lion, a very fast block cipher construction - - Added an S2K base class (s2k.h) and an OpenPGP_S2K class (pgp_s2k.h) - - Basic types (ciphers, hashes, etc) know their names now (call name()) - - Changed the EntropySource type somewhat - - Big speed-ups for ISAAC, Adler32, CRC24, and CRC32 - - Optimized CAST-256, DES, SAFER-SK, Serpent, SEAL, MD2, and RIPEMD-160 - - Some semantics of SecureVector have changed slightly - - The mlock module has been removed for the time being - - Added string handling functions for hashes and MACs - - Various non-user-visible cleanups - - Shared library soname is now set to the full version number - -* 0.7.4, 2001-07-15 - - New modules: Zlib, gettimeofday and x86 RTC timers, Unix I/O for Pipe - - Fixed a vast number of errors in the config script/makefile/specfile - - Pipe now has a stdio(3) interface as well as C++ iostreams - - ARC4 supports skipping the first N bytes of the cipher stream (ala MARK4) - - Bzip2 supports decompressing multiple concatenated streams, and flushing - - Added a simple 'overall average' score to the benchmarks - - Fixed a small bug in the POSIX timer module - - Removed a very-unlikely-to-occur bug in most of the hash functions - - filtbase.h now includes <iosfwd>, not <iostream> - - Minor documentation updates - -* 0.7.3, 2001-06-08 - - Fix build problems on Solaris/SPARC - - Fix build problems with Perl versions < 5.6 - - Fixed some stupid code that broke on a few compilers - - Added string handling functions to Pipe - - MISTY1 optimizations - -* 0.7.2, 2001-06-03 - - Build system supports modules - - Added modules for mlock, a /dev/random EntropySource, POSIX1.b timers - - Added Bzip2 compression filter, contributed by Peter Jones - - GNU make no longer required (tested with 4.4BSD pmake and Solaris make) - - Fixed minor bug in several of the hash functions - - Various other minor fixes and changes - - Updates to the documentation - -* 0.7.1, 2001-05-16 - - Rewrote configure script: more consistent and complete - - Made it easier to find out parameters of types at run time (opencl.h) - - New functions for finding the version being used (version.h) - - New SymmetricKey interface for Filters (symkey.h) - - InvalidKeyLength now records what the invalid key length was - - Optimized DES, CS-Cipher, MISTY1, Skipjack, XTEA - - Changed GOST to use correct S-box ordering (incompatible change) - - Benchmark code was almost totally rewritten - - Many more entries in the test vector file - - Fixed minor and idiotic bug in check.cpp - -* 0.7.0, 2001-03-01 - - First public release +.. _relnotes: + +Release Notes +======================================== + +Series 1.10 +---------------------------------------- + +Version 1.10.0, Not Yet Released +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +Series 1.9 +---------------------------------------- + +Version 1.9.18, 2011-06-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fourth release candidate for 1.10.0 + +* The GOST 34.10 verification operation was not ensuring that s and r + were both greater than zero. This could potentially have meant it + would have accepted an invalid all-zero signature as valid for any + message. Due to how ECC points are internally represented it instead + resulted in an exception being thrown. + +* A simple multiexponentation algorithm is now used in ECDSA and + GOST-34.10 signature verification, leading to 20 to 25% improvements + in ECDSA and 25% to 40% improvements in GOST-34.10 verification + performance. + +* The internal representation of elliptic curve points has been + modified to use Montgomery representation exclusively, resulting in + reduced memory usage and a 10 to 20% performance improvement for + ECDSA and ECDH. + +* In OAEP decoding, scan for the delimiter bytes using a loop that is + written without conditionals so as to help avoid timing analysis. + Unfortunately GCC at least is 'smart' enough to compile it to + jumps anyway. + +* The SSE2 implementation of IDEA did not work correctly when compiled + by Clang, because the trick it used to emulate a 16 bit unsigned + compare in SSE (which doesn't contain one natively) relied on signed + overflow working in the 'usual' way. A different method that doesn't + rely on signed overflow is now used. + +* Add support for compiling SSL using Visual C++ 2010's TR1 + implementation. + +* Fix a bug under Visual C++ 2010 which would cause ``hex_encode`` to + crash if given a zero-sized input to encode. + +* A new build option ``--via-amalgamation`` will first generate the + single-file amalgamation, then build the library from that single + file. This option requires a lot of memory and does not parallelize, + but the resulting library is smaller and may be faster. + +* On Unix, the library and header paths have been changed to allow + parallel installation of different versions of the library. Headers + are installed into ``<prefix>/include/botan-1.9/botan``, libraries + are named ``libbotan-1.9``, and ``botan-config`` is now namespaced + (so in this release ``botan-config-1.9``). All of these embedded + versions will be 1.10 in the upcoming stable release. + +* The soname system has been modified. In this release the library + soname is ``libbotan-1.9.so.0``, with the full library being named + ``libbotan-1.9.so.0.18``. The ``0`` is the ABI version, and will be + incremented whenever a breaking ABI change is made. + +* TR1 support is not longer automatically assumed under older versions + of GCC + +* Functions for base64 decoding that work standalone (without needing + to use a pipe) have been added to ``base64.h`` + +* The function ``BigInt::to_u32bit`` was inadvertently removed in 1.9.11 + and has been added back. + +* The function ``BigInt::get_substring`` did not work correctly with a + *length* argument of 32. + +* The implementation of ``FD_ZERO`` on Solaris uses ``memset`` and + assumes the caller included ``string.h`` on its behalf. Do so to + fix compilation in the ``dev_random`` and ``unix_procs`` entropy + sources. Patch from Jeremy C. Reed. + +* Add two different configuration targets for Atom, since some are + 32-bit and some are 64-bit. The 'atom' target now refers to the + 64-bit implementations, use 'atom32' to target the 32-bit + processors. + +* The (incomplete) support for CMS and card verifiable certificates + are disabled by default; add ``--enable-modules=cms`` or + ``--enable-modules=cvc`` during configuration to turn them back on. + +Version 1.9.17, 2011-04-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Third release candidate for 1.10.0 + +* The format preserving encryption method currently available was + presented in the header ``fpe.h`` and the functions ``fpe_encrypt`` + and ``fpe_decrypt``. These were renamed as it is likely that other + FPE schemes will be included in the future. The header is now + ``fpe_fe1.h``, and the functions are named ``fe1_encrypt`` and + ``fe1_decrypt``. See :doc:`fpe` for more information. + +* New options to ``configure.py`` control what tools are used for + documentation generation. The ``--with-sphinx`` option enables using + Sphinx to convert ReST into HTML; otherwise the ReST sources are + installed directly. If ``--with-doxygen`` is used, Doxygen will run + as well. Documentation generation can be triggered via the ``docs`` + target in the makefile; it will also be installed by the install + target on Unix. + +* A bug in 1.9.16 effectively disabled support for runtime CPU feature + detection on x86 under GCC in that release. + +* A mostly internal change, all references to "ia32" and "amd64" have + been changed to the vendor neutral and probably easier to understand + "x86-32" and "x86-64". For instance, the "mp_amd64" module has been + renamed "mp_x86_64", and the macro indicating x86-32 has changed + from ``BOTAN_TARGET_ARCH_IS_IA32`` to + ``BOTAN_TARGET_ARCH_IS_X86_32``. The classes calling assembly have + also been renamed. + +* Similiarly to the above change, the AES implemenations using the + AES-NI instruction set have been renamed from AES_XXX_Intel to + AES_XXX_NI. + +* Systems that are identified as `sun4u` will default to compiling for + 32-bit SPARCv9 code rather than 64-bit. This matches the still + common convention for 32-bit SPARC userspaces. If you want 64-bit + code on such as system, use ``--cpu=sparc64``. + +* Some minor fixes for compiling botan under the BeOS + clone/continuation `Haiku <http://haiku-os.org>`_. + +* Further updates to the documentation + +Version 1.9.16, 2011-04-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Second release candidate for 1.10.0 + +* The documentation, previously written in LaTeX, is now in + reStructuredText suitable for processing by `Sphinx + <http://sphinx.pocoo.org>`_, which can generate nicely formatted + HTML and PDFs. The documentation has also been greatly updated and + expanded. + +* The class ``EC_Domain_Params`` has been renamed ``EC_Group``, with a + typedef for backwards compatability. + +* ``EC_Group``'s string constructor didn't understand the standard + names like "secp160r1", forcing use of the OIDs. + +* Two constructors for ECDSA private keys, the one that creates a new + random key, and the one that provides a preset private key as a + ``BigInt``, have been merged. This matches the existing interface + for DSA and DH keys. If you previously used the version taking a + ``BigInt`` private key, you'll have to additionally pass in a + ``RandomNumberGenerator`` object starting in this release. + +* It is now possible to create ECDH keys with a preset ``BigInt`` + private key; previously no method for this was available. + +* The overload of ``generate_passhash9`` that takes an explicit + algorithm identifier has been merged with the one that does not. + The algorithm identifier code has been moved from the second + parameter to the fourth. See :ref:`passhash9` for details. + +* Change shared library versioning to match the normal Unix + conventions. Instead of ``libbotan-X.Y.Z.so``, the shared lib is + named ``libbotan-X.Y.so.Z``; this allows the runtime linker to do + its runtime linky magic. It can be safely presumed that any change + in the major or minor version indicates ABI incompatability. + +* Remove the socket wrapper code; it was not actually used by anything + in the library, only in the examples, and you can use whatever kind + of (blocking) socket interface you like with the SSL/TLS code. It's + available as socket.h in the examples directory if you want to use + it. + +* Disable the by-default 'strong' checking of private keys that are + loaded from storage. You can always request key material sanity + checking using Private_Key::check_key. + +* Bring back removed functions ``min_keylength_of``, + ``max_keylength_of``, ``keylength_multiple_of`` in ``lookup.h`` to + avoid breaking applications written against 1.8 + +Version 1.9.15, 2011-03-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* First release candidate for 1.10.0 + +* Modify how message expansion is done in SHA-256 and SHA-512. + Instead of expanding the entire message at the start, compute them + in the minimum number of registers. Values are computed 15 rounds + before they are needed. On a Core i7-860, GCC 4.5.2, went from 143 + to 157 MiB/s in SHA-256, and 211 to 256 MiB/s in SHA-512. + +* Pipe will delete empty output queues as soon as they are no longer + needed, even if earlier messages still have data unread. However an + (empty) entry in a deque of pointers will remain until all prior + messages are completely emptied. + +* Avoid reading the SPARC ``%tick`` register on OpenBSD as unlike + Linux the kernel will not trap and emulate it for us, causing a + illegal instruction crash. + +* Improve detection and autoconfiguration for ARM processors. + +Version 1.9.14, 2011-03-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for bcrypt, OpenBSD's password hashing scheme. It is + described in :ref:`bcrypt`. + +* Add support for NIST's AES key wrapping algorithm, as described in + :rfc:`3394`. It is available by including ``rfc3394.h``. + +* Fix an infinite loop in zlib filters introduced in 1.9.11 (PR 142) + +Version 1.9.13, 2011-02-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Update Keccak to the round 3 variant +* Fix ordering in GOST 34.10 signatures to match DNSSEC specifications +* Use ``size_t`` instead of ``u32bit`` for small integers in DER/BER codecs +* Add new build option ``--distribution-info`` +* Fix problems in the amalgamation build +* Fix building under Clang 2.9 and Sun Studio 12 + +Version 1.9.12, 2010-12-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add the Keccak hash function +* Fix compilation problems in Python wrappers +* Fix compilation problem in OpenSSL engine +* Update SQLite3 database encryption codec + +Version 1.9.11, 2010-11-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Many SSL/TLS APIs have changed. This API is still unstable. +* The SSL interface requires TR1 (uses std::tr1::function) +* Fix SSL handshake failures when using RC4 ciphersuites +* Fix a number of CRL encoding and decoding bugs +* Counter mode now always encrypts 256 blocks in parallel +* Code where u32bit was used to represent a length now uses size_t +* Use small tables in the first round of AES +* Removed AES class: app must choose AES-128, AES-192, or AES-256 +* Add hex encoding/decoding functions that can be used without a Pipe +* Add base64 encoding functions that can be used without a Pipe +* Add to_string function to X509_Certificate +* Add support for dynamic engine loading on Windows +* Replace BlockCipher::BLOCK_SIZE attribute with function block_size() +* Replace HashFunction::HASH_BLOCK_SIZE attribute with hash_block_size() +* Changed semantics of MemoryRegion::resize and clear to match STL +* Removed MemoryRegion::append, replaced by push_back and operator+= +* Move PBKDF lookup to engine system +* The IDEA key schedule has been changed to run in constant time +* Avoid a possible timing vulnerability in Montgomery reduction +* Add Algorithm and Key_Length_Specification classes +* Switch default PKCS #8 encryption algorithm from AES-128 to AES-256 +* Update Skein-512 to match the v1.3 specification +* Allow using PBKDF2 with empty passphrases +* Add compile-time deprecation warnings for GCC, Clang, and MSVC +* Support use of HMAC(SHA-256) and CMAC(Blowfish) in passhash9 +* Improve support for Intel Atom processors +* Fix compilation problems under Sun Studio and Clang + +Version 1.9.10, 2010-08-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add a constant time AES implementation using SSSE3 +* Add support for loading new Engines at runtime +* Use GCC byteswap intrinsics where possible +* Drop support for building with Python 2.4 +* Fix benchmarking of block ciphers in ECB mode +* Consolidate the two x86 assembly engines +* Rename S2K to PBKDF + +Version 1.9.9, 2010-06-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add new X509::BER_encode and PKCS8::BER_encode +* Give all Filter objects a name() function +* Add Keyed_Filter::valid_iv_length +* Increase default iteration counts for private key encryption +* Fix compilation of mp_asm64 on 64-bit MIPS with GCC 4.4 and later +* Fix compilation under Apple's GCC 4.2 +* Expand and update the Doxygen documentation + +Version 1.9.8, 2010-06-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for wide multiplications on 64-bit Windows +* Use constant time multiplication in IDEA +* Avoid possible timing attack against OAEP decoding +* Removed FORK-256; rarely used and it has been broken +* Rename ``--use-boost-python`` to ``--with-boost-python`` +* Skip building shared libraries on MinGW/Cygwin +* Fix creation of 512 and 768 bit DL groups using the DSA kosherizer +* Fix compilation on GCC versions before 4.3 (missing cpuid.h) +* Fix compilation under the Clang compiler + +Version 1.9.7, 2010-04-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* TLS: Support reading SSLv2 client hellos +* TLS: Add support for SEED ciphersuites (RFC 4162) +* Add Comb4P hash combiner function +* Fix checking of EMSA_Raw signatures with leading 0 bytes + +Version 1.9.6, 2010-04-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* TLS: Add support for TLS v1.1 +* TLS: Support server name indicator extension +* TLS: Fix server handshake +* TLS: Fix server using DSA certificates +* TLS: Avoid timing channel between CBC padding check and MAC verification + +Version 1.9.5, 2010-03-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Numerous ECC optimizations +* Fix GOST 34.10-2001 X.509 key loading +* Allow PK_Signer's fault protection checks to be toggled off +* Avoid using pool-based locking allocator if we can't mlock +* Remove all runtime options +* New BER_Decoder::{decode_and_check, decode_octet_string_bigint} +* Remove SecureBuffer in favor of SecureVector length parameter +* HMAC_RNG: Perform a poll along with user-supplied entropy +* Fix crash in MemoryRegion if Allocator::get failed +* Fix small compilation problem on FreeBSD + +Version 1.9.4, 2010-03-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add the Ajisai SSLv3/TLSv1.0 implementation +* Add GOST 34.10-2001 public key signature scheme +* Add SIMD implementation of Noekeon +* Add SSE2 implementation of IDEA +* Extend Salsa20 to support longer IVs (XSalsa20) +* Perform XTS encryption and decryption in parallel where possible +* Perform CBC decryption in parallel where possible +* Add SQLite3 db encryption codec, contributed by Olivier de Gaalon +* Add a block cipher cascade construction +* Add support for password hashing for authentication (passhash9.h) +* Add support for Win32 high resolution system timers +* Major refactoring and API changes in the public key code +* Use consistency checking (anti-fault attack) for all signature schemes +* Changed S2K interface: derive_key now takes salt, iteration count +* Remove dependency on TR1 for ECC and CVC code +* Renamed ECKAEG to its more usual name, ECDH +* Fix crash in GMP_Engine if library is shutdown and reinitialized +* Fix an invalid memory read in MD4 +* Fix Visual C++ static builds +* Remove Timer class entirely +* Switch default PKCS #8 encryption algorithm from 3DES to AES-128 +* New option --gen-amalgamation for creating a SQLite-style amalgamation +* Many headers are now explicitly internal-use-only and are not installed +* Greatly improve the Win32 installer +* Several fixes for Visual C++ debug builds + +Version 1.9.3, 2009-11-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add new AES implementation using Intel's AES instruction intrinsics +* Add an implementation of format preserving encryption +* Allow use of any hash function in X.509 certificate creation +* Optimizations for MARS, Skipjack, and AES +* Set macros for available SIMD instructions in build.h +* Add support for using InnoSetup to package Windows builds +* By default build a DLL on Windows + +Version 1.9.2, 2009-11-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add SIMD version of XTEA +* Support both SSE2 and AltiVec SIMD for Serpent and XTEA +* Optimizations for SHA-1 and SHA-2 +* Add AltiVec runtime detection +* Fix x86 CPU identification with Intel C++ and Visual C++ + +Version 1.9.1, 2009-10-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Better support for Python and Perl wrappers +* Add an implementation of Blue Midnight Wish (Round 2 tweak version) +* Modify Skein-512 to match the tweaked 1.2 specification +* Add threshold secret sharing (draft-mcgrew-tss-02) +* Add runtime cpu feature detection for x86/x86-64 +* Add code for general runtime self testing for hashes, MACs, and ciphers +* Optimize XTEA; twice as fast as before on Core2 and Opteron +* Convert CTR_BE and OFB from filters to stream ciphers +* New parsing code for SCAN algorithm names +* Enable SSE2 optimizations under Visual C++ +* Remove all use of C++ exception specifications +* Add support for GNU/Hurd and Clang/LLVM + +Version 1.9.0, 2009-09-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for parallel invocation of block ciphers where possible +* Add SSE2 implementation of Serpent +* Add Rivest's package transform (an all or nothing transform) +* Minor speedups to the Turing key schedule +* Fix processing multiple messages in XTS mode +* Add --no-autoload option to configure.py, for minimized builds +* The previously used configure.pl script is no longer supported + +Series 1.8 +---------------------------------------- + +Version 1.8.11, 2010-11-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a number of CRL encoding and decoding bugs +* When building a debug library under VC++, use the debug runtime +* Fix compilation under Sun Studio on Linux and Solaris +* Add several functions for compatability with 1.9 +* In the examples, read most input files as binary +* The Perl build script has been removed in this release + +Version 1.8.10, 2010-08-31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Switch default PKCS #8 encryption algorithm from 3DES to AES-256 +* Increase default hash iterations from 2048 to 10000 in PBES1 and PBES2 +* Use small tables in the first round of AES +* Add PBKDF typedef and get_pbkdf for better compatability with 1.9 +* Add version of S2K::derive_key taking salt and iteration count +* Enable the /proc-walking entropy source on NetBSD +* Fix the doxygen makefile target + +Version 1.8.9, 2010-06-16 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Use constant time multiplication in IDEA +* Avoid possible timing attack against OAEP decoding +* Add new X509::BER_encode and PKCS8::BER_encode +* Enable DLL builds under Windows +* Add Win32 installer support +* Add support for the Clang compiler +* Fix problem in semcem.h preventing build under Clang or GCC 3.4 +* Fix bug that prevented creation of DSA groups under 1024 bits +* Fix crash in GMP_Engine if library is shutdown and reinitialized +* Work around problem with recent binutils in x86-64 SHA-1 +* The Perl build script is no longer supported and refuses to run by default + +Version 1.8.8, 2009-11-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Alter Skein-512 to match the tweaked 1.2 specification +* Fix use of inline asm for access to x86 bswap function +* Allow building the library without AES enabled +* Add 'powerpc64' alias to ppc64 arch for Gentoo ebuild + +Version 1.8.7, 2009-09-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix processing multiple messages in XTS mode +* Add --no-autoload option to configure.py, for minimized builds + +Version 1.8.6, 2009-08-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add Cryptobox, a set of simple password-based encryption routines +* Only read world-readable files when walking /proc for entropy +* Fix building with TR1 disabled +* Fix x86 bswap support for Visual C++ +* Fixes for compilation under Sun C++ +* Add support for Dragonfly BSD (contributed by Patrick Georgi) +* Add support for the Open64 C++ compiler +* Build fixes for MIPS systems running Linux +* Minor changes to license, now equivalent to the FreeBSD/NetBSD license + +Version 1.8.5, 2009-07-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Change configure.py to work on stock Python 2.4 +* Avoid a crash in Skein_512::add_data processing a zero-length input +* Small build fixes for SPARC, ARM, and HP-PA processors +* The test suite now returns an error code from main() if any tests failed + +Version 1.8.4, 2009-07-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a bug in nonce generation in the Miller-Rabin test + +Version 1.8.3, 2009-07-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add a new Python configuration script +* Add the Skein-512 SHA-3 candidate hash function +* Add the XTS block cipher mode from IEEE P1619 +* Fix random_prime when generating a prime of less than 7 bits +* Improve handling of low-entropy situations during PRNG seeding +* Change random device polling to prefer /dev/urandom over /dev/random +* Use an input insensitive implementation of same_mem instead of memcmp +* Correct DataSource::discard_next to return the number of discarded bytes +* Provide a default value for AutoSeeded_RNG::reseed +* Fix Gentoo bug 272242 + +Version 1.8.2, 2009-04-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Make entropy polling more flexible and in most cases faster +* GOST 28147 now supports multiple sbox parameters +* Added the GOST 34.11 hash function +* Fix botan-config problems on MacOS X + +Version 1.8.1, 2009-01-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Avoid a valgrind warning in es_unix.cpp on 32-bit Linux +* Fix memory leak in PKCS8 load_key and encrypt_key +* Relicense api.tex from CC-By-SA 2.5 to BSD +* Fix botan-config on MacOS X, Solaris + +Version 1.8.0, 2008-12-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix compilation on Solaris with GCC + +Series 1.7 +---------------------------------------- + +Version 1.7.24, 2008-12-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a compatibility problem with SHA-512/EMSA3 signature padding +* Fix bug preventing EGD/PRNGD entropy poller from working +* Fix integer overflow in Pooling_Allocator::get_more_core (bug id #27) +* Add EMSA3_Raw, a variant of EMSA3 called CKM_RSA_PKCS in PKCS #11 +* Add support for SHA-224 in EMSA2 and EMSA3 PK signature padding schemes +* Add many more test vectors for RSA with EMSA2, EMSA3, and EMSA4 +* Wrap private structs in SSE2 SHA-1 code in anonymous namespace +* Change configure.pl's CPU autodetection output to be more consistent +* Disable using OpenSSL's AES due to crashes of unknown cause +* Fix warning in /proc walking entropy poller +* Fix compilation with IBM XLC for Cell 0.9-200709 + +Version 1.7.23, 2008-11-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Change to use TR1 (thus enabling ECDSA) with GCC and ICC +* Optimize almost all hash functions, especially MD4 and Tiger +* Add configure.pl options --{with,without}-{bzip2,zlib,openssl,gnump} +* Change Timer to be pure virtual, and add ANSI_Clock_Timer +* Cache socket descriptors in the EGD entropy source +* Avoid bogging down startup in /proc walking entropy source +* Remove Buffered_EntropySource helper class +* Add a Default_Benchmark_Timer typedef in benchmark.h +* Add examples using benchmark.h and Algorithm_Factory +* Add ECC tests from InSiTo +* Minor documentation updates + +Version 1.7.22, 2008-11-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add provider preferences to Algorithm_Factory +* Fix memory leaks in PBE_PKCS5v20 and get_pbe introduced in 1.7.21 +* Optimize AES encryption and decryption (about 10% faster) +* Enable SSE2 optimized SHA-1 implementation on Intel Prescott CPUs +* Fix nanoseconds overflow in benchmark code +* Remove Engine::add_engine + +Version 1.7.21, 2008-11-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Make algorithm lookup much more configuable +* Add facilities for runtime performance testing of algorithms +* Drop use of entropy estimation in the PRNGs +* Increase intervals between HMAC_RNG automatic reseeding +* Drop InitializerOptions class, all options but thread safety + +Version 1.7.20, 2008-11-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Namespace pkg-config file by major and minor versions +* Cache device descriptors in Device_EntropySource +* Split base.h into {block_cipher,stream_cipher,mac,hash}.h +* Removed get_mgf function from lookup.h + +Version 1.7.19, 2008-11-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add HMAC_RNG, based on a design by Hugo Krawczyk +* Optimized the Turing stream cipher (about 20% faster on x86-64) +* Modify Randpool's reseeding algorithm to poll more sources +* Add a new AutoSeeded_RNG in auto_rng.h +* OpenPGP_S2K changed to take hash object instead of name +* Add automatic identification for Intel's Prescott processors + +Version 1.7.18, 2008-10-22 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add Doxygen comments from InSiTo +* Add ECDSA and ECKAEG benchmarks +* Add configure.pl switch --with-tr1-implementation +* Fix configure.pl's --with-endian and --with-unaligned-mem options +* Added support for pkg-config +* Optimize byteswap with x86 inline asm for Visual C++ by Yves Jerschow +* Use const references to avoid copying overhead in CurveGFp, GFpModulus + +Version 1.7.17, 2008-10-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add missing ECDSA object identifiers +* Fix error in x86 and x86-64 assembler affecting GF(p) math +* Remove Boost dependency from GF(p) math +* Modify botan-config to not print -L/usr/lib or -L/usr/local/lib +* Add BOTAN_DLL macro to over 30 classes missing it +* Rename the two SHA-2 base classes for consistency + +Version 1.7.16, 2008-10-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add several missing pieces needed for ECDSA and ECKAEG +* Add Card Verifiable Certificates from InSiTo +* Add SHA-224 from InSiTo +* Add BSI variant of EMSA1 from InSiTo +* Add GF(p) and ECDSA tests from InSiTo +* Split ECDSA and ECKAEG into distinct modules +* Allow OpenSSL and GNU MP engines to be built with public key algos disabled +* Rename sha256.h to sha2_32.h and sha_64.h to sha2_64.h + +Version 1.7.15, 2008-10-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add GF(p) arithmetic from InSiTo +* Add ECDSA and ECKAEG implementations from InSiTo +* Minimize internal dependencies, allowing for smaller build configurations +* Add new User Manual and Architecture Guide from FlexSecure GmbH +* Alter configure.pl options for better autotools compatibility +* Update build instructions for recent changes to configure.pl +* Fix CPU detection using /proc/cpuinfo + +Version 1.7.14, 2008-09-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Split library into parts allowing modular builds +* Add (very preliminary) CMS support to the main library +* Some constructors now require object pointers instead of names +* Support multiple implementations of the same algorithm +* Build support for Pentium-M processors, from Derek Scherger +* Build support for MinGW/MSYS, from Zbigniew Zagorski +* Use inline assembly for bswap on 32-bit x86 + +Version 1.7.13, 2008-09-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add SSLv3 MAC, SSLv3 PRF, and TLS v1.0 PRF from Ajisai +* Allow all examples to compile even if compression not enabled +* Make CMAC's polynomial doubling operation a public class method +* Use the -m64 flag when compiling with Sun Forte on x86-64 +* Clean up and slightly optimize CMAC::final_result + +Version 1.7.12, 2008-09-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add x86 assembly for Visual Studio C++, by Luca Piccarreta +* Add a Perl XS module, by Vaclav Ovsik +* Add SWIG-based wrapper for Botan +* Add SSE2 implementation of SHA-1, by Dean Gaudet +* Remove the BigInt::sig_words cache due to bugs +* Combined the 4 Blowfish sboxes, suggested by Yves Jerschow +* Changed BigInt::grow_by and BigInt::grow_to to be non-const +* Add private assignment operators to classes that don't support assignment +* Benchmark RSA encryption and signatures +* Added test programs for random_prime and ressol +* Add high resolution timers for IA-64, HP-PA, S390x +* Reduce use of the RNG during benchmarks +* Fix builds on STI Cell PPU +* Add support for IBM's XLC compiler +* Add IETF 8192 bit MODP group + +Version 1.7.11, 2008-09-11 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the Salsa20 stream cipher +* Optimized Montgomery reduction, Karatsuba squaring +* Added 16x16->32 word Comba multiplication and squaring +* Use a much larger Karatsuba cutoff point +* Remove bigint_mul_add_words +* Inlined several BigInt functions +* Add useful information to the generated build.h +* Rename alg_{ia32,amd64} modules to asm_{ia32,amd64} +* Fix the Windows build + +Version 1.7.10, 2008-09-05 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Public key benchmarks run using a selection of random keys +* New benchmark timer options are clock_gettime, gettimeofday, times, clock +* Including reinterpret_cast optimization for xor_buf in default header +* Split byte swapping and word rotation functions into distinct headers +* Add IETF modp 6144 group and 2048 and 3072 bit DSS groups +* Optimizes BigInt right shift +* Add aliases in DL_Group::Format enum +* BigInt now caches the significant word count + +Version 1.7.9, 2008-08-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Make clear() in most algorithm base classes a pure virtual +* Add noexec stack marker for GNU linker in assembly code +* Avoid string operations in ressol +* Compilation fixes for MinGW and Visual Studio C++ 2008 +* Some autoconfiguration fixes for Windows + +Version 1.7.8, 2008-07-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the block cipher Noekeon +* Remove global deref_alias function +* X509_Store takes timeout options as constructor arguments +* Add Shanks-Tonelli algorithm, contributed by FlexSecure GmbH +* Extend random_prime() for generating primes of any bit length +* Remove Config class +* Allow adding new entropy via base RNG interface +* Reseeding a X9.31 PRNG also reseeds the underlying PRNG + +Version 1.7.7, 2008-06-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Remove the global PRNG object +* The PK filter objects were removed +* Add a test suite for the ANSI X9.31 PRNG +* Much cleaner and (mostly) thread-safe reimplementation of es_ftw +* Remove both default arguments to ANSI_X931_RNG's constructor +* Remove the randomizing version of OctetString::change +* Make the cipher and MAC to use in Randpool configurable +* Move RandomNumberGenerator declaration to rng.h +* RSA_PrivateKey will not generate keys smaller than 1024 bits +* Fix an error decoding BER UNIVERSAL types with special taggings + +Version 1.7.6, 2008-05-05 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Initial support for Windows DLLs, from Joel Low +* Reset the position pointer when a new block is generated in X9.32 PRNG +* Timer objects are now treated as entropy sources +* Moved several ASN.1-related enums from enums.h to an appropriate header +* Removed the AEP module, due to inability to test +* Removed Global_RNG and rng.h +* Removed system_clock +* Removed Library_State::UI and the pulse callback logic + +Version 1.7.5, 2008-04-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The API of X509_CA::sign_request was altered to avoid race conditions +* New type Pipe::message_id to represent the Pipe message number +* Remove the Named_Mutex_Holder for a small performance gain +* Removed several unused or rarely used functions from Config +* Ignore spaces inside of a decimal string in BigInt::decode +* Allow using a std::istream to initialize a DataSource_Stream object +* Fix compilation problem in zlib compression module +* The chunk sized used by Pooling_Allocator is now a compile time setting +* The size of random blinding factors is now a compile time setting +* The install target no longer tries to set a particular owner/group + +Version 1.7.4, 2008-03-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Use unaligned memory read/writes on systems that allow it, for performance +* Assembly for x86-64 for accessing the bswap instruction +* Use larger buffers in ARC4 and WiderWAKE for significant throughput increase +* Unroll loops in SHA-160 for a few percent increase in performance +* Fix compilation with GCC 3.2 in es_ftw and es_unix +* Build fix for NetBSD systems +* Prevent es_dev from being built except on Unix systems + +Version 1.7.3, 2008-01-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* New invocation syntax for configure.pl with several new options +* Support for IPv4 addresses in a subject alternative name +* New fast poll for the generic Unix entropy source (es_unix) +* The es_file entropy source has been replaced by the es_dev module +* The malloc allocator does not inherit from Pooling_Allocator anymore +* The path that es_unix will search in are now fully user-configurable +* Truncate X9.42 PRF output rather than allow counter overflow +* PowerPC is now assumed to be big-endian + +Version 1.7.2, 2007-10-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Initialize the global library state lazily +* Add plain CBC-MAC for backwards compatibility with old systems +* Clean up some of the self test code +* Throw a sensible exception if a DL_Group is not found +* Truncate KDF2 output rather than allowing counter overflow +* Add newly assigned OIDs for SHA-2 and DSA with SHA-224/256 +* Fix a Visual Studio compilation problem in x509stat.cpp + +Version 1.7.1, 2007-07-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a race condition in the algorithm object cache +* HMAC key schedule optimization +* The build header sets a macro defining endianness, if known +* New word load/store abstraction allowing further optimization +* Modify most of the library to avoid use the C-style casts +* Use higher resolution timers in symmetric benchmarks + +Version 1.7.0, 2007-05-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* DSA parameter generation now follows FIPS 186-3 +* Added OIDs for Rabin-Williams and Nyberg-Rueppel +* Somewhat better support for out of tree builds +* Minor optimizations for RC2 and Tiger +* Documentation updates +* Update the todo list + +Series 1.6 +---------------------------------------- + +Version 1.6.5, 2008-08-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add noexec stack marker for GNU linker in assembly code +* Fix autoconfiguration problem on x86 with GCC 4.2 and 4.3 + +Version 1.6.4, 2008-03-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a compilation problem with Visual Studio C++ 2003 + +Version 1.6.3, 2007-07-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix a race condition in the algorithm lookup cache +* Fix problems building the memory pool on some versions of Visual C++ + +Version 1.6.2, 2007-03-24 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix autodection on Athlon64s running Linux +* Fix builds on QNX and compilers using STLport +* Remove a call to abort() that crept into production + +Version 1.6.1, 2007-01-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix some base64 decoder bugs +* Add a new option to base64 encoding, to always append a newline +* Fix some build problems under Visual Studio with debug enabled +* Fix a bug in BER_Decoder that was triggered under some compilers + +Version 1.6.0, 2006-12-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Minor cleanups versus 1.5.13 + +Series 1.5 +---------------------------------------- + +Version 1.5.13, 2006-12-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Compilation fixes for the bzip2, zlib, and GNU MP modules +* Better support for Intel C++ and EKOpath C++ on x86-64 + +Version 1.5.12, 2006-10-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Cleanups in the initialization routines +* Add some x86-64 assembly for multiply-add +* Fix problems generating very small (below 384 bit) RSA keys +* Support out of tree builds +* Bring some of the documentation up to date +* More improvements to the Python bindings + +Version 1.5.11, 2006-09-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Removed the Algorithm base class +* Various cleanups in the public key inheritance hierarchy +* Major overhaul of the configure/build setup +* Added x86 assembler implementations of Serpent and low-level MPI code +* Optimizations for the SHA-1 x86 assembler +* Various improvements to the Python wrappers +* Work around a Visual Studio compiler bug + +Version 1.5.10, 2006-08-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add x86 assembler versions of MD4, MD5, and SHA-1 +* Expand InitializerOptions' language to support on/off switches +* Fix definition of OID 2.5.4.8; was accidentally changed in 1.5.9 +* Fix possible resource leaks in the mmap allocator +* Slightly optimized buffering in MDx_HashFunction +* Initialization failures are dealt with somewhat better +* Add an example implementing Pollard's Rho algorithm +* Better option handling in the test/benchmark tool +* Expand the xor_ciph example to support longer keys +* Some updates to the documentation + +Version 1.5.9, 2006-07-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed bitrot in the AEP engine +* Fix support for marking certificate/CRL extensions as critical +* Significant cleanups in the library state / initialization code +* LibraryInitializer takes an explicit InitializerOptions object +* Make Mutex_Factory an abstract class, add Default_Mutex_Factory +* Change configuration access to using global_state() +* Add support for global named mutexes throughout the library +* Add some STL wrappers for the delete operator +* Change how certificates are created to be more flexible and general + +Version 1.5.8, 2006-06-23 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Many internal cleanups to the X.509 cert/CRL code +* Allow for application code to support new X.509 extensions +* Change the return type of X509_Certificate::{subject,issuer}_info +* Allow for alternate character set handling mechanisms +* Fix a bug that was slowing squaring performance somewhat +* Fix a very hard to hit overflow bug in the C version of word3_muladd +* Minor cleanups to the assembler modules +* Disable es_unix module on FreeBSD due to build problem on FreeBSD 6.1 +* Support for GCC 2.95.x has been dropped in this release + +Version 1.5.7, 2006-05-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Further, major changes to the BER/DER coding system +* Updated the Qt mutex module to use Mutex_Factory +* Moved the library global state object into an anonymous namespace +* Drop the Visual C++ x86 assembly module due to bugs + +Version 1.5.6, 2006-03-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The low-level DER/BER coding system was redesigned and rewritten +* Portions of the certificate code were cleaned up internally +* Use macros to substantially clean up the GCC assembly code +* Added 32-bit x86 assembly for Visual C++ (by Luca Piccarreta) +* Avoid a couple of spurious warnings under Visual C++ +* Some slight cleanups in X509_PublicKey::key_id + +Version 1.5.5, 2006-02-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a potential infinite loop in the memory pool code (Matt Johnston) +* Made Pooling_Allocator::Memory_Block an actual class of sorts +* Some small optimizations to the division and modulo computations +* Cleaned up the implementation of some of the BigInt operators +* Reduced use of dynamic memory allocation in low-level BigInt functions +* A few simplifications in the Randpool mixing function +* Removed power(), as it was not particularly useful (or fast) +* Fixed some annoying bugs in the benchmark code +* Added a real credits file + +Version 1.5.4, 2006-01-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Integrated x86 and amd64 assembly code, contributed by Luca Piccarreta +* Fixed a memory access off-by-one in the Karatsuba code +* Changed Pooling_Allocator's free list search to a log(N) algorithm +* Merged ModularReducer with its only subclass, Barrett_Reducer +* Fixed sign-handling bugs in some of the division and modulo code +* Renamed the module description files to modinfo.txt +* Further cleanups in the initialization code +* Removed BigInt::add and BigInt::sub +* Merged all the division-related functions into just divide() +* Modified the <mp_asmi.h> functions to allow for better optimizations +* Made the number of bits polled from an EntropySource user configurable +* Avoid including <algorithm> in <botan/secmem.h> +* Fixed some build problems with Sun Forte +* Removed some dead code from bigint_modop +* Fix the definition of same_mem + +Version 1.5.3, 2006-01-24 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Many optimizations in the low-level multiple precision integer code +* Added hooks for assembly implementations of the MPI code +* Support for the X.509 issuer alternative name extension in new certs +* Fixed a bug in the decompression modules; found and patched by Matt Johnston +* New Windows mutex module (mux_win32), by Luca Piccarreta +* Changed the Windows timer module to use QueryPerformanceCounter +* mem_pool.cpp was using std::set iterators instead of std::multiset ones +* Fixed a bug in X509_CA preventing users from disabling particular extensions +* Fixed the mp_asm64 module, which was entirely broken in 1.5.2 +* Fixed some module build problems on FreeBSD and Tru64 + +Version 1.5.2, 2006-01-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed an off-by-one memory read in MISTY1::key() +* Fixed a nasty memory leak in Output_Buffers::retire() +* Reimplemented the memory allocator from scratch +* Improved memory caching in Montgomery exponentiation +* Optimizations for multiple precision addition and subtraction +* Fixed a build problem in the hardware timer module on 64-bit PowerPC +* Changed default Karatsuba cutoff to 12 words (was 14) +* Removed MemoryRegion::bits(), which was unused and incorrect +* Changed maximum HMAC keylength to 1024 bits +* Various minor Makefile and build system changes +* Avoid using std::min in <secmem.h> to bypass Windows libc macro pollution +* Switched checks/clock.cpp back to using clock() by default +* Enabled the symmetric algorithm tests, which were accidentally off in 1.5.1 +* Removed the Default_Mutex's unused clone() member function + +Version 1.5.1, 2006-01-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Implemented Montgomery exponentiation +* Implemented generalized Karatsuba multiplication and squaring +* Implemented Comba squaring for 4, 6, and 8 word inputs +* Added new Modular_Exponentiator and Power_Mod classes +* Removed FixedBase_Exp and FixedExponent_Exp +* Fixed a performance regression in get_allocator introduced in 1.5.0 +* Engines can now offer S2K algorithms and block cipher padding methods +* Merged the remaining global 'algolist' code into Default_Engine +* The low-level MPI code is linked as C again +* Replaced BigInt's get_nibble with the more general get_substring +* Some documentation updates + +Version 1.5.0, 2006-01-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Moved all global/shared library state into a single object +* Mutex objects are created through mutex factories instead of a global +* Removed ::get_mutex(), ::initialize_mutex(), and Mutex::clone() +* Removed the RNG_Quality enum entirely +* There is now only a single global-use PRNG +* Removed the no_aliases and no_oids options for LibraryInitializer +* Removed the deprecated algorithms SEAL, ISAAC, and HAVAL +* Change es_ftw to use unbuffered I/O + +Series 1.4 +---------------------------------------- + +Version 1.4.12, 2006-01-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed an off-by-one memory read in MISTY1::key() +* Fixed a nasty memory leak in Output_Buffers::retire() +* Changed maximum HMAC keylength to 1024 bits +* Fixed a build problem in the hardware timer module on 64-bit PowerPC + +Version 1.4.11, 2005-12-31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Changed Whirlpool diffusion matrix to match updated algorithm spec +* Fixed several engine module build errors introduced in 1.4.10 +* Fixed two build problems in es_capi; reported by Matthew Gregan +* Added a constructor to DataSource_Memory taking a std::string +* Placing the same Filter in multiple Pipes triggers an exception +* The configure script accepts --docdir and --libdir +* Merged doc/rngs.txt into the main API document +* Thanks to Joel Low for several bug reports on early tarballs of 1.4.11 + +Version 1.4.10, 2005-12-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added an implementation of KASUMI, the block cipher used in 3G phones +* Refactored Pipe; output queues are now managed by a distinct class +* Made certain Filter facilities only available to subclasses of Fanout_Filter +* There is no longer any overhead in Pipe for a message that has been read out +* It is now possible to generate RSA keys as small as 128 bits +* Changed some of the core classes to derive from Algorithm as a virtual base +* Changed Randpool to use HMAC instead of a plain hash as the mixing function +* Fixed a bug in the allocators; found and fixed by Matthew Gregan +* Enabled the use of binary file I/O, when requested by the application +* The OpenSSL engine's block cipher code was missing some deallocation calls +* Disabled the es_ftw module on NetBSD, due to header problems there +* Fixed a problem preventing tm_hard from building on MacOS X on PowerPC +* Some cleanups for the modules that use inline assembler +* config.h is now stored in build/ instead of build/include/botan/ +* The header util.h was split into bit_ops.h, parsing.h, and util.h +* Cleaned up some redundant include directives + +Version 1.4.9, 2005-11-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the IBM-created AES candidate algorithm MARS +* Added the South Korean block cipher SEED +* Added the stream cipher Turing +* Added the new hash function FORK-256 +* Deprecated the ISAAC stream cipher +* Twofish and RC6 are significantly faster with GCC +* Much better support for 64-bit PowerPC +* Added support for high-resolution PowerPC timers +* Fixed a bug in the configure script causing problems on FreeBSD +* Changed ANSI X9.31 to support arbitrary block ciphers +* Make the configure script a bit less noisy +* Added more test vectors for some algorithms, including all the AES finalists +* Various cosmetic source code cleanups + +Version 1.4.8, 2005-10-16 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Resolved a bad performance problem in the allocators; fix by Matt Johnston +* Worked around a Visual Studio 2003 compilation problem introduced in 1.4.7 +* Renamed OMAC to CMAC to match the official NIST naming +* Added single byte versions of update() to PK_Signer and PK_Verifier +* Removed the unused reverse_bits and reverse_bytes functions + +Version 1.4.7, 2005-09-25 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed major performance problems with recent versions of GNU C++ +* Added an implementation of the X9.31 PRNG +* Removed the X9.17 and FIPS 186-2 PRNG algorithms +* Changed defaults to use X9.31 PRNGs as global PRNG objects +* Documentation updates to reflect the PRNG changes +* Some cleanups related to the engine code +* Removed two useless headers, base_eng.h and secalloc.h +* Removed PK_Verifier::valid_signature +* Fixed configure/build system bugs affecting MacOS X builds +* Added support for the EKOPath x86-64 compiler +* Added missing destructor for BlockCipherModePaddingMethod +* Fix some build problems with Visual C++ 2005 beta +* Fix some build problems with Visual C++ 2003 Workshop + +Version 1.4.6, 2005-03-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix an error in the shutdown code introduced in 1.4.5 +* Setting base/pkcs8_tries to 0 disables the builtin fail-out +* Support for XMPP identifiers in X.509 certificates +* Duplicate entries in X.509 DNs are removed +* More fixes for Borland C++, from Friedemann Kleint +* Add a workaround for buggy iostreams + +Version 1.4.5, 2005-02-26 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add support for AES encryption of private keys +* Minor fixes for PBES2 parameter decoding +* Internal cleanups for global state variables +* GCC 3.x version detection was broken in non-English locales +* Work around a Sun Forte bug affecting mem_pool.h +* Several fixes for Borland C++ 5.5, from Friedemann Kleint +* Removed inclusion of init.h into base.h +* Fixed a major bug in reading from certificate stores +* Cleaned up a couple of mutex leaks +* Removed some left-over debugging code +* Removed SSL3_MAC, SSL3_PRF, and TLS_PRF + +Version 1.4.4, 2004-12-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Further tweaks to the pooling allocator +* Modified EMSA3 to support SSL/TLS signatures +* Changes to support Qt/QCA, from Justin Karneges +* Moved mux_qt module code into mod_qt +* Fixes for HP-UX from Mike Desjardins + +Version 1.4.3, 2004-11-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Split up SecureAllocator into Allocator and Pooling_Allocator +* Memory locking allocators are more likely to be used +* Fixed the placement of includes in some modules +* Fixed broken installation procedure +* Fixes in configure script to support alternate install programs +* Modules can specify the minimum version they support + +Version 1.4.2, 2004-10-31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a major CRL handling bug +* Cipher and hash operations can be offloaded to engines +* Added support for cipher and hash offload in OpenSSL engine +* Improvements for 64-bit CPUs without a widening multiply instruction +* Support for SHA2-* and Whirlpool with EMSA2 +* Fixed a long-standing build problem with conflicting include files +* Fixed some examples that hadn't been updated for 1.4.x +* Portability fixes for Solaris, BSD, HP-UX, and others +* Lots of fixes and cleanups in the configure script +* Updated the Gentoo ebuild file + +Version 1.4.1, 2004-10-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed major errors in the X.509 and PKCS #8 copy_key functions +* Added a LAST_MESSAGE meta-message number for Pipe +* Added new aliases (3DES and DES-EDE) for Triple-DES +* Added some new functions to PK_Verifier +* Cleaned up the KDF interface +* Disabled tm_posix on BSD due to header issues +* Fixed a build problem on PowerPC with GNU C++ pre-3.4 + +Version 1.4.0, 2004-06-26 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the FIPS 186 RNG back +* Added copy_key functions for X.509 public keys and PKCS #8 private keys +* Fixed PKCS #1 signatures with RIPEMD-128 +* Moved some code around to avoid warnings with Sun ONE compiler +* Fixed a bug in botan-config affecting OpenBSD +* Fixed some build problems on Tru64, HP-UX +* Fixed compile problems with Intel C++, Compaq C++ + +Series 1.3 +---------------------------------------- + +Version 1.3.14, 2004-06-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added support for AEP's AEP1000/AEP2000 crypto cards +* Added a Mutex module using Qt, from Justin Karneges +* Added support for engine loading in LibraryInitializer +* Tweaked SecureAllocator, giving 20% better performance under heavy load +* Added timer and memory locking modules for Win32 (tm_win32, ml_win32) +* Renamed PK_Engine to Engine_Core +* Improved the Karatsuba cutoff points +* Fixes for compiling with GCC 3.4 and Sun C++ 5.5 +* Fixes for Linux/s390, OpenBSD, and Solaris +* Added support for Linux/s390x +* The configure script was totally broken for 'generic' OS +* Removed Montgomery reduction due to bugs +* Removed an unused header, pkcs8alg.h +* check --validate returns an error code if any tests failed +* Removed duplicate entry in Unix command list for es_unix +* Moved the Cert_Usage enumeration into X509_Store +* Added new timing methods for PK benchmarks, clock_gettime and RDTSC +* Fixed a few minor bugs in the configure script +* Removed some deprecated functions from x509cert.h and pkcs10.h +* Removed the 'minimal' module, has to be updated for Engine support +* Changed MP_WORD_BITS macro to BOTAN_MP_WORD_BITS to clean up namespace +* Documentation updates + +Version 1.3.13, 2004-05-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major fixes for Cygwin builds +* Minor MacOS X install fixes +* The configure script is a little better at picking the right modules +* Removed ml_unix from the 'unix' module set for Cygwin compatibility +* Fixed a stupid compile problem in pkcs10.h + +Version 1.3.12, 2004-05-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added ability to remove old entries from CRLs +* Swapped the first two arguments of X509_CA::update_crl() +* Added an < operator for MemoryRegion, so it can be used as a std::map key +* Changed X.509 searching by DNS name from substring to full string compares +* Renamed a few X509_Certificate and PKCS10_Request member functions +* Fixed a problem when decoding some PKCS #10 requests +* Hex_Decoder would not check inputs, reported by Vaclav Ovsik +* Changed default CRL expire time from 30 days to 7 days +* X509_CRL's default PEM header is now "X509 CRL", for OpenSSL compatibility +* Corrected errors in the API doc, fixes from Ken Perano +* More documentation about the Pipe/Filter code + +Version 1.3.11, 2004-04-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed two show-stopping bugs in PKCS10_Request +* Added some sanity checks in Pipe/Filter +* The DNS and URI entries would get swapped in subjectAlternativeNames +* MAC_Filter is now willing to not take a key at creation time +* Setting the expiration times of certs and CRLs is more flexible +* Fixed problems building on AIX with GCC +* Fixed some problems in the tutorial pointed out by Dominik Vogt +* Documentation updates + +Version 1.3.10, 2004-03-27 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added support for OpenPGP's ASCII armor format +* Cleaned up the RNG system; seeding is much more flexible +* Added simple autoconfiguration abilities to configure.pl +* Fixed a GCC 2.95.x compile problem +* Updated the example configuration file +* Documentation updates + +Version 1.3.9, 2004-03-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added an engine using OpenSSL (requires 0.9.7 or later) +* X509_Certificate would lose email addresses stored in the DN +* Fixed a missing initialization in a BigInt constructor +* Fixed several Visual C++ compile problems +* Fixed some BeOS build problems +* Fixed the WiderWake benchmark + +Version 1.3.8, 2003-12-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Internal changes to PK algorithms to divide data and algorithms +* DSA/DH/NR/ElGamal constructors accept taking just the private key again +* ElGamal keys now support being imported/exported as ASN.1 objects +* Much more consistent and complete error checking in PK algorithms +* Support for arbitrary backends (engines) for PK operations +* Added Montgomery reductions +* Added an engine that uses GNU MP (requires 4.1 or later) +* Removed the obsolete mp_gmp module +* Moved several initialization/shutdown functions to init.h +* Major refactoring of the memory containers +* New non-locking container, MemoryVector +* Fixed 64-bit problems in BigInt::set_bit/clear_bit +* Renamed PK_Key::check_params() to check_key() +* Some incompatible changes to OctetString +* Added version checking macros in version.h +* Removed the fips140 module pending rewrite +* Added some functions and hooks to help GUIs +* Moved more shared code into MDx_HashFunction +* Added a policy hook for specifying the encoding of X.509 strings + +Version 1.3.7, 2003-12-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a big security problem in es_unix +* Fixed several stability problems in es_unix +* Expanded the list of programs es_unix will try to use +* SecureAllocator now only preallocates blocks in special cases +* Added a special case in Global_RNG::seed for forcing a full poll +* Removed the FIPS 186 RNG added in 1.3.5 pending further testing +* Configure updates for PowerPC CPUs +* Removed the (never tested) VAX support +* Added support for S/390 Linux + +Version 1.3.6, 2003-12-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added a new module 'minimal', which disables most algorithms +* SecureAllocator allocates a few blocks at startup +* A few minor MPI cleanups +* RPM spec file cleanups and fixes + +Version 1.3.5, 2003-11-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major improvements in ASN.1 string handling +* Added partial support for ASN.1 UTF8 STRINGs and BMP STRINGs +* Added partial support for the X.509v3 certificate policies extension +* Centralized the handling of character set information +* Added FIPS 140-2 startup self tests +* Added a module (fips140) for doing extra FIPS 140-2 tests +* Added FIPS 186-2 RNG +* Improved ASN.1 BIT STRING handling +* Removed a memory leak in PKCS10_Request +* The encoding of DirectoryString now follows PKIX guidelines +* Fixed some of the character set dependencies +* Fixed a DER encoding error for tags greater than 30 +* The BER decoder can now handle tags larger than 30 +* Fixed tm_hard.cpp to recognize SPARC on more systems +* Workarounds for a GCC 2.95.x bug in x509find.cpp +* RPM changed to install into /usr instead of /usr/local +* Added support for QNX + +Version 1.3.4, 2003-11-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added a module that does certain MPI operations using GNU MP +* Added the X9.42 Diffie-Hellman PRF +* The Zlib and Bzip2 objects now use custom allocators +* Added member functions for directly hashing/MACing SecureVectors +* Minor optimizations to the MPI addition and subtraction algorithms +* Some cleanups in the low-level MPI code +* Created separate AES-{128,192,256} objects + +Version 1.3.3, 2003-11-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* The library can now be repeatedly initialized and shutdown without crashing +* Fixed an off-by-one error in the CTS code +* Fixed an error in the EMSA4 verification code +* Fixed a memory leak in mutex.cpp (pointed out by James Widener) +* Fixed a memory leak in Pthread_Mutex +* Fixed several memory leaks in the testing code +* Bulletproofed the EMSA/EME/KDF/MGF retrieval functions +* Minor cleanups in SecureAllocator +* Removed a needless mutex guarding the (stateless) global timer +* Fixed a piece of bash-specific code in botan-config +* X.509 objects report more information about decoding errors +* Cleaned up some of the exception handling +* Updated the example config file with new OIDSs +* Moved the build instructions into a separate document, building.tex + +Version 1.3.2, 2003-11-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a bug preventing DSA signatures from verifying on X.509 objects +* Made the X509_Store search routines more efficient and flexible +* Added a function to X509_PublicKey to do easy public/private key matching +* Added support for decoding indefinite length BER data +* Changed Pipe's peek() to take an offset +* Removed Filter::set_owns in favor of the new incr_owns function +* Removed BigInt::zero() and BigInt::one() +* Renamed the PEM related options from base/pem_* to pem/* +* Added an option to specify the line width when encoding PEM +* Removed the "rng/safe_longterm" option; it's always on now +* Changed the cipher used for RNG super-encryption from ARC4 to WiderWake4+1 +* Cleaned up the base64/hex encoders and decoders +* Added an ASN.1/BER decoder as an example +* AES had its internals marked 'public' in previous versions +* Changed the value of the ASN.1 NO_OBJECT enum +* Various new hacks in the configure script +* Removed the already nominal support for SunOS + +Version 1.3.1, 2003-11-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Generalized a few pieces of the DER encoder +* PKCS8::load_key would fail if handed an unencrypted key +* Added a failsafe so PKCS #8 key decoding can't go into an infinite loop + +Version 1.3.0, 2003-11-02 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major redesign of the PKCS #8 private key import/export system +* Added a small amount of UI interface code for getting passphrases +* Added heuristics that tell if a key, cert, etc is stored as PEM or BER +* Removed CS-Cipher, SHARK, ThreeWay, MD5-MAC, and EMAC +* Removed certain deprecated constructors of RSA, DSA, DH, RW, NR +* Made PEM decoding more forgiving of extra text before the header + +Series 1.2 +---------------------------------------- + +Version 1.2.8, 2003-11-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Merged several important bug fixes from 1.3.x + +Version 1.2.7, 2003-10-31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added support for reading configuration files +* Added constructors so NR and RW keys can be imported easily +* Fixed mp_asm64, which was completely broken in 1.2.6 +* Removed tm_hw_ia32 module; replaced by tm_hard +* Added support for loading certain oddly formed RSA certificates +* Fixed spelling of NON_REPUDIATION enum +* Renamed the option default_to_ca to v1_assume_ca +* Fixed a minor bug in X.509 certificate generation +* Fixed a latent bug in the OID lookup code +* Updated the RPM spec file +* Added to the tutorial + +Version 1.2.6, 2003-07-04 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major performance increase for PK algorithms on most 64-bit systems +* Cleanups in the low-level MPI code to support asm implementations +* Fixed build problems with some versions of Compaq's C++ compiler +* Removed useless constructors for NR public and private keys +* Removed support for the patch_file directive in module files +* Removed several deprecated functions + +Version 1.2.5, 2003-06-22 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a tricky and long-standing memory leak in Pipe +* Major cleanups and fixes in the memory allocation system +* Removed alloc_mlock, which has been superseded by the ml_unix module +* Removed a denial of service vulnerability in X509_Store +* Fixed compilation problems with VS .NET 2003 and Codewarrior 8 +* Added another variant of PKCS8::load_key, taking a memory buffer +* Fixed various minor/obscure bugs which occurred when MP_WORD_BITS != 32 +* BigInt::operator%=(word) was a no-op if the input was a power of 2 +* Fixed portability problems in BigInt::to_u32bit +* Fixed major bugs in SSL3-MAC +* Cleaned up some messes in the PK algorithms +* Cleanups and extensions for OMAC and EAX +* Made changes to the entropy estimation function +* Added a 'beos' module set for use on BeOS +* Officially deprecated a few X509:: and PKCS8:: functions +* Moved the contents of primes.h to numthry.h +* Moved the contents of x509opt.h to x509self.h +* Removed the (empty) desx.h header +* Documentation updates + +Version 1.2.4, 2003-05-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a bug in EMSA1 affecting NR signature verification +* Fixed a few latent bugs in BigInt related to word size +* Removed an unused function, mp_add2_nc, from the MPI implementation +* Reorganized the core MPI files + +Version 1.2.3, 2003-05-20 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a bug that prevented DSA/NR key generation +* Fixed a bug that prevented importing some root CA certs +* Fixed a bug in the BER decoder when handing optional bit or byte strings +* Fixed the encoding of authorityKeyIdentifier in X509_CA +* Added a sanity check in PBKDF2 for zero length passphrases +* Added versions of X509::load_key and PKCS8::load_key that take a file name +* X509_CA generates 128 bit serial numbers now +* Added tests to check PK key generation +* Added a simplistic X.509 CA example +* Cleaned up some of the examples + +Version 1.2.2, 2003-05-13 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Add checks to prevent any BigInt bugs from revealing an RSA or RW key +* Changed the interface of Global_RNG::seed +* Major improvements for the es_unix module +* Added another Win32 entropy source, es_win32 +* The Win32 CryptoAPI entropy source can now poll multiple providers +* Improved the BeOS entropy source +* Renamed pipe_unixfd module to fd_unix +* Fixed a file descriptor leak in the EGD module +* Fixed a few locking bugs + +Version 1.2.1, 2003-05-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added ANSI X9.23 compatible CBC padding +* Added an entropy source using Win32 CryptoAPI +* Removed the Pipe I/O operators taking a FILE* +* Moved the BigInt encoding/decoding functions into the BigInt class +* Integrated several fixes for VC++ 7 (from Hany Greiss) +* Fixed the configure.pl script for Windows builds + +Version 1.2.0, 2003-04-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Tweaked the Karatsuba cut-off points +* Increased the allowed keylength of HMAC and Blowfish +* Removed the 'mpi_ia32' module, pending rewrite +* Workaround a GCC 2.95.x bug in eme1.cpp + +Series 1.1 +---------------------------------------- + +Version 1.1.13, 2003-04-22 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added OMAC +* Added EAX authenticated cipher mode +* Diffie-Hellman would not do blinding in some cases +* Optimized the OFB and CTR modes +* Corrected Skipjack's word ordering, as per NIST clarification +* Support for all subject/issuer attribute types required by RFC 3280 +* The removeFromCRL CRL reason code is now handled correctly +* Increased the flexibility of the allocators +* Renamed Rijndael to AES, created aes.h, deleted rijndael.h +* Removed support for the 'no_timer' LibraryInitializer option +* Removed 'es_pthr' module, pending further testing +* Cleaned up get_ciph.cpp + +Version 1.1.12, 2003-04-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a ASN.1 string encoding bug +* Fixed a pair of X509_DN encoding problems +* Base64_Decoder and Hex_Decoder can now validate input +* Removed support for the LibraryInitializer option 'egd_path' +* Added tests for DSA X.509 and PKCS #8 key formats +* Removed a long deprecated feature of DH_PrivateKey's constructor +* Updated the RPM .spec file +* Major documentation updates + +Version 1.1.11, 2003-04-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added PKCS #10 certificate requests +* Changed X509_Store searching interface to be more flexible +* Added a generic Certificate_Store interface +* Added a function for generating self-signed X.509 certs +* Cleanups and changes to X509_CA +* New examples for PKCS #10 and self-signed certificates +* Some documentation updates + +Version 1.1.10, 2003-04-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* X509_CA can now generate new X.509 CRLs +* Added blinding for RSA, RW, DH, and ElGamal to prevent timing attacks +* More certificate and CRL extensions/attributes are supported +* Better DN handling in X.509 certificates/CRLs +* Added a DataSink hierarchy (suggested by Jim Darby) +* Consolidated SecureAllocator and ManagedAllocator +* Many cleanups and generalizations +* Added a (slow) pthreads based EntropySource +* Fixed some threading bugs + +Version 1.1.9, 2003-02-25 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added support for using X.509v2 CRLs +* Fixed several bugs in the path validation algorithm +* Certificates can be verified for a particular usage +* Algorithm for comparing distinguished names now follows X.509 +* Cleaned up the code for the es_beos, es_ftw, es_unix modules +* Documentation updates + +Version 1.1.8, 2003-01-29 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixes for the certificate path validation algorithm in X509_Store +* Fixed a bug affecting X509_Certificate::is_ca_cert() +* Added a general configuration interface for policy issues +* Cleanups and API changes in the X.509 CA, cert, and store code +* Made various options available for X509_CA users +* Changed X509_Time's interface to work around time_t problems +* Fixed a theoretical weakness in Randpool's entropy mixing function +* Fixed problems compiling with GCC 2.95.3 and GCC 2.96 +* Fixed a configure bug (reported by Jon Wilson) affecting MinGW + +Version 1.1.7, 2003-01-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed an obscure but dangerous bug in SecureVector::swap +* Consolidated SHA-384 and SHA-512 to save code space +* Added SSL3-MAC and SSL3-PRF +* Documentation updates, including a new tutorial + +Version 1.1.6, 2002-12-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Initial support for X.509v3 certificates and CAs +* Major redesign/rewrite of the ASN.1 encoding/decoding code +* Added handling for DSA/NR signatures encoded as DER SEQUENCEs +* Documented the generic cipher lookup interface +* Added an (untested) entropy source for BeOS +* Various cleanups and bug fixes + +Version 1.1.5, 2002-11-17 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the discrete logarithm integrated encryption system (DLIES) +* Various optimizations for BigInt +* Added support for assembler optimizations in modules +* Added BigInt x86 optimizations module (mpi_ia32) + +Version 1.1.4, 2002-11-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Speedup of 15-30% for PK algorithms +* Implemented the PBES2 encryption scheme +* Fixed a potential bug in decoding RSA and RW private keys +* Changed the DL_Group class interface to handle different formats better +* Added support for PKCS #3 encoded DH parameters +* X9.42 DH parameters use a PEM label of 'X942 DH PARAMETERS' +* Added key pair consistency checking +* Fixed a compatibility problem with gcc 2.96 (pointed out by Hany Greiss) +* A botan-config script is generated at configure time +* Documentation updates + +Version 1.1.3, 2002-11-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added a generic public/private key loading interface +* Fixed a small encoding bug in RSA, RW, and DH +* Changed the PK encryption/decryption interface classes +* ECB supports using padding methods +* Added a function-based interface for library initialization +* Added support for RIPEMD-128 and Tiger PKCS#1 v1.5 signatures +* The cipher mode benchmarks now use 128-bit AES instead of DES +* Removed some obsolete typedefs +* Removed OpenCL support (opencl.h, the OPENCL_* macros, etc) +* Added tests for PKCS #8 encoding/decoding +* Added more tests for ECB and CBC + +Version 1.1.2, 2002-10-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Support for PKCS #8 encoded RSA, DSA, and DH private keys +* Support for Diffie-Hellman X.509 public keys +* Major reorganization of how X.509 keys are handled +* Added PKCS #5 v2.0's PBES1 encryption scheme +* Added a generic cipher lookup interface +* Added the WiderWake4+1 stream cipher +* Added support for sync-able stream ciphers +* Added a 'paranoia level' option for the LibraryInitializer +* More security for RNG output meant for long term keys +* Added documentation for some of the new 1.1.x features +* CFB's feedback argument is now specified in bits +* Renamed CTR class to CTR_BE +* Updated the RSA and DSA examples to use X.509 and PKCS #8 key formats + +Version 1.1.1, 2002-10-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added the Korean hash function HAS-160 +* Partial support for RSA and DSA X.509 public keys +* Added a mostly functional BER encoder/decoder +* Added support for non-deterministic MAC functions +* Initial support for PEM encoding/decoding +* Internal cleanups in the PK algorithms +* Several new convenience functions in Pipe +* Fixed two nasty bugs in Pipe +* Messed with the entropy sources for es_unix +* Discrete logarithm groups are checked for safety more closely now +* For compatibility with GnuPG, ElGamal now supports DSA-style groups + +Version 1.1.0, 2002-09-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added entropy estimation to the RNGs +* Improved the overall design of both Randpool and ANSI_X917_RNG +* Added a separate RNG for nonce generation +* Added window exponentiation support in power_mod +* Added a get_s2k function and the PKCS #5 S2K algorithms +* Added the TLSv1 PRF +* Replaced BlockCipherModeIV typedef with InitializationVector class +* Renamed PK_Key_Agreement_Scheme to PK_Key_Agreement +* Renamed SHA1 -> SHA_160 and SHA2_x -> SHA_x +* Added support for RIPEMD-160 PKCS#1 v1.5 signatures +* Changed the key agreement scheme interface +* Changed the S2K and KDF interfaces +* Better SCAN compatibility for HAVAL, Tiger, MISTY1, SEAL, RC5, SAFER-SK +* Added support for variable-pass Tiger +* Major speedup for Rabin-Williams key generation + +Series 1.0 +---------------------------------------- + +Version 1.0.2, 2003-01-12 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed an obscure SEGFAULT causing bug in Pipe +* Fixed an obscure but dangerous bug in SecureVector::swap + +Version 1.0.1, 2002-09-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed a minor bug in Randpool::random() +* Added some new aliases and typedefs for 1.1.x compatibility +* The 4096-bit RSA benchmark key was decimal instead of hex +* EMAC was returning an incorrect name + +Version 1.0.0, 2002-08-26 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Octal I/O of BigInt is now supported +* Fixed portability problems in the es_egd module +* Generalized IV handling in the block cipher modes +* Added Karatsuba multiplication and k-ary exponentiation +* Fixed a problem in the multiplication routines + +Series 0.9 +---------------------------------------- + +Version 0.9.2, 2002-08-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* DH_PrivateKey::public_value() was returning the wrong value +* Various BigInt optimizations +* The filters.h header now includes hex.h and base64.h +* Moved Counter mode to ctr.h +* Fixed a couple minor problems with VC++ 7 +* Fixed problems with the RPM spec file + +Version 0.9.1, 2002-08-10 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Grand rename from OpenCL to Botan +* Major optimizations for the PK algorithms +* Added ElGamal encryption +* Added Whirlpool +* Tweaked memory allocation parameters +* Improved the method of seeding the global RNG +* Moved pkcs1.h to eme_pkcs.h +* Added more test vectors for some algorithms +* Fixed error reporting in the BigInt tests +* Removed Default_Timer, it was pointless +* Added some new example applications +* Removed some old examples that weren't that interesting +* Documented the compression modules + +Version 0.9.0, 2002-08-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* EMSA4 supports variable salt size +* PK_* can take a string naming the encoding method to use +* Started writing some internals documentation + +Series 0.8 +---------------------------------------- + +Version 0.8.7, 2002-07-30 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed bugs in EME1 and EMSA4 +* Fixed a potential crash at shutdown +* Cipher modes returned an ill-formed name +* Removed various deprecated types and headers +* Cleaned up the Pipe interface a bit +* Minor additions to the documentation +* First stab at a Visual C++ makefile (doc/Makefile.vc7) + +Version 0.8.6, 2002-07-25 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added EMSA4 (aka PSS) +* Brought the manual up to date; many corrections and additions +* Added a parallel hash function construction +* Lookup supports all available algorithms now +* Lazy initialization of the lookup tables +* Made more discrete logarithm groups available through get_dl_group() +* StreamCipher_Filter supports seeking (if the underlying cipher does) +* Minor optimization for GCD calculations +* Renamed SAFER_SK128 to SAFER_SK +* Removed many previously deprecated functions +* Some now-obsolete functions, headers, and types have been deprecated +* Fixed some bugs in DSA prime generation +* DL_Group had a constructor for DSA-style prime gen but it wasn't defined +* Reversed the ordering of the two arguments to SEAL's constructor +* Fixed a threading problem in the PK algorithms +* Fixed a minor memory leak in lookup.cpp +* Fixed pk_types.h (it was broken in 0.8.5) +* Made validation tests more verbose +* Updated the check and example applications + +Version 0.8.5, 2002-07-21 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major changes to constructors for DL-based cryptosystems (DSA, NR, DH) +* Added a DL_Group class +* Reworking of the pubkey internals +* Support in lookup for aliases and PK algorithms +* Renamed CAST5 to CAST_128 and CAST256 to CAST_256 +* Added EMSA1 +* Reorganization of header files +* LibraryInitializer will install new allocator types if requested +* Fixed a bug in Diffie-Hellman key generation +* Did a workaround in pipe.cpp for GCC 2.95.x on Linux +* Removed some debugging code from init.cpp that made FTW ES useless +* Better checking for invalid arguments in the PK algorithms +* Reduced Base64 and Hex default line length (if line breaking is used) +* Fixes for HP's aCC compiler +* Cleanups in BigInt + +Version 0.8.4, 2002-07-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added Nyberg-Rueppel signatures +* Added Diffie-Hellman key exchange (kex interface is subject to change) +* Added KDF2 +* Enhancements to the lookup API +* Many things formerly taking pointers to algorithms now take names +* Speedups for prime generation +* LibraryInitializer has support for seeding the global RNG +* Reduced SAFER-SK128 memory consumption +* Reversed the ordering of public and private key values in DSA constructor +* Fixed serious bugs in MemoryMapping_Allocator +* Fixed memory leak in Lion +* FTW_EntropySource was not closing the files it read +* Fixed line breaking problem in Hex_Encoder + +Version 0.8.3, 2002-06-09 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added DSA and Rabin-Williams signature schemes +* Added EMSA3 +* Added PKCS#1 v1.5 encryption padding +* Added Filters for PK algorithms +* Added a Keyed_Filter class +* LibraryInitializer processes arguments now +* Major revamp of the PK interface classes +* Changed almost all of the Filters for non-template operation +* Changed HMAC, Lion, Luby-Rackoff to non-template classes +* Some fairly minor BigInt optimizations +* Added simple benchmarking for PK algorithms +* Added hooks for fixed base and fixed exponent modular exponentiation +* Added some examples for using RSA +* Numerous bugfixes and cleanups +* Documentation updates + +Version 0.8.2, 2002-05-18 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added an (experimental) algorithm lookup interface +* Added code for directly testing BigInt +* Added SHA2-384 +* Optimized SHA2-512 +* Major optimization for Adler32 (thanks to Dan Nicolaescu) +* Various minor optimizations in BigInt and related areas +* Fixed two bugs in X9.19 MAC, both reported by Darren Starsmore +* Fixed a bug in BufferingFilter +* Made a few fixes for MacOS X +* Added a workaround in configure.pl for GCC 2.95.x +* Better support for PowerPC, ARM, and Alpha +* Some more cleanups + +Version 0.8.1, 2002-05-06 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Major code cleanup (check doc/deprecated.txt) +* Various bugs fixed, including several portability problems +* Renamed MessageAuthCode to MessageAuthenticationCode +* A replacement for X917 is in x917_rng.h +* Changed EMAC to non-template class +* Added ANSI X9.19 compatible CBC-MAC +* TripleDES now supports 128 bit keys + +Version 0.8.0, 2002-04-24 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Merged BigInt: many bugfixes and optimizations since alpha2 +* Added RSA (rsa.h) +* Added EMSA2 (emsa2.h) +* Lots of new interface code for public key algorithms (pk_base.h, pubkey.h) +* Changed some interfaces, including SymmetricKey, to support the global rng +* Fixed a serious bug in ManagedAllocator +* Renamed RIPEMD128 to RIPEMD_128 and RIPEMD160 to RIPEMD_160 +* Removed some deprecated stuff +* Added a global random number generator (rng.h) +* Added clone functions to most of the basic algorithms +* Added a library initializer class (init.h) +* Version macros in version.h +* Moved the base classes from opencl.h to base.h +* Renamed the bzip2 module to comp_bzip2 and zlib to comp_zlib +* Documentation updates for the new stuff (still incomplete) +* Many new deprecated things: check doc/deprecated.txt + +Series 0.7 +---------------------------------------- + +Version 0.7.10, 2002-04-07 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Added EGD_EntropySource module (es_egd) +* Added a file tree walking EntropySource (es_ftw) +* Added MemoryLocking_Allocator module (alloc_mlock) +* Renamed the pthr_mux, unix_rnd, and mmap_mem modules +* Changed timer mechanism; the clock method can be switched on the fly. +* Renamed MmapDisk_Allocator to MemoryMapping_Allocator +* Renamed ent_file.h to es_file.h (ent_file.h is around, but deprecated) +* Fixed several bugs in MemoryMapping_Allocator +* Added more default sources for Unix_EntropySource +* Changed SecureBuffer to use same allocation methods as SecureVector +* Added bigint_divcore into mp_core to support BigInt alpha2 release +* Removed some Pipe functions deprecated since 0.7.8 +* Some fixes for the configure program + +Version 0.7.9, 2002-03-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Memory allocation substantially revamped +* Added memory allocation method based on mmap(2) in the mmap_mem module +* Added ECB and CTS block cipher modes (ecb.h, cts.h) +* Added a Mutex interface (mutex.h) +* Added module pthr_mux, implementing the Mutex interface +* Added Threaded Filter interface (thr_filt.h) +* All algorithms can now by keyed with SymmetricKey objects +* More testing occurs with --validate (expected failures) +* Fixed two bugs reported by Hany Greiss, in Luby-Rackoff and RC6 +* Fixed a buffering bug in Bzip_Decompress and Zlib_Decompress +* Made X917 safer (and about 1/3 as fast) +* Documentation updates + +Version 0.7.8, 2002-02-28 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* More capabilities for Pipe, inspired by SysV STREAMS, including peeking, + better buffering, and stack ops. NOT BACKWARDS COMPATIBLE: SEE DOCUMENTATION +* Added a BufferingFilter class +* Added popen() based EntropySource for generic Unix systems (unix_rnd) +* Moved 'devrand' module into main distribution (ent_file.h), renamed to + File_EntropySource, and changed interface somewhat. +* Made Randpool somewhat more conservative and also 25% faster +* Minor fixes and updates for the configure script +* Added some tweaks for memory allocation +* Documentation updates for the new Pipe interface +* Fixed various minor bugs +* Added a couple of new example programs (stack and hasher2) + +Version 0.7.7, 2001-11-24 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Filter::send now works in the constructor of a Filter subclass +* You may now have to include <opencl/pipe.h> explicitly in some code +* Added preliminary PK infrastructure classes in pubkey.h and pkbase.h +* Enhancements to SecureVector (append, destroy functions) +* New infrastructure for secure memory allocation +* Added IEEE P1363 primitives MGF1, EME1, KDF1 +* Rijndael optimizations and cleanups +* Changed CipherMode<B> to BlockCipherMode(B*) +* Fixed a nasty bug in pipe_unixfd +* Added portions of the BigInt code into the main library +* Support for VAX, SH, POWER, PowerPC-64, Intel C++ + +Version 0.7.6, 2001-10-14 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fixed several serious bugs in SecureVector created in 0.7.5 +* Square optimizations +* Fixed shared objects on MacOS X and HP-UX +* Fixed static libs for KCC 4.0; works with KCC 3.4g as well +* Full support for Athlon and K6 processors using GCC +* Added a table of prime numbers < 2**16 (primes.h) +* Some minor documentation updates + +Version 0.7.5, 2001-08-19 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Split checksum.h into adler32.h, crc24.h, and crc32.h +* Split modes.h into cbc.h, cfb.h, and ofb.h +* CBC_wPadding* has been replaced by CBC_Encryption and CBC_Decryption +* Added OneAndZeros and NoPadding methods for CBC +* Added Lion, a very fast block cipher construction +* Added an S2K base class (s2k.h) and an OpenPGP_S2K class (pgp_s2k.h) +* Basic types (ciphers, hashes, etc) know their names now (call name()) +* Changed the EntropySource type somewhat +* Big speed-ups for ISAAC, Adler32, CRC24, and CRC32 +* Optimized CAST-256, DES, SAFER-SK, Serpent, SEAL, MD2, and RIPEMD-160 +* Some semantics of SecureVector have changed slightly +* The mlock module has been removed for the time being +* Added string handling functions for hashes and MACs +* Various non-user-visible cleanups +* Shared library soname is now set to the full version number + +Version 0.7.4, 2001-07-15 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* New modules: Zlib, gettimeofday and x86 RTC timers, Unix I/O for Pipe +* Fixed a vast number of errors in the config script/makefile/specfile +* Pipe now has a stdio(3) interface as well as C++ iostreams +* ARC4 supports skipping the first N bytes of the cipher stream (ala MARK4) +* Bzip2 supports decompressing multiple concatenated streams, and flushing +* Added a simple 'overall average' score to the benchmarks +* Fixed a small bug in the POSIX timer module +* Removed a very-unlikely-to-occur bug in most of the hash functions +* filtbase.h now includes <iosfwd>, not <iostream> +* Minor documentation updates + +Version 0.7.3, 2001-06-08 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Fix build problems on Solaris/SPARC +* Fix build problems with Perl versions < 5.6 +* Fixed some stupid code that broke on a few compilers +* Added string handling functions to Pipe +* MISTY1 optimizations + +Version 0.7.2, 2001-06-03 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Build system supports modules +* Added modules for mlock, a /dev/random EntropySource, POSIX1.b timers +* Added Bzip2 compression filter, contributed by Peter Jones +* GNU make no longer required (tested with 4.4BSD pmake and Solaris make) +* Fixed minor bug in several of the hash functions +* Various other minor fixes and changes +* Updates to the documentation + +Version 0.7.1, 2001-05-16 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Rewrote configure script: more consistent and complete +* Made it easier to find out parameters of types at run time (opencl.h) +* New functions for finding the version being used (version.h) +* New SymmetricKey interface for Filters (symkey.h) +* InvalidKeyLength now records what the invalid key length was +* Optimized DES, CS-Cipher, MISTY1, Skipjack, XTEA +* Changed GOST to use correct S-box ordering (incompatible change) +* Benchmark code was almost totally rewritten +* Many more entries in the test vector file +* Fixed minor and idiotic bug in check.cpp + +Version 0.7.0, 2001-03-01 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* First public release diff --git a/doc/lowlevel.txt b/doc/lowlevel.txt new file mode 100644 index 000000000..852d7eb43 --- /dev/null +++ b/doc/lowlevel.txt @@ -0,0 +1,236 @@ + +The Low-Level Interface +================================= + +Botan has two different interfaces. The one documented in this section +is meant more for implementing higher-level types (see the section on +filters, earlier in this manual) than for use by applications. Using +it safely requires a solid knowledge of encryption techniques and best +practices, so unless you know, for example, what CBC mode and nonces +are, and why PKCS #1 padding is important, you should avoid this +interface in favor of something working at a higher level. + +Basic Algorithm Abilities +--------------------------------- + +There are a small handful of functions implemented by most of Botan's +algorithm objects. Among these are: + +.. cpp:function:: std::string Algorithm::name() + +Returns a human-readable string of the name of this +algorithm. Examples of names returned are "AES-128" and +"HMAC(SHA-512)". You can turn names back into algorithm objects using +the functions in ``lookup.h``. + +.. cpp:function:: void Algorithm::clear() + +Clear out the algorithm's internal state. A block cipher object will +"forget" its key, a hash function will "forget" any data put into it, +etc. The object will look and behave as it did when you initially +allocated it. + +.. cpp:function:: T* Algorithm::clone() + +This function is central to Botan's name-based interface. The +``clone`` has many different return types, such as ``BlockCipher``\* +and ``HashFunction``\*, depending on what kind of object it is called +on. Note that unlike Java's clone, this returns a new object in a +"pristine" state; that is, operations done on the initial object +before calling ``clone`` do not affect the initial state of the new +clone. + +Cloned objects can (and should) be deallocated with the C++ ``delete`` +operator. + +Keys and IVs +--------------------------------- + +Both symmetric keys and initialization values can be considered byte +(or octet) strings. These are represented by + +.. cpp:class:: OctetString + + Also known as ``SymmetricKey`` and ``InitializationVector``, when + you want to express intent. + + .. cpp:function:: OctetString(RandomNumberGenerator& rng, size_t length) + + This constructor creates a new random key *length* bytes long + using the random number generator. + + .. cpp:function:: OctetString(std::string str) + + The argument *str* is assumed to be a hex string; it is + converted to binary and stored. Whitespace is ignored. + + .. cpp:function:: OctetString(const byte* input, size_t length) + + This constructor copies its input. + + .. cpp:function:: as_string() const + + Returns the hex representation of the key or IV + +Symmetrically Keyed Algorithms +--------------------------------- + +Block ciphers, stream ciphers, and MACs are all keyed operations; to +be useful, they have to be set to use a particular key, which is a +randomly chosen string of bits of a specified length. The length +required by any particular algorithm may vary, depending on both the +algorithm specification and the implementation. You can query any +botan object to find out what key length(s) it supports. + +To make this similarity in terms of keying explicit, all algorithms of +those types are derived from the :cpp:class`SymmetricAlgorithm` base. +This type provides functions for setting the key, and querying +restrictions on the size of the key. + +.. cpp:class:: SymmetricAlgorithm + + .. cpp:function:: void set_key(const byte* key, size_t length) + + .. cpp:function:: void set_key(const SymmetricKey& key) + + This sets the key to the value specified. Most algorithms only + accept keys of certain lengths. If you attempt to call + ``set_key`` with a key length that is not supported, the + exception ``Invalid_Key_Length`` will be thrown. + + In all cases, ``set_key`` must be called on an object before any + data processing (encryption, decryption, etc) is done by that + object. If this is not done, the results are undefined. + + .. cpp:function:: bool valid_keylength(size_t length) const + + This function returns true if and only if *length* is a valid + keylength for the algorithm. + + .. cpp:function:: size_t minimum_keylength() const + + Return the smallest key length (in bytes) that is acceptible for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptible for the + algorithm + +Block Ciphers +--------------------------------- + +All block ciphers classes in botan are subclasses of + +.. cpp:class:: BlockCipher + + Which subclasses the :cpp:class:`SymmetricAlgorithm` interface. + + .. cpp:function:: size_t block_size() const + + Returns the block size of the cipher in bytes + + .. cpp:function:: void encrypt_n(const byte* in, \ + byte* out, size_t n) const + + Encrypt *n* blocks of data, taking the input from the array *in* + and placing the ciphertext into *out*. The two pointers may be + identical, but should not overlap ranges. + + .. cpp:function:: void encrypt(const byte* in, byte* out) const + + Encrypt a single block, taking the input from *in* and placing + it in *out*. Acts like :cpp:func:`encrypt_n`\ (in, out, 1). + + .. cpp:function:: void encrypt(byte* block) const + + Identical to :cpp:func:`encrypt`\ (block, block) + + .. cpp:function:: void decrypt_n(const byte* in, byte out, size_t n) const + + Decrypt *n* blocks of data, taking the input from *in* and + placing the plaintext in *out*. The two pointers may be + identical, but should not overlap ranges. + + .. cpp:function:: void decrypt(const byte* in, byte* out) const + + Decrypt a single block, taking the input from *in* and placing it + in *out*. Acts like :cpp:func:`decrypt_n`\ (in, out, 1). + + .. cpp:function:: void decrypt(byte* block) const + + Identical to :cpp:func:`decrypt`\ (block, block) + +Stream Ciphers +--------------------------------- + +Stream ciphers are somewhat different from block ciphers, in that +encrypting data results in changing the internal state of the +cipher. Also, you may encrypt any length of data in one go (in byte +amounts). + +.. cpp:function:: void StreamCipher::encrypt(const byte* in, byte* out, size_t length) + +.. cpp:function:: void StreamCipher::encrypt(byte* data, size_t length) + +Stream ciphers implement the ``SymmetricAlgorithm`` interface. + +Hash Functions / Message Authentication Codes +---------------------------------------------- + +Hash functions take their input without producing any output, only +producing anything when all input has already taken place. MACs are +very similar, but are additionally keyed. Both of these are derived +from the base class ``BufferedComputation``, which has the following +functions. + +.. cpp:function:: size_t BufferedComputation::output_length() + +Return the size of the output of this function. + +.. cpp:function:: void BufferedComputation::update(const byte* input, size_t length) + +.. cpp:function:: void BufferedComputation::update(byte input) + +.. cpp:function:: void BufferedComputation::update(const std::string& input) + +Updates the hash/mac calculation with *input*. + +.. cpp:function:: void BufferedComputation::final(byte* out) + +.. cpp:function:: SecureVector<byte> BufferedComputation::final() + +Complete the hash/MAC calculation and place the result into ``out``. +For the argument taking an array, exactly ``output_length`` bytes will +be written. After you call ``final``, the hash function is reset to +its initial state, so it may be reused immediately. + +The second method of using final is to call it with no arguments at +all, as shown in the second prototype. It will return the hash/mac +value in a memory buffer. + +There is also a pair of functions called ``process``. They are a +combination of a single ``update``, and ``final``. Both versions +return the final value, rather than placing it an array. Calling +``process`` with a single byte value isn't available, mostly because +it would rarely be useful. + +A MAC can be viewed (in most cases) as a keyed hash function, so +classes that are derived from ``MessageAuthenticationCode`` have +``update`` and ``final`` classes just like a ``HashFunction`` (and +like a ``HashFunction``, after ``final`` is called, it can be used to +make a new MAC right away; the key is kept around). + +A MAC has the ``SymmetricAlgorithm`` interface in addition to the +``BufferedComputation`` interface. + +Checksums +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Checksums are very similar to hash functions, and in fact share the +same interface. But there are some significant differences, the major +ones being that the output size is very small (usually in the range of +2 to 4 bytes), and is not cryptographically secure. But for their +intended purpose (error checking), they perform very well. Some +examples of checksums included in Botan are the Adler32 and CRC32 +checksums. diff --git a/doc/old_tutorial.tex b/doc/old_tutorial.tex deleted file mode 100644 index f220d765a..000000000 --- a/doc/old_tutorial.tex +++ /dev/null @@ -1,880 +0,0 @@ -\documentclass{article} - -\setlength{\textwidth}{6.5in} % 1 inch side margins -\setlength{\textheight}{9in} % ~1 inch top and bottom margins - -\setlength{\headheight}{0in} -\setlength{\topmargin}{0in} -\setlength{\headsep}{0in} - -\setlength{\oddsidemargin}{0in} -\setlength{\evensidemargin}{0in} - -\title{\textbf{Botan Tutorial}} -\author{Jack Lloyd \\ - \texttt{[email protected]}} -\date{2009/07/08} - -\newcommand{\filename}[1]{\texttt{#1}} -\newcommand{\manpage}[2]{\texttt{#1}(#2)} - -\newcommand{\macro}[1]{\texttt{#1}} - -\newcommand{\function}[1]{\textbf{#1}} -\newcommand{\type}[1]{\texttt{#1}} -\renewcommand{\arg}[1]{\textsl{#1}} -\newcommand{\variable}[1]{\textsl{#1}} - -\begin{document} - -\maketitle - -\tableofcontents - -\parskip=5pt -\pagebreak - -\section{Introduction} - -This document essentially sets up various simple scenarios and then -shows how to solve the problems using Botan. It's fairly simple, and -doesn't cover many of the available APIs and algorithms, especially -the more obscure or unusual ones. It is a supplement to the API -documentation and the example applications, which are included in the -distribution. - -To quote the Perl man page: '``There's more than one way to do it.'' -Divining how many more is left as an exercise to the reader.' - -This is \emph{not} a general introduction to cryptography, and most simple -terms and ideas are not explained in any great detail. - -Finally, most of the code shown in this tutorial has not been tested, it was -just written down from memory. If you find errors, please let me know. - -\section{Initializing the Library} - -The first step to using Botan is to create a \type{LibraryInitializer} object, -which handles creating various internal structures, and also destroying them at -shutdown. Essentially: - -\begin{verbatim} -#include <botan/botan.h> -/* include other headers here */ - -int main() - { - LibraryInitializer init; - /* now do stuff */ - return 0; - } -\end{verbatim} - -\section{Hashing a File} - -\section{Symmetric Cryptography} - -\subsection{Encryption with a passphrase} - -Probably the most common crypto problem is encrypting a file (or some data that -is in-memory) using a passphrase. There are a million ways to do this, most of -them bad. In particular, you have to protect against weak passphrases, -people reusing a passphrase many times, accidental and deliberate modification, -and a dozen other potential problems. - -We'll start with a simple method that is commonly used, and show the problems -that can arise. Each subsequent solution will modify the previous one to -prevent one or more common problems, until we arrive at a good version. - -In these examples, we'll always use Serpent in Cipher-Block Chaining -(CBC) mode. Whenever we need a hash function, we'll use SHA-256, since -that is a common and well-known hash that is thought to be secure. - -In all examples, we choose to derive the Initialization Vector (IV) from the -passphrase. Another (probably more common) alternative is to generate the IV -randomly and include it at the beginning of the message. Either way is -acceptable, and can be secure. The method used here was chosen to make for more -interesting examples (because it's harder to get right), and may not be an -appropriate choice for some environments. - -First, some notation. The passphrase is stored as a \type{std::string} named -\variable{passphrase}. The input and output files (\variable{infile} and -\variable{outfile}) are of types \type{std::ifstream} and \type{std::ofstream} -(respectively). - -\subsubsection{First try} - -We hash the passphrase with SHA-256, and use the resulting hash to key -Serpent. To generate the IV, we prepend a single '0' character to the -passphrase, hash it, and truncate it to 16 bytes (which is Serpent's -block size). - -\begin{verbatim} - HashFunction* hash = get_hash("SHA-256"); - - SymmetricKey key = hash->process(passphrase); - SecureVector<byte> raw_iv = hash->process('0' + passphrase); - InitializationVector iv(raw_iv, 16); - - Pipe pipe(get_cipher("Serpent/CBC/PKCS7", key, iv, ENCRYPTION)); - - pipe.start_msg(); - infile >> pipe; - pipe.end_msg(); - outfile << pipe; -\end{verbatim} - -\subsubsection{Problem 1: Buffering} - -There is a problem with the above code, if the input file is fairly large as -compared to available memory. Specifically, all the encrypted data is stored -in memory, and then flushed to \variable{outfile} in a single go at the very -end. If the input file is big (say, a gigabyte), this will be most problematic. - -The solution is to use a \type{DataSink} to handle the output for us (writing -to \arg{outfile} will be implicit with writing to the \type{Pipe}). We can do -this by replacing the last few lines with: - -\begin{verbatim} - Pipe pipe(get_cipher("Serpent/CBC/PKCS7", key, iv, ENCRYPTION), - new DataSink_Stream(outfile)); - - pipe.start_msg(); - infile >> pipe; - pipe.end_msg(); -\end{verbatim} - -\subsubsection{Problem 2: Deriving the key and IV} - -Hash functions like SHA-256 are deterministic; if the same passphrase -is supplied twice, then the key (and in our case, the IV) will be the -same. This is very dangerous, and could easily open the whole system -up to attack. What we need to do is introduce a salt (or nonce) into -the generation of the key from the passphrase. This will mean that the -key will not be the same each time the same passphrase is typed in by -a user. - -There is another problem with using a bare hash function to derive -keys. While it's inconceivable (based on our current understanding of -thermodynamics and theories of computation) that an attacker could -brute-force a 256-bit key, it would be fairly simple for them to -compute the SHA-256 hashes of various common passwords ('password', -the name of the dog, the significant other's middle name, favorite -sports team) and try those as keys. So we want to slow the attacker -down if we can, and an easy way to do that is to iterate the hash -function a bunch of times (say, 1024 to 4096 times). This will involve -only a small amount of effort for a legitimate user (since they only -have to compute the hashes once, when they type in their passphrase), -but an attacker, trying out a large list of potential passphrases, -will be seriously annoyed (and slowed down) by this. - -In this iteration of the example, we'll kill these two birds with one -stone, and derive the key from the passphrase using a PBKDF -(Password-Based Key Derivation Function). In this example, we use -PBKDF2 with Hash Message Authentication Code (HMAC(SHA-256)), which is -specified in PKCS \#5. We replace the first four lines of code from -the first example with: - -\begin{verbatim} - PBKDF* pbkdf = get_pbkdf("PBKDF2(SHA-256)"); - // hard-coded iteration count for simplicity; should be sufficient - pbkdf->set_iterations(10000); - // 8 octets == 64-bit salt; again, good enough - pbkdf->new_random_salt(8); - SecureVector<byte> the_salt = pbkdf->current_salt(); - - // 48 octets == 32 for key + 16 for IV - SecureVector<byte> key_and_IV = pbkdf->derive_key(48, passphrase).bits_of(); - - SymmetricKey key(key_and_IV, 32); - InitializationVector iv(key_and_IV + 32, 16); -\end{verbatim} - -To complete the example, we have to remember to write out the salt (stored in -\variable{the\_salt}) at the beginning of the file. The receiving side needs to -know this value in order to restore it (by calling the \variable{pbkdf} object's -\function{change\_salt} function) so it can derive the same key and IV from the -passphrase. - -\subsubsection{Problem 3: Protecting against modification} - -As it is, an attacker can undetectably alter the message while it is -in transit. It is vital to remember that encryption does not imply -authentication (except when using special modes that are specifically -designed to provide authentication along with encryption, like OCB and -EAX). For this purpose, we will append a message authentication code -to the encrypted message. Specifically, we will generate an extra 256 -bits of key data, and use it to key the ``HMAC(SHA-256)'' MAC -function. We don't want to have the MAC and the cipher to share the -same key; that is very much a no-no. - -\begin{verbatim} - // 80 octets == 32 for cipher key + 16 for IV + 32 for hmac key - SecureVector<byte> keys_and_IV = pbkdf->derive_key(80, passphrase); - - SymmetricKey key(keys_and_IV, 32); - InitializationVector iv(keys_and_IV + 32, 16); - SymmetricKey mac_key(keys_and_IV + 32 + 16, 32); - - Pipe pipe(new Fork( - new Chain( - get_cipher("Serpent/CBC/PKCS7", key, iv, ENCRYPTION), - new DataSink_Stream(outfile) - ), - new MAC_Filter("HMAC(SHA-256)", mac_key) - ) - ); - - pipe.start_msg(); - infile >> pipe; - pipe.end_msg(); - - // now read the MAC from message #2. Message numbers start from 0 - SecureVector<byte> hmac = pipe.read_all(1); - outfile.write((const char*)&hmac[0], hmac.size()); -\end{verbatim} - -The receiver can check the size of the file (in bytes), and since it knows how -long the MAC is, can figure out how many bytes of ciphertext there are. Then it -reads in that many bytes, sending them to a Serpent/CBC decryption object -(which could be obtained by calling \verb|get_cipher| with an argument of -\type{DECRYPTION} instead of \type{ENCRYPTION}), and storing the final bytes to -authenticate the message with. - -\subsubsection{Problem 4: Cleaning up the key generation} - -The method used to derive the keys and IV is rather inelegant, and it would be -nice to clean that up a bit, algorithmically speaking. A nice solution for this -is to generate a master key from the passphrase and salt, and then generate the -two keys and the IV (the cryptovariables) from that. - -Starting from the master key, we derive the cryptovariables using a KDF -algorithm, which is designed, among other things, to ``separate'' keys so that -we can derive several different keys from the single master key. For this -purpose, we will use KDF2, which is a generally useful KDF function (defined in -IEEE 1363a, among other standards). The use of different labels (``cipher -key'', etc) makes sure that each of the three derived variables will have -different values. - -\begin{verbatim} - PBKDF* pbkdf = get_pbkdf("PBKDF2(SHA-256)"); - // hard-coded iteration count for simplicity; should be sufficient - pbkdf->set_iterations(10000); - // 8 octet == 64-bit salt; again, good enough - pbkdf->new_random_salt(8); - // store the salt so we can write it to a file later - SecureVector<byte> the_salt = pbkdf->current_salt(); - - SymmetricKey master_key = pbkdf->derive_key(48, passphrase); - - KDF* kdf = get_kdf("KDF2(SHA-256)"); - - SymmetricKey key = kdf->derive_key(32, master_key, "cipher key"); - SymmetricKey mac_key = kdf->derive_key(32, master_key, "hmac key"); - InitializationVector iv = kdf->derive_key(16, master_key, "cipher iv"); -\end{verbatim} - -\subsubsection{Final version} - -Here is the final version of the encryption code, with all the changes we've -made: - -\begin{verbatim} - PBKDF* pbkdf = get_pbkdf("PBKDF2(SHA-256)"); - pbkdf->set_iterations(10000); - pbkdf->new_random_salt(8); - SecureVector<byte> the_salt = pbkdf->current_salt(); - - SymmetricKey master_key = pbkdf->derive_key(48, passphrase); - - KDF* kdf = get_kdf("KDF2(SHA-256)"); - - SymmetricKey key = kdf->derive_key(32, master_key, "cipher key"); - SymmetricKey mac_key = kdf->derive_key(32, masterkey, "hmac key"); - InitializationVector iv = kdf->derive_key(16, masterkey, "cipher iv"); - - Pipe pipe(new Fork( - new Chain( - get_cipher("Serpent/CBC/PKCS7", key, iv, ENCRYPTION), - new DataSink_Stream(outfile) - ), - new MAC_Filter("HMAC(SHA-256)", mac_key) - ) - ); - - outfile.write((const char*)&the_salt[0], the_salt.size()); - - pipe.start_msg(); - infile >> pipe; - pipe.end_msg(); - - SecureVector<byte> hmac = pipe.read_all(1); - outfile.write((const char*)&hmac[0], hmac.size()); -\end{verbatim} - -\subsubsection{Another buffering technique} - -Sometimes the use of \type{DataSink\_Stream} is not practical for whatever -reason. In this case, an alternate buffering mechanism might be useful. Here is -some code which will write all the processed data as quickly as possible, so -that memory pressure is reduced in the case of large inputs. - -\begin{verbatim} - pipe.start_msg(); - SecureBuffer<byte, 1024> buffer; - while(infile.good()) - { - infile.read((char*)&buffer[0], buffer.size()); - u32bit got_from_infile = infile.gcount(); - pipe.write(buffer, got_from_infile); - - if(infile.eof()) - pipe.end_msg(); - - while(pipe.remaining() > 0) - { - u32bit buffered = pipe.read(buffer, buffer.size()); - outfile.write((const char*)&buffer[0], buffered); - } - } - if(infile.bad() || (infile.fail() && !infile.eof())) - throw Some_Exception(); -\end{verbatim} - -\pagebreak - -\subsection{Authentication} - -After doing the encryption routines, doing message authentication keyed off a -passphrase is not very difficult. In fact it's much easier than the encryption -case, for the following reasons: a) we only need one key, and b) we don't have -to store anything, so all the input can be done in a single step without -worrying about it taking up a lot of memory if the input file is large. - -In this case, we'll hex-encode the salt and the MAC, and output them both to -standard output (the salt followed by the MAC). - -\begin{verbatim} - PBKDF* pbkdf = get_pbkdf("PBKDF2(SHA-256)"); - pbkdf->set_iterations(10000); - pbkdf->new_random_salt(8); - OctetString the_salt = pbkdf->current_salt(); - - SymmetricKey hmac_key = pbkdf->derive_key(32, passphrase); - - Pipe pipe(new MAC_Filter("HMAC(SHA-256)", mac_key), - new Hex_Encoder - ); - - std::cout << the_salt.to_string(); // hex encoded - - pipe.start_msg(); - infile >> pipe; - pipe.end_msg(); - std::cout << pipe.read_all_as_string() << std::endl; -\end{verbatim} - -\subsection{User Authentication} - -Doing user authentication off a shared passphrase is fairly easy. Essentially, -a challenge-response protocol is used - the server sends a random challenge, -and the client responds with an appropriate response to the challenge. The idea -is that only someone who knows the passphrase can generate or check to see if a -response is valid. - -Let's say we use 160-bit (20 byte) challenges, which seems fairly -reasonable. We can create this challenge using the global random -number generator (RNG): - -\begin{verbatim} - byte challenge[20]; - Global_RNG::randomize(challenge, sizeof(challenge), Nonce); - // send challenge to client -\end{verbatim} - -After reading the challenge, the client generates a response based on -the challenge and the passphrase. In this case, we will do it by -repeatedly hashing the challenge, the passphrase, and (if applicable) -the previous digest. We iterate this construction 10000 times, to make -brute force attacks on the passphrase hard to do. Since we are already -using 160-bit challenges, a 160-bit response seems warranted, so we'll -use SHA-1. - -\begin{verbatim} - HashFunction* hash = get_hash("SHA-1"); - SecureVector<byte> digest; - for(u32bit j = 0; j != 10000; j++) - { - hash->update(digest, digest.size()); - hash->update(passphrase); - hash->update(challenge, challenge.size()); - digest = hash->final(); - } - delete hash; - // send value of digest to the server -\end{verbatim} - -Upon receiving the response from the client, the server computes what the -response should have been based on the challenge it sent out, and the -passphrase. If the two responses match, the client is authenticated. -Otherwise, it is not. - -An alternate method is to use PBKDF2 again, using the challenge as the salt. In -this case, the response could (for example) be the hash of the key produced by -PBKDF2. There is no reason to have an explicit iteration loop, as PBKDF2 is -designed to prevent dictionary attacks (assuming PBKDF2 is set up for a large -iteration count internally). - -\pagebreak - -\section{Public Key Cryptography} - -\subsection{Basic Operations} - -In this section, we'll assume we have a \type{X509\_PublicKey*} named -\arg{pubkey}, and, if necessary, a private key type (a -\type{PKCS8\_PrivateKey*}) named \arg{privkey}. A description of these types, -how to create them, and related details appears later in this tutorial. In this -section, we will use various functions that are defined in -\filename{look\_pk.h} -- you will have to include this header explicitly. - -\subsubsection{Encryption} - -Basically, pick an encoding method, create a \type{PK\_Encryptor} (with -\function{get\_pk\_encryptor}()), and use it. But first we have to make sure -the public key can actually be used for public key encryption. For encryption -(and decryption), the key could be RSA, ElGamal, or (in future versions) some -other public key encryption scheme, like Rabin or an elliptic curve scheme. - -\begin{verbatim} - PK_Encrypting_Key* key = dynamic_cast<PK_Encrypting_Key*>(pubkey); - if(!key) - error(); - PK_Encryptor* enc = get_pk_encryptor(*key, "EME1(SHA-256)"); - - byte msg[] = { /* ... */ }; - - // will also accept a SecureVector<byte> as input - SecureVector<byte> ciphertext = enc->encrypt(msg, sizeof(msg)); -\end{verbatim} - -\subsubsection{Decryption} - -This is essentially the same as the encryption operation, but using a private -key instead. One major difference is that the decryption operation can fail due -to the fact that the ciphertext was invalid (most common padding schemes, such -as ``EME1(SHA-256)'', include various pieces of redundancy, which are checked -after decryption). - -\begin{verbatim} - PK_Decrypting_Key* key = dynamic_cast<PK_Decrypting_Key*>(privkey); - if(!key) - error(); - PK_Decryptor* dec = get_pk_decryptor(*key, "EME1(SHA-256)"); - - byte msg[] = { /* ... */ }; - - SecureVector<byte> plaintext; - - try { - // will also accept a SecureVector<byte> as input - plaintext = dec->decrypt(msg, sizeof(msg)); - } - catch(Decoding_Error) - { - /* the ciphertext was invalid */ - } -\end{verbatim} - -\subsubsection{Signature Generation} - -There is one difficulty with signature generation that does not occur with -encryption or decryption. Specifically, there are various padding methods which -can be useful for different signature algorithms, and not all are appropriate -for all signature schemes. The following table breaks down what algorithms -support which encodings: - -\begin{tabular}{|c|c|c|} \hline -Signature Algorithm & Usable Encoding Methods & Preferred Encoding(s) \\ \hline -DSA / NR & EMSA1 & EMSA1 \\ \hline -RSA & EMSA1, EMSA2, EMSA3, EMSA4 & EMSA3, EMSA4 \\ \hline -Rabin-Williams & EMSA2, EMSA4 & EMSA2, EMSA4 \\ \hline -\end{tabular} - -For new applications, use EMSA4 with both RSA and Rabin-Williams, as it is -significantly more secure than the alternatives. However, most current -applications/libraries only support EMSA2 with Rabin-Williams and EMSA3 with -RSA. Given this, you may be forced to use less secure encoding methods for the -near future. In these examples, we punt on the problem, and hard-code using -EMSA1 with SHA-256. - -\begin{verbatim} - Public_Key* key = /* loaded or generated somehow */ - PK_Signer* signer = get_pk_signer(*key, "EMSA1(SHA-256)"); - - byte msg[] = { /* ... */ }; - - /* - You can also repeatedly call update(const byte[], u32bit), followed - by a call to signature(), which will return the final signature of - all the data that was passed through update(). sign_message() is - just a stub that calls update() once, and returns the value of - signature(). - */ - - SecureVector<byte> signature = signer->sign_message(msg, sizeof(msg)); -\end{verbatim} - -\pagebreak - -\subsubsection{Signature Verification} - -In addition to all the problems with choosing the correct padding method, -there is yet another complication with verifying a signature. Namely, there are -two varieties of signature algorithms - those providing message recovery (that -is, the value that was signed can be directly recovered by someone verifying -the signature), and those without message recovery (the verify operation simply -returns if the signature was valid, without telling you exactly what was -signed). This leads to two slightly different implementations of the -verification operation, which user code has to work with. As you can see -however, the implementation is still not at all difficult. - -\begin{verbatim} - PK_Verifier* verifier = 0; - - PK_Verifying_with_MR_Key* key1 = - dynamic_cast<PK_Verifying_with_MR_Key*>(pubkey); - PK_Verifying_wo_MR_Key* key2 = - dynamic_cast<PK_Verifying_wo_MR_Key*>(pubkey); - - if(key1) - verifier = get_pk_verifier(*key1, "EMSA1(SHA-256)"); - else if(key2) - verifier = get_pk_verifier(*key2, "EMSA1(SHA-256)"); - else - error(); - - byte msg[] = { /* ... */ }; - byte sig[] = { /* ... */ }; - - /* - Like PK_Signer, you can also do repeated calls to - void update(const byte some_data[], u32bit length) - followed by a call to - bool check_signature(const byte the_sig[], u32bit length) - which will return true (valid signature) or false (bad signature). - The function verify_message() is a simple wrapper around update() and - check_signature(). - - */ - bool is_valid = verifier->verify_message(msg, sizeof(msg), sig, sizeof(sig)); -\end{verbatim} - -\subsubsection{Key Agreement} - -WRITEME - -\pagebreak - -\subsection{Working with Keys} - -\subsubsection{Reading Public Keys (X.509 format)} - -There are two separate ways to read X.509 public keys. Remember that the X.509 -public keys are simply that: public keys. There is no associated information -(such as the owner of that key) included with the public key itself. If you -need that kind of information, you'll need to use X.509 certificates. - -However, there are surely times when a simple public key is sufficient. The -most obvious is when the key is implicitly trusted, for example if access -and/or modification of it is controlled by something else (like filesystem -ACLs). In other cases, it is a perfectly reasonable proposition to use them -over the network as an anonymous key exchange mechanism. This is, admittedly, -vulnerable to man-in-the-middle attacks, but it's simple enough that it's hard -to mess up (see, for example, Peter Guttman's paper ``Lessons Learned in -Implementing and Deploying Crypto Software'' in Usenix '02). - -The way to load a key is basically to set up a \type{DataSource} and then call -\function{X509::load\_key}, which will return a \type{X509\_PublicKey*}. For -example: - -\begin{verbatim} - DataSource_Stream somefile("somefile.pem"); // has 3 public keys - X509_PublicKey* key1 = X509::load_key(somefile); - X509_PublicKey* key2 = X509::load_key(somefile); - X509_PublicKey* key3 = X509::load_key(somefile); - // Now we have them all loaded. Huzah! -\end{verbatim} - -At this point you can use \function{dynamic\_cast} to find the operations the -key supports (by seeing if a cast to \type{PK\_Encrypting\_Key}, -\type{PK\_Verifying\_with\_MR\_Key}, or \type{PK\_Verifying\_wo\_MR\_Key} -succeeds). - -There is a variant of \function{X509::load\_key} (and of -\function{PKCS8::load\_key}, described in the next section) which take a -filename (as a \type{std::string}). These are just convenience functions which -create the appropriate \type{DataSource} for you and call the main -\function{X509::load\_key}. - -\subsubsection{Reading Private Keys (PKCS \#8 format)} - -This is very similar to reading raw public keys, with the difference that the -key may be encrypted with a user passphrase: - -\begin{verbatim} - // rng is a RandomNumberGenerator, like AutoSeeded_RNG - - DataSource_Stream somefile("somefile"); - std::string a_passphrase = /* get from the user */ - PKCS8_PrivateKey* key = PKCS8::load_key(somefile, rng, a_passphrase); -\end{verbatim} - -You can, by the way, convert a \type{PKCS8\_PrivateKey} to a -\type{X509\_PublicKey} simply by casting it (with \function{dynamic\_cast}), as -the private key type is derived from \type{X509\_PublicKey}. As with -\type{X509\_PublicKey}, you can use \function{dynamic\_cast} to figure out what -operations the private key is capable of; in particular, you can attempt to -cast it to \type{PK\_Decrypting\_Key}, \type{PK\_Signing\_Key}, or -\type{PK\_Key\_Agreement\_Key}. - -Sometimes you can get away with having a static passphrase passed to -\function{load\_key}. Typically, however, you'll have to do some user -interaction to get the appropriate passphrase. In that case you'll want to use -the \type{UI} related interface, which is fully described in the API -documentation. - -\subsubsection{Generating New Private Keys} - -Generate a new private key is the one operation which requires you to -explicitly name the type of key you are working with. There are (currently) two -kinds of public key algorithms in Botan: ones based on the integer -factorization (IF) problem (RSA and Rabin-Williams), and ones based on the -discrete logarithm (DL) problem (DSA, Diffie-Hellman, Nyberg-Rueppel, and -ElGamal). Since discrete logarithm parameters (primes and generators) can be -shared among many keys, there is the notion of these being a combined type -(called \type{DL\_Group}). - -To create a new DL-based private key, simply pass a desired \type{DL\_Group} to -the constructor of the private key - a new public/private key pair will be -generated. Since in IF-based algorithms, the modulus used isn't shared by other -keys, we don't use this notion. You can create a new key by passing in a -\type{u32bit} telling how long (in bits) the key should be. - -There are quite a few ways to get a \type{DL\_Group} object. The best is to use -the function \function{get\_dl\_group}, which takes a string naming a group; it -will either return that group, if it knows about it, or throw an -exception. Names it knows about include ``IETF-n'' where n is 768, 1024, 1536, -2048, 3072, or 4096, and ``DSA-n'', where n is 512, 768, or 1024. The IETF -groups are the ones specified for use with IPSec, and the DSA ones are the -default DSA parameters specified by Java's JCE. For DSA and Nyberg-Rueppel, use -the ``DSA-n'' groups, and for Diffie-Hellman and ElGamal, use the ``IETF-n'' -groups. - -You can also generate a new random group. This is not recommend, because it is -very slow, particularly for ``safe'' primes, which are needed for -Diffie-Hellman and ElGamal. - -Some examples: - -\begin{verbatim} - RSA_PrivateKey rsa1(512); // 512-bit RSA key - RSA_PrivateKey rsa2(2048); // 2048-bit RSA key - - RW_PrivateKey rw1(1024); // 1024-bit Rabin-Williams key - RW_PrivateKey rw2(1536); // 1536-bit Rabin-Williams key - - DSA_PrivateKey dsa(get_dl_group("DSA-512")); // 512-bit DSA key - DH_PrivateKey dh(get_dl_group("IETF-4096")); // 4096-bit DH key - NR_PrivateKey nr(get_dl_group("DSA-1024")); // 1024-bit NR key - ElGamal_PrivateKey elg(get_dl_group("IETF-1536")); // 1536-bit ElGamal key -\end{verbatim} - -To export your newly created private key, use the PKCS \#8 routines in -\filename{pkcs8.h}: - -\begin{verbatim} - std::string a_passphrase = /* get from the user */ - std::string the_key = PKCS8::PEM_encode(rsa2, a_passphrase); -\end{verbatim} - -You can read the key back in using \function{PKCS8::load\_key}, described in -the section ``Reading Private Keys (PKCS \#8 format)'', above. Unfortunately, -this only works with keys that have an assigned algorithm identifier and -standardized format. Currently this is only the RSA, DSA, DH, and ElGamal -algorithms, though RW and NR keys can also be imported and exported by -assigning them an OID (this can be done either through a configuration file, or -by calling the function \function{OIDS::add\_oid} in \filename{oids.h}). Be -aware that the OID and format for ElGamal keys is not exactly standard, but -there does exist at least one other crypto library which will accept the -format. - -The raw public can be exported using: - -\begin{verbatim} - std::string the_public_key = X509::PEM_encode(rsa2); -\end{verbatim} - -\pagebreak - -\section{X.509v3 Certificates} - -Using certificates is rather complicated, so only the very basic mechanisms are -going to be covered here. The section ``Setting up a CA'' goes into reasonable -detail about CRLs and certificate requests, but there is a lot that isn't -covered (else this section would get quite long and complicated). - -\subsection{Importing and Exporting Certificates} - -Importing and exporting X.509 certificates is easy. Simply call the constructor -with either a \type{DataSource\&}, or the name of a file: - -\begin{verbatim} - X509_Certificate cert1("cert1.pem"); - - /* This file contains two certificates, concatenated */ - DataSource_Stream in("certs2_and_3.pem"); - - X509_Certificate cert2(in); // read the first cert - X509_Certificate cert3(in); // read the second cert -\end{verbatim} - -Exporting the certificate is a simple matter of calling the member function -\function{PEM\_encode}(), which returns a \type{std::string} containing the -certificate in PEM encoding. - -\begin{verbatim} - std::cout << cert3.PEM_encode(); - some_ostream_object << cert1.PEM_encode(); - std::string cert2_str = cert2.PEM_encode(); -\end{verbatim} - -\subsection{Verifying Certificates} - -Verifying a certificate requires that we build up a chain of trust, starting -from the root (usually a commercial CA), down through some number of -intermediate CAs, and finally reaching the actual certificate in -question. Thus, to verify, we actually have to have all those certificates -on hand (or at the very least, know where we can get the ones we need). - -The class which handles both storing certificates, and verifying them, is -called \type{X509\_Store}. We'll start by assuming that we have all the -certificates we need, and just want to verify a cert. This is done by calling -the member function \function{validate\_cert}, which takes the -\type{X509\_Certificate} in question, and an optional argument of type -\type{Cert\_Usage} (which is ignored here; read the section in the API doc -titled ``Verifying Certificates for information). It returns an enum; -\type{X509\_Code}, which, for most purposes, is either \type{VERIFIED}, or -something else (which specifies what circumstance caused the certificate to be -considered invalid). Really, that's it. - -Now, how to let \type{X509\_Store} know about all those certificates and CRLs -we have lying around? The simplest method is to add them directly, using the -functions \function{add\_cert}, \function{add\_certs}, -\function{add\_trusted\_certs}, and \function{add\_crl}; for details, consult -the API doc or read the \filename{x509stor.h} header. There is also a much more -elegant and powerful method: \type{Certificate\_Store}s. A certificate store -refers to an object that knows how to retrieve certificates from some external -source (a file, an LDAP directory, a HTTP server, a SQL database, or anything -else). By calling the function \function{add\_new\_certstore}, you can register -a new certificate store, which \type{X509\_Store} will use to find certificates -it needs. Thus, you can get away with only adding whichever root CA cert(s) you -want to use, letting some online source handle the storage of all intermediate -X.509 certificates. The API documentation has a more complete discussion of -\type{Certificate\_Store}. - -\subsection{Setting up a CA} - -WRITEME - -\pagebreak - -\section{Special Topics} - -This chapter is for subjects that don't really fit into the API documentation -or into other chapters of the tutorial. - -\subsection{GUIs} - -There is nothing particularly special about using Botan in a GUI-based -application. However there are a few tricky spots, as well as a few ways to -take advantage of an event-based application. - -\subsubsection{Initialization} - -Generally you will create the \type{LibraryInitializer} somewhere in -\texttt{main}, before entering the event loop. One problem is that some GUI -libraries take over \texttt{main} and drop you right into the event loop; the -question then is how to initialize the library? The simplest way is probably to -have a static flag that marks if you have already initialized the library or -not. When you enter the event loop, check to see if this flag has not been set, -and if so, initialize the library using the function-based initializers. Using -\type{LibraryInitializer} obviously won't work in this case, since it would be -destroyed as soon as the current event handler finished. You then deinitialize -the library whenever your application is signaled to quit. - -\subsubsection{Interacting With the Library} - -In the simple case, the user will do stuff asynchronously, and then in response -your code will do things like encrypt a file or whatever, which can all be done -synchronously, since the data is right there for you. An application doing -something like this is basically going to look exactly like a command line -application that uses Botan, the only major difference being that the calls to -the library are inside event handlers. - -Much harder is something like an SSH client, where you're acting as a layer -between two asynchronous things (the user and the network). This actually isn't -restricted to GUIs at all (text-mode SSH clients have to deal with most of the -same problems), but it is probably more common with a GUI app. The following -discussion is fairly vague, but hopefully somewhat useful. - -There are a few facilities in Botan that are primarily designed to be used by -applications based on an event loop. See the section ``User Interfaces'' in the -main API doc for details. - -\subsubsection{Entropy} - -One nice advantage of using a GUI is opening a new method of gathering entropy -for the library. This is especially handy on Windows, where the available -sources of entropy are pretty questionable. In many versions, -\texttt{CryptGenRandom} is really rather poor, and the Toolhelp functions may -not provide much data on a small system (such as a handheld). For example, in -GTK+, you can use the following callback to get information about mouse -movements: - -\begin{verbatim} -static gint add_entropy(GtkWidget* widget, GdkEventMotion* event) - { - if(event) - Global_RNG::add_entropy(event, sizeof(GdkEventMotion)); - return FALSE; - } -\end{verbatim} - -And then register it with your main GTK window (presumably named -\variable{window}) as follows: - -\begin{verbatim} -gtk_signal_connect(GTK_OBJECT(window), "motion_notify_event", - GTK_SIGNAL_FUNC(add_entropy), NULL); - -gtk_widget_set_events(window, GDK_POINTER_MOTION_MASK); -\end{verbatim} - -Even though we're catching all mouse movements, and hashing the results into -the entropy pool, this doesn't use up more than a few percent of even a -relatively slow desktop CPU. Note that in the case of using X over a network, -catching all mouse events would cause large amounts of X traffic over the -network, which might make your application slow, or even unusable (I haven't -tried it, though). - -This could be made nicer if the collection function did something like -calculating deltas between each run, storing them into a buffer, and then when -enough of them have been added, hashing them and send them all to the PRNG in -one shot. This would not only reduce load, but also prevent the PRNG from -overestimating the amount of entropy it's getting, since its estimates don't -(can't) take history into account. For example, you could move the mouse back -and forth one pixel, and the PRNG would think it was getting a full load of -entropy each time, when actually it was getting (at best) a bit or two. - -\end{document} diff --git a/doc/passhash.txt b/doc/passhash.txt new file mode 100644 index 000000000..8ce3cf805 --- /dev/null +++ b/doc/passhash.txt @@ -0,0 +1,117 @@ + +Password Hashing +======================================== + +Storing passwords for user authentication purposes in plaintext is the +simplest but least secure method; when an attacker compromises the +database in which the passwords are stored, they immediately gain +access to all of them. Often passwords are reused among multiple +services or machines, meaning once a password to a single service is +known an attacker has a substantial head start on attacking other +machines. + +The general approach is to store, instead of the password, the output +of a one way function of the password. Upon receiving an +authentication request, the authenticator can recompute the one way +function and compare the value just computed with the one that was +stored. If they match, then the authentication request succeeds. But +when an attacker gains access to the database, they only have the +output of the one way function, not the original password. + +Common hash functions such as SHA-256 are one way, but used alone they +have problems for this purpose. What an attacker can do, upon gaining +access to such a stored password database, is hash common dictionary +words and other possible passwords, storing them in a list. Then he +can search through his list; if a stored hash and an entry in his list +match, then he has found the password. Even worse, this can happen +*offline*: an attacker can begin hashing common passwords days, +months, or years before ever gaining access to the database. In +addition, if two users choose the same password, the one way function +output will be the same for both of them, which will be visible upon +inspection of the database. + +There are two solutions to these problems: salting and +iteration. Salting refers to including, along with the password, a +randomly chosen value which perturbs the one way function. Salting can +reduce the effectivness of offline dictionary generation (because for +each potential password, an attacker would have to compute the one way +function output for all possible salts - with a large enough salt, +this can make the problem quite difficult). It also prevents the same +password from producing the same output, as long as the salts do not +collide. With a large salt (say 80 to 128 bits) this will be quite +unlikely. Iteration refers to the general technique of forcing +multiple one way function evaluations when computing the output, to +slow down the operation. For instance if hashing a single password +requires running SHA-256 100,000 times instead of just once, that will +slow down user authentication by a factor of 100,000, but user +authentication happens quite rarely, and usually there are more +expensive operations that need to occur anyway (network and database +I/O, etc). On the other hand, an attacker who is attempting to break a +database full of stolen password hashes will be seriously +inconvenienced by a factor of 100,000 slowdown; they will be able to +only test at a rate of .0001% of what they would without iterations +(or, equivalently, will require 100,000 times as many zombie botnet +hosts). + +Botan provides two techniques for password hashing, bcrypt and +passhash9. + +.. _bcrypt: + +Bcrypt Password Hashing +---------------------------------------- + +Bcrypt is a password hashing scheme originally designed for use in +OpenBSD, but numerous other implementations exist. It is made +available by including ``bcrypt.h``. Bcrypt provides outputs that +look like this:: + + "$2a$12$7KIYdyv8Bp32WAvc.7YvI.wvRlyVn0HP/EhPmmOyMQA4YKxINO0p2" + +.. cpp:function:: std::string generate_bcrypt(const std::string& password, \ + RandomNumberGenerator& rng, u16bit work_factor = 10) + + Takes the password to hash, a rng, and a work factor. Higher values + increase the amount of time the algorithm runs, increasing the cost + of cracking attempts. The resulting hash is returned as a string. + +.. cpp:function:: bool check_bcrypt(const std::string& password, \ + const std::string& hash) + + Takes a password and a bcrypt output and returns true if the + password is the same as the one that was used to generate the + bcrypt hash. + +Here is an example of using bcrypt: + +.. literalinclude:: examples/bcrypt.cpp + +.. _passhash9: + +Passhash9 +---------------------------------------- + +Botan also provides a password hashing technique called passhash9, in +``passhash9.h``, which is based on PBKDF2. Its outputs look like:: + + "$9$AAAKxwMGNPSdPkOKJS07Xutm3+1Cr3ytmbnkjO6LjHzCMcMQXvcT" + +.. cpp:function:: std::string generate_passhash9(const std::string& password, \ + RandomNumberGenerator& rng, u16bit work_factor = 10, byte alg_id = 0) + + Functions much like ``generate_bcrypt``. The last parameter, + ``alg_id``, specifies which PRF to use. Currently defined values + are + + ======= ============== + Value PRF algorithm + ======= ============== + 0 HMAC(SHA-1) + 1 HMAC(SHA-256) + 2 CMAC(Blowfish) + ======= ============== + +.. cpp:function:: bool check_passhash9(const std::string& password, \ + const std::string& hash) + + Functions much like ``check_bcrypt`` diff --git a/doc/pbkdf.txt b/doc/pbkdf.txt new file mode 100644 index 000000000..f24dcd188 --- /dev/null +++ b/doc/pbkdf.txt @@ -0,0 +1,76 @@ + +.. _pbkdf: + +PBKDF Algorithms +======================================== + +There are various procedures for turning a passphrase into a arbitrary +length key for use with a symmetric cipher. A general interface for +such algorithms is presented in ``pbkdf.h``. The main function is +``derive_key``, which takes a passphrase, a salt, an iteration count, +and the desired length of the output key, and returns a key of that +length, deterministically produced from the passphrase and salt. If an +algorithm can't produce a key of that size, it will throw an exception +(most notably, PKCS #5's PBKDF1 can only produce strings between 1 and +$n$ bytes, where $n$ is the output size of the underlying hash +function). + +The purpose of the iteration count is to make the algorithm take +longer to compute the final key (reducing the speed of brute-force +attacks of various kinds). Most standards recommend an iteration count +of at least 10000. Currently defined PBKDF algorithms are +"PBKDF1(digest)", "PBKDF2(digest)", and "OpenPGP-S2K(digest)"; you can +retrieve any of these using the ``get_pbkdf``, found in +``lookup.h``. As of this writing, "PBKDF2(SHA-256)" with 10000 +iterations and a 16 byte salt is recommend for new applications. + +.. cpp:function:: OctetString PBKDF::derive_key( \ + size_t output_len, const std::string& passphrase, \ + const byte* salt, size_t salt_len, \ + size_t iterations) const + + Computes a key from *passphrase* and the *salt* (of length + *salt_len* bytes) using an algorithm-specific interpretation of + *iterations*, producing a key of length *output_len*. + + Use an iteration count of at least 10000. The salt should be + randomly chosen by a good random number generator (see + :ref:`random_number_generators` for how), or at the very least + unique to this usage of the passphrase. + + If you call this function again with the same parameters, you will + get the same key. + +:: + + PBKDF* pbkdf = get_pbkdf("PBKDF2(SHA-256)"); + AutoSeeded_RNG rng; + + SecureVector<byte> salt = rng.random_vec(16); + OctetString aes256_key = pbkdf->derive_key(32, "password", + &salt[0], salt.size(), + 10000); + + +OpenPGP S2K +---------------------------------------- + +There are some oddities about OpenPGP's S2K algorithms that are +documented here. For one thing, it uses the iteration count in a +strange manner; instead of specifying how many times to iterate the +hash, it tells how many *bytes* should be hashed in total +(including the salt). So the exact iteration count will depend on the +size of the salt (which is fixed at 8 bytes by the OpenPGP standard, +though the implementation will allow any salt size) and the size of +the passphrase. + +To get what OpenPGP calls "Simple S2K", set iterations to 0, and do +not specify a salt. To get "Salted S2K", again leave the iteration +count at 0, but give an 8-byte salt. "Salted and Iterated S2K" +requires an 8-byte salt and some iteration count (this should be +significantly larger than the size of the longest passphrase that +might reasonably be used; somewhere from 1024 to 65536 would probably +be about right). Using both a reasonably sized salt and a large +iteration count is highly recommended to prevent password guessing +attempts. + diff --git a/doc/pgpkey.txt b/doc/pgpkey.txt new file mode 100644 index 000000000..ef8827835 --- /dev/null +++ b/doc/pgpkey.txt @@ -0,0 +1,43 @@ + +PGP Code Signing Key +======================================== + +.. highlight:: none + +The following PGP key is used to sign all releases:: + + pub 2048R/EFBADFBC 2004-10-30 + Key fingerprint = 621D AF64 11E1 851C 4CF9 A2E1 6211 EBF1 EFBA DFBC + uid Botan Distribution Key + + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: GnuPG v2.0.17 (GNU/Linux) + + mQELBEGD1j0BCADHxPJkPcjJE+4Dlisx2hVc0Dj6JI1MSLrkM8R+2bOhVUSferxP + T1EMPhfrAdOHTAloyvRThJztnZsNKqfLL49GGcBLdEGAVNks1pG37Teze5Lx1XIu + zJFrozL2sqBy5C6nHpFgd1tcD68Rah2wp0u2cR9owXf1IqKdEfuo661+MTv7wTB1 + 4hKV75nB7ZO6676SEZRILYM+7RJwKAKEmEPJc6hEf94VXn9ecNzaTlHgYkjhz9db + LOd3od9XvuUw+LMR1dwBqMxbvR90MiXjbedDEkbArcZB9YOAIvEX/lC3qaW4XJt4 + iwHWl/YVZEfALcvQywe2CDrH5hO794wd9MpBAAYptBZCb3RhbiBEaXN0cmlidXRp + b24gS2V5iQEqBBMBAgAUAhsDAh4BAheABQJKfFpnBBUKCQgACgkQYhHr8e+637xk + PQf/aOi78XenwwvFrwXOVIVTdZIf8rK1zJksf26h09UD8uVV6z5iiTcpn86+eN9p + 6Ar8IH3tD+JuFnPSwZ/r9MNC2XZwenYo4Gb14jqM6/9hBe328vmeM4Y1G7bD4HrL + kgV5WEyokqm3zbp3FBLr3Vh68TAC5JB9aHevra+cCA2u3vBNI3YUM5z4TdO150P3 + J00whkqImQEUni8bgxvllBLFM+uhucsX3HZWkoDEpotbg8yd0bqMkiPEyMr1OnJq + eDVDMrB5wnyLgLFfRAAw3mopM0C1PNOAHr/BIYiaDHX2OwnOfep8rMDoRVf2Ge0D + DBgsJJ6LduQHLeg403SHWL2F6YkCHAQTAQIABgUCQYPWUgAKCRBcD5boTsFta+r9 + EACWVis7YcaGkKKgRB/5ox8rM36XVhMXdh/hnnGHt5rapbbRRkRHRcWU8WIcFO1A + 59+TfwNNd8gN1MEt/5aX5KHWVKHBDexJgIxm6Dm1pisYHf/dnYQPM18hmqqwNlKY + 97hFkPpHd7enrtc/SvGbQhhLXYlpwBrdMl76e9xJLnnrRQksxegGPo8cr+C9HTs1 + Lwa8zzBxyBwYBYX+0moDkDShEhuXx6mEOXrGvQanJuIvpoIwGH+62E65MbJGlwWp + w/MAtm2jFhBIhGV0bqJCFp9zIgdNgfskBaPr0oilbuJQZqP0Iqe/6CCt4XkS51yW + ZqxjLAFpEpvDec4PGw3witKf/koGon9X8C035+nEjLBrWy18Q91vw2USyLI+mm9d + iMAS8pY2gomfxBO2VwYHJryZykjCYQkccRA1tHteRj4gqTObo0Ak47y5MnplTWwi + 40oP7K2cfhCRBmMioxmYES4xsHEupfRBo3xr1Jq9q0t688WTT1NXHPMPoueF9mKZ + Cf2pa9aHsqBmWTm3sCaNQKGubCDBEUmJUyndmSatJyYM7NVYoUp6EfqMACFuTNdB + sjKMh7aWVikQpbJDfA1BIU3lZeqgjgrghVAWkEOBfhG0IVZj+RVCJpsqoTJ8asY2 + VreArSCyr/VnLEnfuH/QpgvCiCbepo3E34DJt4SaAOO2ZohGBBARAgAGBQJMGVc1 + AAoJEKY/LL36AvvMgsoAn2G7kXd09BF7ffk1Sfh174SVrvM9AKC7+R7x0+yV3SCd + JkkUOo3xR5cOxw== + =1QuR + -----END PGP PUBLIC KEY BLOCK----- diff --git a/doc/pgpkeys.asc b/doc/pgpkeys.asc deleted file mode 100644 index 378230f32..000000000 --- a/doc/pgpkeys.asc +++ /dev/null @@ -1,83 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v2.0.9 (GNU/Linux) - -mQGiBDqZbS4RBACH3vOrWo72lWh/lbECfIfGdtl+YDgyGMB2BiGDJG7Kzbg9IB2e -no0Du+omligWpgWlYdkiJ+/wpCJlBxd/P3rEegp822aeV1eD3E03wxWUvhyWgy+8 -I8POrcCjC9RkrTGTl5RiFdaRVCG93vzmJFUJoI1Kt0F5AnTJXJm4VgNo0wCg4F/M -jN7YfhrUroE8ksTGPiCeNocD/R6wGZ0FFtYHdK5W19u/vM9JfAXxoK+OmDheFSVL -oIWVCXacwvbVQ15MfdQxaRyZmkWD9jgm2Omr8II6iK12B3WLRb96bkQzC0Sd25Xm -2tLKUDBwK0meG/8cRj3hE4WFF6VBdhWNtRhbby6Le9JHC+ylMrHwMy+HHXl5a2gf -ycCmA/9LU5GukTKfaBz9OPrVkMf2n0RbdBgn5hxtDeZ5iV6JMosEGobMnZ77n44M -VdGk6NWlMZqmwy6tJg2CdKPiQtjJaPuIR6qM0rtc8tpnhJSqq2c3KNOcaTennJsc -H3MNtT6FeZH1pZOhcmLjs7wb267NgR89vBQd2l46qWYSaBCASbQWQm90YW4gRGlz -dHJpYnV0aW9uIEtleYhiBBMRAgAaBQsHCgMEAxUDAgMWAgECF4ACGQEFAkkXKWoA -EgdlR1BHAAEBCRCmPyy9+gL7zKhdAKCfZvYBJeZaVW+Cq8S463bbw9vtJACg29tp -zrPhPtU4baw3ngVFUjUcLCyJAhwEEAECAAYFAkkq4q8ACgkQXA+W6E7BbWuJmg/+ -NTxLCg0I527bNowv/pEBrN26Aghwu3/Gn6QrRz2bFQ1A/8LNw2w8eKY0w/b5ieiC -kYy/DmkcDFkspmtaVvA0A+hK/NIIEbFqllKnTQ2BK5EdqQxS+OuBZN4BbJJ2XzKD -6bUcmIEpzymVah/r49D09VG7TQeBequcER9DumSuKhDM10Jt594tkjUo8E7BO8Np -54T2MXX3Nk839eZLihnSh5Cnj6pmLlr/4Tx8iXQTuk2CKkOWxCXaE1CJlUnaXTTy -T16na7PdWPKUR1x2cNY9uL+r5RwSRebV2iV3620MzFHYIAbFYrRdew8HnBnzrwgE -gk4z8fFFSDwIkkGVIkZMqchyWQySJ8UIQpUPVM0/EA+ejgMbLx/Xt6ONIZQiq9Cc -8AaPsoEXFlQHRFN65BB8GIYUdraw/yHwTWX4UNtyNNTq6zgwnsvik6ZJN7RNdgea -rZavW8svXsDZgwEVDI3ps19B1yD0AxC/IJ9uqxqTKn+dYciiZJCMBUTITb6lVs6b -SnMNqdllE2z591cQH02rInHH25WiMjoPeboUozLZ7tyWZtv7/CP4a+IcNqB7LmET -qNTWki3cAnLw5UfPVYrnunI5jHG2eFCjHk3cGAM/AcWRs+wqRfUAqzjs/rRUH8QD -n4vADnCuKHle3dRFq3Dy+fCZe/7yEmeAyJ8FbmSQRgOZAgsEQX8lLwEQALecnQ3J -k1iajTjKoUryWAs8orDTBxiOkYQuwD1g01Geu5XMcDx0ykqPPer1688QN2P/4Lc6 -zN4B0h3SNn8zmz9MI9afCaL3DPynogKX4/zPvSSAITiSytClKNbpSRoqjpdXeoUU -cW7gs8+d81bYJtgBtATtVHDZXzDO32wbPT1Zi+IdI+19R84tgWZBDgLYdQIaUa+G -+j14Gdubc4nFfP6h/UmWC7r6xo0TeQsNLUv2c9nyMeUUKeKZwBar0349sWKihjLf -ne9TXPgdEpg0C9fYAlxTOBa+hIbESVie/4BxtvSHk+wWFpRZtBkS43SDF5qZY0TX -uZJmt3YhiX/zlRut1nhLtqxzNVMIZtNZkD4MrMl7+mHManITkCMBS5NmpmXdlBES -Si+cPVMD91fEAuILczJj/VCUl1pn83kIlD9wxDNQcFdMzuicvFneEszW7UCdvPUC -3UcFQcsxAuYUEPr/H9Qraogm8/UE7+fTb8pTSt06KsZR3nMLLMKICcgLpraDQENZ -GCcK8js82FsB+6ccQ5WB1nMDfdDbYNyRKv/bgPmKxOw74jo24wSeio4zFHBzVXYQ -CLleO52H+w5jz4vEXhC3IEqoLhJHAIW41yl3pqx1qeZ0XwOfGP67nQzI+YhUn59+ -OBngAVQ8rdfWxopzVTI7oRlQafFbTyN/sReTAAYptC5KYWNrIExsb3lkIChTaWdu -aW5nIEtleSkgPGxsb3lkQHJhbmRvbWJpdC5uZXQ+iQIuBBMBAgAYAhsDAh4BAheA -BQJBgDp5AwsJAgQVAgMIAAoJEFwPluhOwW1roTQP+QFzRSVwJYzHUebr1nQSS65b -/9EeX3tSI8ZnKEMAIAYn3YvnYhZxKwdFvCWKZJXfPcaJqv+xWEvArsYEbj6n4AJw -73V27USLqvqNnBleeQluM1nm8AYvmukHXUDmTOCRhqL1rK70DKTRB3Q08sgnmuRF -8sMuG6TRPm8zk9N87zI8fYbT7hWxoO6E9wXPOr+4cYirmtbPY0Ni5bWvd/JrRzWa -2e/UVrpvoBE6kPaF6mxK8oDTGmRr+yKjEsxsTKYQJbguzDYtjEvjoDxScYfegk7n -5PdOGyhjDV/EjC/I7HcJNDVg72szmNLaNskoiHZaEiiTKD60gWFRwQJfNRYiZk0J -x1707wNZCzjKVkeD5U8x4uWchkWjXft0XdCYsKdZQ/GTepcIwz683wicdCVAMcUt -vy43i5DaPelOV22TqL6coLoelso1AURHAwfgBc/cqCsweUVotNA8SvsYMTaXuNMm -578Cs44AEXrWY0sLFCYEu6rA47HV7FXoaruK7Qjo/IopqsLd42g7HBR993tEl7j5 -3lK0VGHdFI0I4kw/tWSVXqH5vK12WLg0mc+21KGoLjkGSdPsKNUP2xhZaiK8fAB9 -2WonnGMAVUXwQ4Tu9gGzA4KzjZv5RLWvOnbRc8Vh1ppXXoSrlRkHJXT6wHfNDrvf -ZJuOruFauUJmw1CEQcKyiQEiBBABAgAMBQJBugFKBQMAEnUAAAoJEJcQuJvKV618 -KrcIAJ0f1Js973k2ednThL7Fy1B68KZ/DOpbWqB8R53oJ/aaIU0TpXqKFN+amy1N -qrC2lLh7DebBJkan+UNJ6l/uj6cR0q+D1VeDjrFKgS9D7WwjXthik6Ph/nMnd9jz -TH7+8CxN3h0BAlaysxbM/gXjPYd/z05yYdtMayE/hnUhG1ysKrWdVzZv68qBesi+ -h0Z5b7IsfdlTtBi+0Y/wNDiOl8dg7UIkNjYveNgv02yR6InQEnAW6ESEiJ5/p4fi -CPtyTk3Hz8biM4I7oTKPNYhnpp7LxVMQbeWck3mb9Yjr2uqjNMiFuBHslmAZvtBn -hj55BU0GwM7ukMNkQLWICfftXGmIRgQTEQIABgUCQjkXLAAKCRBG+5XZXjRWKC0P -AKCHLrGe1Lz/4sxvKhROPiGFAEOPoACfRYNAzEZJ2iqeb6JxQuu3gxH3XVuZAQsE -QYPWPQEIAMfE8mQ9yMkT7gOWKzHaFVzQOPokjUxIuuQzxH7Zs6FVRJ96vE9PUQw+ -F+sB04dMCWjK9FOEnO2dmw0qp8svj0YZwEt0QYBU2SzWkbftN7N7kvHVci7MkWuj -MvayoHLkLqcekWB3W1wPrxFqHbCnS7ZxH2jBd/Uiop0R+6jrrX4xO/vBMHXiEpXv -mcHtk7rrvpIRlEgtgz7tEnAoAoSYQ8lzqER/3hVef15w3NpOUeBiSOHP11ss53eh -31e+5TD4sxHV3AGozFu9H3QyJeNt50MSRsCtxkH1g4Ai8Rf+ULeppbhcm3iLAdaX -9hVkR8Aty9DLB7YIOsfmE7v3jB30ykEABim0FkJvdGFuIERpc3RyaWJ1dGlvbiBL -ZXmJATQEEwECAB4FAkGD1j0CGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQYhHr -8e+637yzmAf/VTzFHTY/JoehmaXmoQflhDT2gvHCRi1cWv0g1nxPMLAgN44KHRQp -ckgO8edO6QYI9zTxwa+WQxt+WqX8qv8/MAKjhqsLIB/XBF2+FwW6RXcO9t7gwKDY -6ufUuN7Lju0CIZrXYVUqSdwLzwG6MiTc170aYranq1riRtmtRwhubvIMRo3bkxZX -RPWHpm535h7Cfos7AKj+kq/Q3IlBhnmuSLS2H05rceLQ37VHi/xJOqqRZiJndSPy -gP3uKII1fOaLu74YKGSerXeWtCzzA5XzCZRov0z74CnTRKwT5u5hf4zp9doMi+DV -sjtXTqXDHM8snA2tvPASNW67uK+v7WnZmYkCHAQTAQIABgUCQYPWUgAKCRBcD5bo -TsFta+r9EACWVis7YcaGkKKgRB/5ox8rM36XVhMXdh/hnnGHt5rapbbRRkRHRcWU -8WIcFO1A59+TfwNNd8gN1MEt/5aX5KHWVKHBDexJgIxm6Dm1pisYHf/dnYQPM18h -mqqwNlKY97hFkPpHd7enrtc/SvGbQhhLXYlpwBrdMl76e9xJLnnrRQksxegGPo8c -r+C9HTs1Lwa8zzBxyBwYBYX+0moDkDShEhuXx6mEOXrGvQanJuIvpoIwGH+62E65 -MbJGlwWpw/MAtm2jFhBIhGV0bqJCFp9zIgdNgfskBaPr0oilbuJQZqP0Iqe/6CCt -4XkS51yWZqxjLAFpEpvDec4PGw3witKf/koGon9X8C035+nEjLBrWy18Q91vw2US -yLI+mm9diMAS8pY2gomfxBO2VwYHJryZykjCYQkccRA1tHteRj4gqTObo0Ak47y5 -MnplTWwi40oP7K2cfhCRBmMioxmYES4xsHEupfRBo3xr1Jq9q0t688WTT1NXHPMP -oueF9mKZCf2pa9aHsqBmWTm3sCaNQKGubCDBEUmJUyndmSatJyYM7NVYoUp6EfqM -ACFuTNdBsjKMh7aWVikQpbJDfA1BIU3lZeqgjgrghVAWkEOBfhG0IVZj+RVCJpsq -oTJ8asY2VreArSCyr/VnLEnfuH/QpgvCiCbepo3E34DJt4SaAOO2Zg== -=QyrG ------END PGP PUBLIC KEY BLOCK----- diff --git a/doc/pubkey.txt b/doc/pubkey.txt new file mode 100644 index 000000000..6ff016038 --- /dev/null +++ b/doc/pubkey.txt @@ -0,0 +1,541 @@ + +Public Key Cryptography +================================= + +Public key cryptography (also called assymmetric cryptography) is a collection +of techniques allowing for encryption, signatures, and key agreement. + +Key Objects +---------------------------------------- + +Public and private keys are represented by classes ``Public_Key`` and it's +subclass ``Private_Key``. The use of inheritence here means that a +``Private_Key`` can be converted into a reference to a public key. + +None of the functions on ``Public_Key`` and ``Private_Key`` itself are +particularly useful for users of the library, because 'bare' public key +operations are *very insecure*. The only purpose of these functions is to +provide a clean interface that higher level operations can be built on. So +really the only thing you need to know is that when a function takes a +reference to a ``Public_Key``, it can take any public key or private key, and +similiarly for ``Private_Key``. + +Types of ``Public_Key`` include ``RSA_PublicKey``, ``DSA_PublicKey``, +``ECDSA_PublicKey``, ``DH_PublicKey``, ``ECDH_PublicKey``, ``RW_PublicKey``, +``NR_PublicKey``,, and ``GOST_3410_PublicKey``. There are cooresponding +``Private_Key`` classes for each of these algorithms. + +.. _creating_new_private_keys: + +Creating New Private Keys +---------------------------------------- + +Creating a new private key requires two things: a source of random numbers +(see :ref:`random_number_generators`) and some algorithm specific parameters +that define the *security level* of the resulting key. For instance, the +security level of an RSA key is (at least in part) defined by the length of +the public key modulus in bits. So to create a new RSA private key, you would +call + +.. cpp:function:: RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, size_t bits) + + A constructor that creates a new random RSA private key with a modulus + of length *bits*. + +Algorithms based on the discrete-logarithm problem uses what is called a +*group*; a group can safely be used with many keys, and for some operations, +like key agreement, the two keys *must* use the same group. There are +currently two kinds of discrete logarithm groups supported in botan: the +integers modulo a prime, represented by :ref:`dl_group`, and elliptic curves +in GF(p), represented by :ref:`ec_group`. A rough generalization is that the +larger the group is, the more secure the algorithm is, but coorespondingly the +slower the operations will be. + +Given a ``DL_Group``, you can create new DSA, Diffie-Hellman, and +Nyberg-Rueppel key pairs with + +.. cpp:function:: DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + +.. cpp:function:: DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + +.. cpp:function:: NR_PrivateKey::NR_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + +.. cpp:function:: ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + + The optional *x* parameter to each of these contructors is a private key + value. This allows you to create keys where the private key is formed by + some special technique; for instance you can use the hash of a password (see + :ref:`pbkdf` for how to do that) as a private key value. Normally, you would + leave the value as zero, letting the class generate a new random key. + +Finally, given an ``EC_Group`` object, you can create a new ECDSA, +ECDH, or GOST 34.10-2001 private key with + +.. cpp:function:: ECDSA_PrivateKey::ECDSA_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. cpp:function:: ECDH_PrivateKey::ECDH_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. cpp:function:: GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + + +Generating RSA keys +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This example will 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), either encrypted or +unencrypted depending on if a password was given. + +.. literalinclude:: examples/rsa_kgen.cpp + +Generate DSA keys +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This example generates a 2048 bit DSA key + +.. literalinclude:: examples/dsa_kgen.cpp + + +.. _serializing_private_keys: + +Serializing Private Keys Using PKCS #8 +---------------------------------------- + +The standard format for serializing a private key is PKCS #8, the operations +for which are defined in ``pkcs8.h``. It supports both unencrypted and +encrypted storage. + +.. cpp:function:: SecureVector<byte> PKCS8::BER_encode(const Private_Key& key, \ + RandomNumberGenerator& rng, const std::string& password, const std::string& pbe_algo = "") + + Takes any private key object, serializes it, encrypts it using + *password*, and returns a binary structure representing the private + key. + + The final (optional) argument, *pbe_algo*, specifies a particular + password based encryption (or PBE) algorithm. If you don't specify a + PBE, a sensible default will be used. + +.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key, \ + RandomNumberGenerator& rng, const std::string& pass, const std::string& pbe_algo = "") + + This formats the key in the same manner as ``BER_encode``, but additionally + encodes it into a text format with identifying headers. Using PEM encoding + is *highly* recommended for many reasons, including compatibility with other + software, for transmission over 8-bit unclean channels, because it can be + identified by a human without special tools, and because it sometimes allows + more sane behavior of tools that process the data. + +Unencrypted serialization is also supported. + +.. warning:: + + In most situations, using unecrypted private key storage is a bad idea, + because anyone can come along and grab the private key without having to + know any passwords or other secrets. Unless you have very particular + security requirements, always use the versions that encrypt the key based on + a passphrase, described above. + +.. cpp:function:: SecureVector<byte> PKCS8::BER_encode(const Private_Key& key) + + Serializes the private key and returns the result. + +.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key) + + Serializes the private key, base64 encodes it, and returns the + result. + +Last but not least, there are some functions that will load (and +decrypt, if necessary) a PKCS #8 private key: + +.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, \ + RandomNumberGenerator& rng, const User_Interface& ui) + +.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, \ + RandomNumberGenerator& rng, std::string passphrase = "") + +.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, \ + RandomNumberGenerator& rng, const User_Interface& ui) + +.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, \ + RandomNumberGenerator& rng, const std::string& passphrase = "") + +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 taking a ``std::string`` attempt to decrypt using the password +given (if the key is encrypted; if it is not, the passphase value will be +ignored). If the passphrase does not decrypt the key, an exception will be +thrown. + +The ones taking a ``User_Interface`` provide a simple callback interface which +makes handling incorrect passphrases and such a bit simpler. A +``User_Interface`` has very little to do with talking to users; it's just a +way to glue together Botan and whatever user interface you happen to be using. + +.. note:: + + In a future version, it is likely that ``User_Interface`` will be + replaced by a simple callback using ``std::function``. + +To use ``User_Interface``, derive a subclass and implement: + +.. cpp:function:: std::string User_Interface::get_passphrase(const std::string& what, \ + const std::string& source, UI_Result& result) const + + The ``what`` argument specifies what the passphrase is needed for (for + example, PKCS #8 key loading passes ``what`` as "PKCS #8 private key"). This + lets you provide the user with some indication of *why* your application is + asking for a passphrase; feel free to pass the string through ``gettext(3)`` + or moral equivalent for i18n purposes. Similarly, ``source`` specifies where + the data in question came from, if available (for example, a file name). If + the source is not available for whatever reason, then ``source`` will be an + empty string; be sure to account for this possibility. + + The function returns the passphrase as the return value, and a status code + in ``result`` (either ``OK`` or ``CANCEL_ACTION``). If ``CANCEL_ACTION`` is + returned in ``result``, then the return value will be ignored, and the + caller will take whatever action is necessary (typically, throwing an + exception stating that the passphrase couldn't be determined). In the + specific case of PKCS #8 key decryption, a ``Decoding_Error`` exception will + be thrown; your UI should assume this can happen, and provide appropriate + error handling (such as putting up a dialog box informing the user of the + situation, and canceling the operation in progress). + +.. _serializing_public_keys: + +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 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As described in :ref:`creating_new_private_keys`, a discrete logarithm group +can be shared among many keys, even keys created by users who do not trust +each other. However, it is necessary to trust the entity who created the +group; that is why organization like NIST use algorithms which generate groups +in a deterministic way such that creating a bogus group would require breaking +some trusted cryptographic primitive like SHA-2. + +Instantiating a ``DL_Group`` simply requires calling + +.. cpp:function:: DL_Group::DL_Group(const std::string& name) + + The *name* parameter is a specially formatted string that consists of three + things, the type of the group ("modp" or "dsa"), the creator of the group, + and the size of the group in bits, all delimited by '/' characters. + + Currently all "modp" groups included in botan are ones defined by the + Internet Engineering Task Force, so the provider is "ietf", and the strings + look like "modp/ietf/N" where N can be any of 768, 1024, 1536, 2048, 3072, + 4096, 6144, or 8192. This group type is used for Diffie-Hellman and ElGamal + algorithms. + + The other type, "dsa" is used for DSA and Nyberg-Rueppel keys. They can + also be used with Diffie-Hellman and ElGamal, but this is less common. The + currently available groups are "dsa/jce/N" for N in 512, 768, or 1024, and + "dsa/botan/N" with N being 2048 or 3072. The "jce" groups are the standard + DSA groups used in the Java Cryptography Extensions, while the "botan" + groups were randomly generated using the FIPS 186-3 algorithm by the library + maintainers. + +You can generate a new random group using + +.. cpp:function:: DL_Group::DL_Group(RandomNumberGenerator& rng, \ + PrimeType type, size_t pbits, size_t qbits = 0) + + The *type* can be either ``Strong``, ``Prime_Subgroup``, or + ``DSA_Kosherizer``. *pbits* specifies the size of the prime in + bits. If the *type* is ``Prime_Subgroup`` or ``DSA_Kosherizer``, + then *qbits* specifies the size of the subgroup. + +You can serialize a ``DL_Group`` using + +.. cpp:function:: SecureVector<byte> DL_Group::DER_Encode(Format format) + +or + +.. cpp:function:: std::string DL_Group::PEM_encode(Format format) + +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_group: + +EC_Group +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An ``EC_Group`` 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 +--------------------------------- + +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 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. + +Encryption +--------------------------------- + +Safe public key encryption requires the use of a padding scheme which hides +the underlying mathematical properties of the algorithm. Additionally, they +will add randomness, so encrypting the same plaintext twice produces two +different ciphertexts. + +The primary interface for encryption is + +.. cpp:class:: PK_Encryptor + + .. cpp:function:: SecureVector<byte> encrypt( \ + const byte* in, size_t length, RandomNumberGenerator& rng) const + + .. cpp:function:: SecureVector<byte> encrypt( \ + const MemoryRegion<byte>& in, RandomNumberGenerator& rng) const + + These encrypt a message, returning the ciphertext. + + .. cpp:function:: size_t maximum_input_size() const + + Returns the maximum size of the message that can be processed, in + bytes. If you call :cpp:func:`PK_Encryptor::encrypt` with a value larger + than this the operation will fail with an exception. + +:cpp:class:`PK_Encryptor` is only an interface - to actually encrypt you have +to create an implementation, of which there are currently two available in the +library, :cpp:class:`PK_Encryptor_EME` and :cpp:class:`DLIES_Encryptor`. DLIES +is a standard method (from IEEE 1363) that uses a key agreement technique such +as DH or ECDH to perform message encryption. Normally, public key encryption +is done using algorithms which support it directly, such as RSA or ElGamal; +these use the EME class: + +.. cpp:class:: PK_Encryptor_EME + + .. cpp:function:: PK_Encryptor_EME(const Public_Key& key, std::string eme) + + With *key* being the key you want to encrypt messages to. The padding + method to use is specified in *eme*. + + The recommended values for *eme* is "EME1(SHA-1)" or "EME1(SHA-256)". If + you need compatability with protocols using the PKCS #1 v1.5 standard, + you can also use "EME-PKCS1-v1_5". + +.. cpp:class:: DLIES_Encryptor + + Available in the header ``dlies.h`` + + .. cpp:function:: DLIES_Encryptor(const PK_Key_Agreement_Key& key, \ + KDF* kdf, MessageAuthenticationCode* mac, size_t mac_key_len = 20) + + Where *kdf* is a key derivation function (see + :ref:`key_derivation_function`) and *mac* is a + MessageAuthenticationCode. + +The decryption classes are named ``PK_Decryptor``, ``PK_Decryptor_EME``, and +``DLIES_Decryptor``. They are created in the exact same way, except they take +the private key, and the processing function is named ``decrypt``. + + +Signatures +--------------------------------- + +Signature generation is performed using + +.. cpp:class:: PK_Signer + + .. cpp:function:: PK_Signer(const Private_Key& key, \ + const std::string& emsa, \ + Signature_Format format = IEEE_1363) + + Constructs a new signer object for the private key *key* using the + signature format *emsa*. The key must support signature operations. In + the current version of the library, this includes RSA, DSA, ECDSA, GOST + 34.10-2001, Nyberg-Rueppel, and Rabin-Williams. Other signature schemes + may be supported in the future. + + Currently available values for *emsa* include EMSA1, EMSA2, EMSA3, EMSA4, + and Raw. All of them, except Raw, take a parameter naming a message + digest function to hash the message with. The Raw encoding signs the + input directly; if the message is too big, the signing operation will + fail. Raw is not useful except in very specialized applications. Examples + are "EMSA1(SHA-1)" and "EMSA4(SHA-256)". + + For RSA, use EMSA4 (also called PSS) unless you need compatability with + software that uses the older PKCS #1 v1.5 standard, in which case use + EMSA3 (also called "EMSA-PKCS1-v1_5"). For DSA, ECDSA, GOST 34.10-2001, + and Nyberg-Rueppel, you should use EMSA1. + + The *format* defaults to ``IEEE_1363`` which is the only available + format for RSA. For DSA and ECDSA, you can also use + ``DER_SEQUENCE``, which will format the signature as an ASN.1 + SEQUENCE value. + + .. cpp:function:: void update(const byte* in, size_t length) + .. cpp:function:: void update(const MemoryRegion<byte>& in) + .. cpp:function:: void update(byte in) + + These add more data to be included in the signature + computation. Typically, the input will be provided directly to a + hash function. + + .. cpp:function:: SecureVector<byte> signature(RandomNumberGenerator& rng) + + Creates the signature and returns it + + .. cpp:function:: SecureVector<byte> sign_message( \ + const byte* in, size_t length, RandomNumberGenerator& rng) + + .. cpp:function:: SecureVector<byte> sign_message( \ + const MemoryRegion<byte>& in, RandomNumberGenerator& rng) + + These functions are equivalent to calling + :cpp:func:`PK_Signer::update` and then + :cpp:func:`PK_Signer::signature`. Any data previously provided + using ``update`` will be included. + +Signatures are verified using + +.. cpp:class:: PK_Verifier + + .. cpp:function:: PK_Verifier(const Public_Key& pub_key, \ + const std::string& emsa, Signature_Format format = IEEE_1363) + + Construct a new verifier for signatures assicated with public + key *pub_key*. The *emsa* and *format* should be the same as + that used by the signer. + + .. cpp:function:: void update(const byte* in, size_t length) + .. cpp:function:: void update(const MemoryRegion<byte>& in) + .. cpp:function:: void update(byte in) + + Add further message data that is purportedly assocated with the + signature that will be checked. + + .. cpp:function:: bool check_signature(const byte* sig, size_t length) + .. cpp:function:: bool check_signature(const MemoryRegion<byte>& sig) + + Check to see if *sig* is a valid signature for the message data + that was written in. Return true if so. This function clears the + internal message state, so after this call you can call + :cpp:func:`PK_Verifier::update` to start verifying another + message. + + .. cpp:function:: bool verify_message(const byte* msg, size_t msg_length, \ + const byte* sig, size_t sig_length) + + .. cpp:function:: bool verify_message(const MemoryRegion<byte>& msg, \ + const MemoryRegion<byte>& sig) + + These are equivalent to calling :cpp:func:`PK_Verifier::update` + on *msg* and then calling :cpp:func:`PK_Verifier::check_signature` + on *sig*. + +Here is an example of DSA signature generation + +.. literalinclude:: examples/dsa_sign.cpp + +Here is an example that verifies DSA signatures + +.. literalinclude:: examples/dsa_ver.cpp + +Key Agreement +--------------------------------- + +You can get a hold of a ``PK_Key_Agreement_Scheme`` object by calling +``get_pk_kas`` with a key that is of a type that supports key +agreement (such as a Diffie-Hellman key stored in a ``DH_PrivateKey`` +object), and the name of a key derivation function. This can be "Raw", +meaning the output of the primitive itself is returned as the key, or +"KDF1(hash)" or "KDF2(hash)" where "hash" is any string you happen to +like (hopefully you like strings like "SHA-256" or "RIPEMD-160"), or +"X9.42-PRF(keywrap)", which uses the PRF specified in ANSI X9.42. It +takes the name or OID of the key wrap algorithm that will be used to +encrypt a content encryption key. + +How key agreement works is that you trade public values with some +other party, and then each of you runs a computation with the other's +value and your key (this should return the same result to both +parties). This computation can be called by using +``derive_key`` with either a byte array/length pair, or a +``SecureVector<byte>`` than holds the public value of the other +party. The last argument to either call is a number that specifies how +long a key you want. + +Depending on the KDF you're using, you *might not* get back a key +of the size you requested. In particular "Raw" will return a number +about the size of the Diffie-Hellman modulus, and KDF1 can only return +a key that is the same size as the output of the hash. KDF2, on the +other hand, will always give you a key exactly as long as you request, +regardless of the underlying hash used with it. The key returned is a +``SymmetricKey``, ready to pass to a block cipher, MAC, or other +symmetric algorithm. + +The public value that should be used can be obtained by calling +``public_data``, which exists for any key that is associated with a +key agreement algorithm. It returns a ``SecureVector<byte>``. + +"KDF2(SHA-256)" is by far the preferred algorithm for key derivation +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. + +An example of using Diffie-Hellman: + +.. literalinclude:: examples/dh.cpp diff --git a/doc/python.tex b/doc/python.tex deleted file mode 100644 index afdd66b6a..000000000 --- a/doc/python.tex +++ /dev/null @@ -1,68 +0,0 @@ -\documentclass{article} - -\setlength{\textwidth}{6.5in} % 1 inch side margins -\setlength{\textheight}{9in} % ~1 inch top and bottom margins - -\setlength{\headheight}{0in} -\setlength{\topmargin}{0in} -\setlength{\headsep}{0in} - -\setlength{\oddsidemargin}{0in} -\setlength{\evensidemargin}{0in} - -\title{\textbf{Botan Python Interface Documentation}} -\author{Jack Lloyd \\ - \texttt{[email protected]}} -\date{2009/10/10} - -\newcommand{\filename}[1]{\texttt{#1}} -\newcommand{\manpage}[2]{\texttt{#1}(#2)} - -\newcommand{\macro}[1]{\texttt{#1}} - -\newcommand{\function}[1]{\textbf{#1}} -\newcommand{\type}[1]{\texttt{#1}} -\renewcommand{\arg}[1]{\textsl{#1}} -\newcommand{\variable}[1]{\textsl{#1}} - -\begin{document} - -\maketitle - -\tableofcontents - -\parskip=5pt -\pagebreak - -\section{Ciphers} - -Botan's Python interface provides a generic interface to any cipher -supported by the library. The class \type{botan.Cipher} takes three -arguments, all strings: first, the name of the algorith, second the -direction (which can be either ``encrypt'' or ``decrypt''), and -lastly, the key to use. For instance - -\begin{verbatim} - encryptor = botan.Cipher("AES-128/EAX", "encrypt", key) -\end{verbatim} - -creates an object that will encrypt and authenticate messages using -the EAX mode of operation using the AES cipher. To use this object, -call the \function{cipher} function with two arguments - the input -to encrypt, and the IV to use: - -\begin{verbatim} - ciphertext = encryptor.cipher(input, salt) -\end{verbatim} - - -\subsection{Cryptobox} - - -\subsection{RNGs} - -\section{RSA} - - - -\end{document} diff --git a/doc/rng.txt b/doc/rng.txt new file mode 100644 index 000000000..66679271d --- /dev/null +++ b/doc/rng.txt @@ -0,0 +1,129 @@ +.. _random_number_generators: + +Random Number Generators +======================================== + +The random number generators provided in Botan are meant for creating +keys, IVs, padding, nonces, and anything else that requires 'random' +data. It is important to remember that the output of these classes +will vary, even if they are supplied with the same seed (ie, two +``Randpool`` objects with similar initial states will not produce the +same output, because the value of high resolution timers is added to +the state at various points). + +To create a random number generator, instantiate a ``AutoSeeded_RNG`` +object. This object will handle choosing the right algorithms from the +set of enabled ones and doing seeding using OS specific +routines. The main service a RandomNumberGenerator provides is, of +course, random numbers: + +.. cpp:function:: byte RandomNumberGenerator::random() + + Generates a single random byte and returns it + +.. cpp:function:: void RandomNumberGenerator::randomize(byte* data, size_t length) + + Places *length* bytes into the array pointed to by *data* + +To ensure good quality output, a PRNG needs to be seeded with truly +random data. Normally this is done for you. However it may happen that +your application has access to data that is potentially unpredictable +to an attacker. If so, use + +.. cpp:function:: void RandomNumberGenerator::add_entropy(const byte* data, \ + size_t length) + +which incorporates the data into the current randomness state. Don't +worry about filtering the data or doing any kind of cryptographic +preprocessing (such as hashing); the RNG objects in botan are designed +such that you can feed them any arbitrary non-random or even +maliciously chosen data - as long as at some point some of the seed +data was good the output will be secure. + + +Implementation Notes +---------------------------------------- + +Randpool +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``Randpool`` is the primary PRNG within Botan. In recent versions all +uses of it have been wrapped by an implementation of the X9.31 PRNG +(see below). If for some reason you should have cause to create a PRNG +instead of using the "global" one owned by the library, it would be +wise to consider the same on the grounds of general caution; while +``Randpool`` is designed with known attacks and PRNG weaknesses in +mind, it is not an standard/official PRNG. The remainder of this +section is a (fairly technical, though high-level) description of the +algorithms used in this PRNG. Unless you have a specific interest in +this subject, the rest of this section might prove somewhat +uninteresting. + +``Randpool`` has an internal state called pool, which is 512 bytes +long. This is where entropy is mixed into and extracted from. There is also a +small output buffer (called buffer), which holds the data which has already +been generated but has just not been output yet. + +It is based around a MAC and a block cipher (which are currently +HMAC(SHA-256) and AES-256). Where a specific size is mentioned, it +should be taken as a multiple of the cipher's block size. For example, +if a 256-bit block cipher were used instead of AES, all the sizes +internally would double. Every time some new output is needed, we +compute the MAC of a counter and a high resolution timer. The +resulting MAC is XORed into the output buffer (wrapping as needed), +and the output buffer is then encrypted with AES, producing 16 bytes +of output. + +After 8 blocks (or 128 bytes) have been produced, we mix the pool. To +do this, we first rekey both the MAC and the cipher; the new MAC key +is the MAC of the current pool under the old MAC key, while the new +cipher key is the MAC of the current pool under the just-chosen MAC +key. We then encrypt the entire pool in CBC mode, using the current +(unused) output buffer as the IV. We then generate a new output +buffer, using the mechanism described in the previous paragraph. + +To add randomness to the PRNG, we compute the MAC of the input and XOR +the output into the start of the pool. Then we remix the pool and +produce a new output buffer. The initial MAC operation should make it +very hard for chosen inputs to harm the security of ``Randpool``, and +as HMAC should be able to hold roughly 256 bits of state, it is +unlikely that we are wasting much input entropy (or, if we are, it +doesn't matter, because we have a very abundant supply). + +ANSI X9.31 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``ANSI_X931_PRNG`` is the standard issue X9.31 Appendix A.2.4 PRNG, +though using AES-256 instead of 3DES as the block cipher. This PRNG +implementation has been checked against official X9.31 test vectors. + +Internally, the PRNG holds a pointer to another PRNG (typically +Randpool). This internal PRNG generates the key and seed used by the +X9.31 algorithm, as well as the date/time vectors. Each time an X9.31 +PRNG object receives entropy, it passes it along to the PRNG it is +holding, and then pulls out some random bits to generate a new key and +seed. This PRNG considers itself seeded as soon as the internal PRNG +is seeded. + + +Entropy Sources +--------------------------------- + +An ``EntropySource`` is an abstract representation of some method of +gather "real" entropy. This tends to be very system dependent. The +*only* way you should use an ``EntropySource`` is to pass it to a PRNG +that will extract entropy from it -- never use the output directly for +any kind of key or nonce generation! + +``EntropySource`` has a pair of functions for getting entropy from +some external source, called ``fast_poll`` and ``slow_poll``. These +pass a buffer of bytes to be written; the functions then return how +many bytes of entropy were gathered. + +Note for writers of ``EntropySource`` subclasses: it isn't necessary +to use any kind of cryptographic hash on your output. The data +produced by an EntropySource is only used by an application after it +has been hashed by the ``RandomNumberGenerator`` that asked for the +entropy, thus any hashing you do will be wasteful of both CPU cycles +and entropy. + diff --git a/doc/scripts/comba.py b/doc/scripts/comba.py deleted file mode 100755 index ce3cfed77..000000000 --- a/doc/scripts/comba.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python - -import sys - -def comba_indexes(N): - - indexes = [] - - for i in xrange(0, 2*N): - x = [] - - for j in xrange(max(0, i-N+1), min(N, i+1)): - x += [(j,i-j)] - indexes += [sorted(x)] - - return indexes - -def comba_sqr_indexes(N): - - indexes = [] - - for i in xrange(0, 2*N): - x = [] - - for j in xrange(max(0, i-N+1), min(N, i+1)): - if j < i-j: - x += [(j,i-j)] - else: - x += [(i-j,j)] - indexes += [sorted(x)] - - return indexes - -def comba_multiply_code(N): - indexes = comba_indexes(N) - - for (i,idx) in zip(range(0, len(indexes)), indexes): - for pair in idx: - print "word3_muladd(&w2, &w1, &w0, x[%2d], y[%2d]);" % (pair) - print "z[%2d] = w0; w0 = w1; w1 = w2; w2 = 0;" % (i) - -def comba_square_code(N): - indexes = comba_sqr_indexes(N) - - for (rnd,idx) in zip(range(0, len(indexes)), indexes): - for (i,pair) in zip(range(0, len(idx)), idx): - if pair[0] == pair[1]: - print " word3_muladd(&w2, &w1, &w0, x[%2d], x[%2d]);" % (pair) - elif i % 2 == 0: - print " word3_muladd_2(&w2, &w1, &w0, x[%2d], x[%2d]);" % (pair[0], pair[1]) - if rnd < len(idx)-2: - print " z[%2d] = w0; w0 = w1; w1 = w2; w2 = 0;\n" % (rnd) - elif rnd == len(idx)-1: - print " z[%2d] = w0;\n" % (rnd) - else: - print " z[%2d] = w1;\n" % (rnd) - -def main(args = None): - if args is None: - args = sys.argv - #comba_square_code(int(args[1])) - comba_multiply_code(int(args[1])) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/doc/scripts/combine_bmarks.pl b/doc/scripts/combine_bmarks.pl deleted file mode 100755 index b6436496e..000000000 --- a/doc/scripts/combine_bmarks.pl +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/perl -w - -use strict; - -my %results; -my %pk; - -my %pk_algos; -my %algos; - -my %filename_to_desc; - -for my $filename (@ARGV) { - - open IN, "<$filename" or die "Couldn't read $filename ($!)\n"; - - my $desc = <IN>; - chomp $desc; - - $results{$desc} = {}; - - while(<IN>) { - if(/(.*): +(.*) Mbytes\/sec/) { - $results{$desc}{$1} = $2; - $algos{$1} = undef; - } - if(/(.*): (.*) ops \/ second \((.*)\)/) { - my $alg = "$1"; - $alg = "$alg $3" if defined($3); - $pk{$desc}{$alg} = $2; - $pk_algos{$alg} = undef; - } - } -} - - -sub print_table { - my @columns = sort keys %results; - - print "\n<P>All results are in MiB / second:\n"; - print "<TABLE BORDER CELLSPACING=1>\n<THEAD>\n"; - - my %col_index = (); - - my $line = "<TR><TH>Algorithm "; - - foreach my $col (@columns) { - $col_index{$col} = length($line); - $line .= "<TH>" . $col . " "; - } - - $line .= "\n<TBODY>\n"; - - print $line; - - $line = ''; - - foreach my $algo (sort keys %algos) { - $line = " <TR><TH>$algo "; - - for my $col (@columns) { - my $result = $results{$col}{$algo}; - $result = "-" if not defined($result); - - $result = "<TH>$result"; - - $line .= ' ' while(length($line) < ($col_index{$col})); - $line .= $result; - - } - - print $line, "\n"; - $line = ''; - } - - print "</TABLE>\n"; -} - - -sub print_pk_table { - my @columns = sort keys %pk; - - print "\n<P>All results are in operations per second:\n"; - print "<TABLE BORDER CELLSPACING=1>\n<THEAD>\n"; - - my %col_index = (); - - my $line = "<TR><TH>Algorithm "; - - foreach my $col (@columns) { - $col_index{$col} = length($line); - $line .= "<TH>" . $col . " "; - } - - $line .= "\n<TBODY>\n"; - - print $line; - - foreach my $algo (sort keys %pk_algos) { - my $line = " <TR><TH>$algo "; - - for my $col (@columns) { - my $result = $pk{$col}{$algo}; - $result = '-' if not defined($result); - - $result = "<TH>$result"; - - $line .= ' ' while(length($line) < ($col_index{$col})); - $line .= $result; - - } - - print $line, "\n"; - } - - print "</TABLE>\n"; -} - -print_table(); -print_pk_table(); diff --git a/doc/scripts/dist.sh b/doc/scripts/dist.sh deleted file mode 100755 index 479de24d1..000000000 --- a/doc/scripts/dist.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash - -# This is probably only useful if run on my machine, which is not -# exactly ideal - -SELECTOR=h:net.randombit.botan -KEY_ID=EFBADFBC -MTN_DB=/storage/mtn/botan.mtn -DIST_DIR=~/Botan-dist - -DIST_FILES_DIR=$HOME/projects/www/files/botan/v1.9/ -WEB_DOCS_DIR=$HOME/projects/www/htdocs/botan/htdocs/ - -# You shouldn't have to change anything after this -mkdir -p $DIST_DIR -cd $DIST_DIR - -mtn -d $MTN_DB checkout -r $SELECTOR Botan - -VERSION=$(Botan/configure.py --version) - -mv Botan Botan-$VERSION - -cd Botan-$VERSION -rm -rf _MTN -rm -f .mtn-ignore - -# Build docs -cd doc - -for doc in api tutorial building python -do - latex $doc.tex - latex $doc.tex - dvips $doc.dvi -o - pdflatex $doc.tex - pdflatex $doc.tex - cp $doc.pdf $DIST_DIR - mv $doc.ps $DIST_DIR - # Clean up after TeX - rm -f $doc.aux $doc.log $doc.dvi $doc.toc -done - -botan_log_to_html log.txt > ../../log.html - -cd .. # topdir -cd .. # now in DIST_DIR - -tar -cf Botan-$VERSION.tar Botan-$VERSION - -bzip2 -9 -k Botan-$VERSION.tar -gzip -9 Botan-$VERSION.tar - -rm -rf Botan-$VERSION - -mv Botan-$VERSION.tar.gz Botan-$VERSION.tgz -mv Botan-$VERSION.tar.bz2 Botan-$VERSION.tbz - -echo "*****************************************************" -read -a PASSWORD -p "Enter PGP password (or ^C to skip signatures): " - -echo $PASSWORD | gpg --batch --armor -b --passphrase-fd 0 -u $KEY_ID Botan-$VERSION.tgz -echo $PASSWORD | gpg --batch --armor -b --passphrase-fd 0 -u $KEY_ID Botan-$VERSION.tbz - -mv Botan-$VERSION.tgz* Botan-$VERSION.tbz* $DIST_FILES_DIR -mv log.html $WEB_DOCS_DIR - -echo "Now edit download.html, and add a release notice to pyblosxom" diff --git a/doc/scripts/print_deps.py b/doc/scripts/print_deps.py deleted file mode 100755 index c68fa2617..000000000 --- a/doc/scripts/print_deps.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/python - -""" -Analyze the botan source tree and print the module interdependencies - -(C) 2009 Jack Lloyd -Distributed under the terms of the Botan license -""" - -import os -import os.path -import sys -import re - -def find_deps_in(filename): - # By convention #include's with spaces before them are - # always wrapped in #ifdef blocks - regexp = re.compile('^#include <botan/(.*)>') - - for line in open(filename).readlines(): - match = regexp.match(line) - if match != None: - yield match.group(1).replace('internal/', '') - -def get_dependencies(dirname): - all_dirdeps = {} - file_homes = {} - - is_sourcefile = re.compile('\.(cpp|h|S)$') - - for (dirpath, dirnames, filenames) in os.walk('src'): - dirdeps = set() - for filename in filenames: - if is_sourcefile.search(filename) != None: - file_homes[filename] = os.path.basename(dirpath) - - for dep in find_deps_in(os.path.join(dirpath, filename)): - if dep not in filenames and dep != 'build.h': - dirdeps.add(dep) - - dirdeps = sorted(dirdeps) - if dirdeps != []: - all_dirdeps[dirpath] = dirdeps - - return (all_dirdeps, file_homes) - -def main(): - (all_dirdeps, file_homes) = get_dependencies('src') - - def interesting_dep_for(dirname): - def interesting_dep(dep): - if dep == 'utils': - return False # everything depends on it - - # block/serpent depends on block, etc - if dirname.find('/%s/' % (dep)) > 0: - return False - return True - return interesting_dep - - for dirname in sorted(all_dirdeps.keys()): - depdirs = sorted(set(map(lambda x: file_homes[x], all_dirdeps[dirname]))) - - depdirs = filter(interesting_dep_for(dirname), depdirs) - - if depdirs != []: - print "%s: %s" % (dirname, ' '.join(depdirs)) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/doc/scripts/update_deps.py b/doc/scripts/update_deps.py deleted file mode 100755 index ac19885e0..000000000 --- a/doc/scripts/update_deps.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/python - -import sys -import re -import os.path - -def update_requires(dir, deps): - lines = map(lambda x: x.strip(), - open(os.path.join(dir, 'info.txt')).readlines()) - - if '<requires>' in lines: - start = lines.index('<requires>') - - while lines.pop(start) != '</requires>': - pass - - while len(lines) > 0 and lines[-1] == '': - lines = lines[:-1] - - if len(deps) > 0: - lines.append('') - lines.append('<requires>') - for dep in deps: - lines.append(dep) - lines.append('</requires>') - lines.append('') - - lines = "\n".join(lines).replace("\n\n\n", "\n\n") - - output = open(os.path.join(dir, 'info.txt'), 'w') - output.write(lines) - output.close() - -def main(): - for line in sys.stdin.readlines(): - (dirname, deps) = line.split(':') - deps = deps.strip().split(' ') - update_requires(dirname, deps) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/doc/secmem.txt b/doc/secmem.txt new file mode 100644 index 000000000..eba3462de --- /dev/null +++ b/doc/secmem.txt @@ -0,0 +1,81 @@ + +Secure Memory Containers +======================================== + +A major concern with mixing modern multiuser OSes and cryptographic +code is that at any time the code (including secret keys) could be +swapped to disk, where it can later be read by an attacker. Botan +stores almost everything (and especially anything sensitive) in memory +buffers that a) clear out their contents when their destructors are +called, and b) have easy plugins for various memory locking functions, +such as the ``mlock`` call on many Unix systems. + +Two of the allocation method used ("malloc" and "mmap") don't +require any extra privileges on Unix, but locking memory does. At +startup, each allocator type will attempt to allocate a few blocks +(typically totaling 128k), so if you want, you can run your +application ``setuid`` ``root``, and then drop privileges +immediately after creating your ``LibraryInitializer``. If you end +up using more than what's been allocated, some of your sensitive data +might end up being swappable, but that beats running as ``root`` +all the time. + +These classes should also be used within your own code for storing +sensitive data. They are only meant for primitive data types (int, +long, etc): if you want a container of higher level Botan objects, you +can just use a ``std::vector``, since these objects know how to clear +themselves when they are destroyed. You cannot, however, have a +``std::vector`` (or any other container) of ``Pipe`` objects or +filters, because these types have pointers to other filters, and +implementing copy constructors for these types would be both hard and +quite expensive (vectors of pointers to such objects is fine, though). + +These types are not described in any great detail: for more information, +consult the definitive sources~--~the header files ``secmem.h`` and +``allocate.h``. + +``SecureBuffer`` is a simple array type, whose size is specified at +compile time. It will automatically convert to a pointer of the +appropriate type, and has a number of useful functions, including +``clear()``, and ``size_t`` ``size()``, which returns the length of +the array. It is a template that takes as parameters a type, and a +constant integer which is how long the array is (for example: +``SecureBuffer<byte, 8> key;``). + +``SecureVector`` is a variable length array. Its size can be increased +or decreased as need be, and it has a wide variety of functions useful +for copying data into its buffer. Like ``SecureBuffer``, it implements +``clear`` and ``size``. + +Allocators +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The containers described above get their memory from allocators. As a +user of the library, you can add new allocator methods at run time for +containers, including the ones used internally by the library, to +use. The interface to this is in ``allocate.h``. Code needing to +allocate or deallocate memory calls ``get_allocator``, which returns a +pointer to an allocator object. This pointer should not be freed: the +caller does not own the allocator (it is shared among multiple +allocatore users, and uses a mutex to serialize access internally if +necessary). It is possible to call ``get_allocator`` with a specific +name to request a particular type of allocator, otherwise, a default +allocator type is returned. + +At start time, the only allocator known is a ``Default_Allocator``, +which just allocates memory using ``malloc``, and zeroizes it when the +memory is released. It is known by the name "malloc". If you ask for +another type of allocator ("locking" and "mmap" are currently used), +and it is not available, some other allocator will be returned. + +You can add in a new allocator type using ``add_allocator_type``. This +function takes a string and a pointer to an allocator. The string gives this +allocator type a name to which it can be referred when one is requesting it +with ``get_allocator``. If an error occurs (such as the name being +already registered), this function returns false. It will return true if the +allocator was successfully registered. If you ask it to, +``LibraryInitializer`` will do this for you. + +Finally, you can set the default allocator type that will be returned +using the policy setting "default_alloc" to the name of any previously +registered allocator. diff --git a/doc/ssl.txt b/doc/ssl.txt new file mode 100644 index 000000000..adca78bf8 --- /dev/null +++ b/doc/ssl.txt @@ -0,0 +1,58 @@ + +.. _ssl_api: + +SSL and TLS +======================================== + +.. versionadded:: 1.9.4 + +Botan supports both client and server implementations of the SSL/TLS +protocols, including SSL v3, TLS v1.0, and TLS v1.1. The insecure and +obsolete SSL v2 is not supported. + +The implementation uses ``std::tr1::function``, so it may not have +been compiled into the version you are using; you can test for the +feature macro ``BOTAN_HAS_SSL_TLS`` to check. + +TLS Clients +---------------------------------------- + +.. cpp:class:: TLS_Client + + .. cpp:function:: TLS_Client( \ + std::tr1::function<size_t (byte*, size_t)> input_fn, \ + std::tr1::function<void (const byte*, size_t)> output_fn, \ + const TLS_Policy& policy, RandomNumberGenerator& rng) + + Creates a TLS client. It will call *input_fn* to read bytes from + the network and call *output_fn* when bytes need to be written to + the network. + + .. cpp:function:: size_t read(byte* buf, size_t buf_len) + + Reads up to *buf_len* bytes from the open connection into *buf*, + returning the number of bytes actually written. + + .. cpp:function:: void write(const byte* buf, size_t buf_len) + + Writes *buf_len* bytes in *buf* to the remote side + + .. cpp:function:: void close() + + Closes the connection + + .. cpp:function:: std::vector<X509_Certificate> peer_cert_chain() + + Returns the certificate chain of the server + +A simple TLS client example: + +.. literalinclude:: examples/tls_client.cpp + + +TLS Servers +---------------------------------------- + +A simple TLS server + +.. literalinclude:: examples/tls_server.cpp diff --git a/doc/support.txt b/doc/support.txt new file mode 100644 index 000000000..288ed8aa0 --- /dev/null +++ b/doc/support.txt @@ -0,0 +1,19 @@ + +Commercial Support Options +======================================== + +Commercial support is currently available for Botan from a couple of +sources. If you provide services related to Botan, email the +development list and your information can be added here. + +* `FlexSecure GmbH <http://www.flexsecure.de>`_ offers support for + both Botan and `InSiTo <http://www.flexsecure.eu/insito/>`_ + libraries. Developers from FlexSecure have done extensive work + with Botan in the past, and many new features to Botan have been + implemented and contributed by them. More information at + http://www.flexsecure.eu/insito/support.html + +* `Jack Lloyd <http://www.randombit.net>`_ can provide services + relating to Botan including performance analysis of application + code using Botan, review of cryptographic use and designs for + security flaws, and implementing new features. diff --git a/doc/thanks.txt b/doc/thanks.txt deleted file mode 100644 index 68fd81b3b..000000000 --- a/doc/thanks.txt +++ /dev/null @@ -1,53 +0,0 @@ - -The following people (sorted alphabetically) contributed bug reports, useful -information, or were generally just helpful people to talk to: - -Jeff B -Rickard Bondesson -Mike Desjardins -Matthew Gregan -Hany Greiss -Friedemann Kleint -Ying-Chieh Liao -Dan Nicolaescu -Vaclav Ovsik -Ken Perano -Darren Starsmore -Kaushik Veeraraghavan -Dominik Vogt -James Widener - -Cerulean Studios, creators of the Trillian instant messaging client, -has provided financial assistance to the project. - -Barry Kavanagh of AEP Systems Ltd kindly provided an AEP2000 crypto card and -drivers, enabling the creation of Botan's AEP engine module. - -In addition, the following people have unknowingly contributed help -via public domain code which has been repurposed into the library: - - Dean Gaudet wrote the SSE2 implementation of SHA-1 - - Mike Hamburg wrote x86-64/SSSE3 assembly which was the basis for the - constant time AES implementation - - The implementation of DES is based off a public domain implementation by Phil - Karn from 1994 (he, in turn, credits Richard Outerbridge and Jim Gillogly). - - Rijndael and Square are based on the reference implementations written by - the inventors, Joan Daemen and Vincent Rijmen. - - The Serpent S-boxes used were discovered by Dag Arne Osvik and detailed in - his paper "Speeding Up Serpent". - - Matthew Skala's public domain twofish.c (as given in GnuPG 0.9.8) provided - the basis for my Twofish code (particularly the key schedule). - - Some of the hash functions (MD5, SHA-1, etc) use an optimized implementation - of one of the boolean functions, which was discovered by Colin Plumb. - - The design of Randpool takes some of its design principles from those - suggested by Eric A. Young in his SSLeay documentation, Peter Gutmann's paper - "Software Generation of Practically Strong Random Numbers", and the paper - "Cryptanalytic Attacks on Pseudorandom Number Generators", by Kelsey, - Schneier, Wagner, and Hall. diff --git a/doc/tutorial.tex b/doc/tutorial.tex deleted file mode 100644 index 840679d10..000000000 --- a/doc/tutorial.tex +++ /dev/null @@ -1,141 +0,0 @@ -\documentclass{article} - -\setlength{\textwidth}{6.5in} % 1 inch side margins -\setlength{\textheight}{9in} % ~1 inch top and bottom margins - -\setlength{\headheight}{0in} -\setlength{\topmargin}{0in} -\setlength{\headsep}{0in} - -\setlength{\oddsidemargin}{0in} -\setlength{\evensidemargin}{0in} - -\title{\textbf{Botan Tutorial}} -\author{Jack Lloyd \\ - \texttt{[email protected]}} -\date{2010/08/07} - -\newcommand{\filename}[1]{\texttt{#1}} -\newcommand{\manpage}[2]{\texttt{#1}(#2)} - -\newcommand{\macro}[1]{\texttt{#1}} - -\newcommand{\function}[1]{\textbf{#1}} -\newcommand{\type}[1]{\texttt{#1}} -\renewcommand{\arg}[1]{\textsl{#1}} -\newcommand{\variable}[1]{\textsl{#1}} - -\begin{document} - -\maketitle - -\tableofcontents - -\parskip=5pt -\pagebreak - -\section{Introduction} - -This document essentially sets up various simple scenarios and then -shows how to solve the problems using botan. It's fairly simple, and -doesn't cover many of the available APIs and algorithms, especially -the more obscure or unusual ones. It is a supplement to the API -documentation and the example applications, which are included in the -distribution. - -\section{Initializing the Library} - -The first step to using botan is to create a \type{LibraryInitializer} -object, which handles creating various internal structures, and also -destroying them at shutdown. - -\begin{verbatim} -#include <botan/botan.h> - -int main() - { - Botan::LibraryInitializer init; - return 0; - } -\end{verbatim} - -If your application is multi-threaded, you need to tell botan this so -that it will use locking where necessary. This is done by passing a -string to the constructor of \type{LibraryInitializer}: - -\begin{verbatim} - Botan::LibraryInitializer init("thread_safe=yes"); -\end{verbatim} - -\section{Introduction to Pipe} - -Most operations in botan are specified in terms of transformations on -streams. The class that handles the I/O and management for these -streams is called \type{Pipe}. You can construct a \type{Pipe} with -one or more \type{Filter}s, which sequentially process messages. You -can only update a single message at a time, but you can leave the -final output contents in a \type{Pipe} and read them out as desired. - -Here is how you might hex encode two messages: - -\begin{verbatim} - std::string message1 = "this is the first message"; - const byte message2[] = "a second message"; - Pipe pipe(new Hex_Encoder); - - pipe.start_msg(); // must be called before writing to the pipe - pipe.write(message1); - pipe.end_msg(); // must be called to signal completion - - /* - process_msg(x) is equivalent to calling - start_msg(); write(x); end_msg(); - */ - pipe.process_msg(message2); - - Pipe::message_id n = pipe.message_count(); // returns 2 - - /* you can read a message as a string, here we read message 0 */ - std::string first_result = pipe.read_all_as_string(0); - - /* or a piece at a time using array/length, now we'll read the - second message (message id 1) - */ - - byte output[4096] = { 0 }; - u32bit got = read(output, sizeof(output), 1); - if(got >= sizeof(output)) - // have to read again to get more of the message -\end{verbatim} - -You can also read output while the message is still active (before the -call to \function{end\_msg}), using the same interfaces. You can find -out how much data is currently available for a particular \type{Pipe} -by calling the member function \function{remaining}, which takes a -message sequence number and returns the number of bytes that are -currently available to read from that message. - -\section{Hashing a File} - -Hashing a file is done using a \type{Hash\_Filter}, which takes a string -which specifies which hash function you want to use: - -\begin{verbatim} - Pipe pipe(new Hash_Filter("SHA-256")); -\end{verbatim} - -The output of a \type{Hash\_Filter} is raw binary. The filter will not -produce any output at all until you call \function{end\_msg}. - -\section{Symmetric Cryptography} - - - -\subsection{Authentication} - -\subsection{User Authentication} - -\section{Public Key Cryptography} - - -\end{document} diff --git a/doc/users.txt b/doc/users.txt new file mode 100644 index 000000000..4c743b137 --- /dev/null +++ b/doc/users.txt @@ -0,0 +1,111 @@ + +Known Users +======================================== + +This is a list of some of the known users of botan. If you'd like to +be added to the list, email the development list. + +Open Source Software +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* `SoftHSM <http://trac.opendnssec.org/wiki/SoftHSM>`_ an open sourced + software PKCS #11 implementation, which is used as part of the + `OpenDNSSEC <http://www.opendnssec.org>`_ project. + +* `Qt Creator <http://qt.nokia.com/products/developer-tools>`_, an + IDE for building Qt applications. + +* `NetSieben's <http://netsieben.com/products/ssh/>`_ + SSH library provides SSHv2 client connections for C++ + applications, using botan for the crypto. (GPL or commercial) + +* `InSiTo <http://www.flexsecure.eu/insito/index.html>`_ is a library + for ePassports based on botan which was commissioned by the German + Federal Office for Information Security. + +* `QCA <http://delta.affinix.com/qca/>`_, the Qt Cryptographic + Architecture (part of KDE4) uses parts of botan as an `embedded + crypto provider + <http://websvn.kde.org/trunk/kdesupport/qca/src/botantools/botan/>`_. + +* `Octopod <http://code.google.com/p/octopod/>`_ is a + file sharing system. + +* `Silverlock <http://www.petroules.com/products/silverlock/>`_ + is a GPL password management tool for Windows, OS X, and Linux.</p> + +* `Monotone <http://monotone.ca/>`_, a free distributed + version control system, uses botan for RSA authentication, + content hashing, and message authentication. + +* `Publimark <http://www.gleguelv.org/soft/publimark/index.html>`_ + is a tool for hiding messages in an audio file. + +* `KeySafe <http://therning.org/magnus/computer/keysafe>`_, + a password application for GNOME + +* `SuSE <http://gcc.opensuse.org>`_ uses botan as part + of a test suite for the GCC optimizer. + +* `Openbench <http://www.exactcode.de/site/open_source/openbench/>`_, + an open source benchmark suite, uses botan as a component. + +* `VNCcrack <http://www.randombit.net/code/vnccrack/>`_ + is a password cracker for the VNC authentication/response protocol. + +Commercial Software +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* `Hulu Desktop <http://www.hulu.com/labs/hulu-desktop>`_ uses botan + on Windows `(ref) + <http://download.hulu.com/HuluDesktop_ThirdPartyLicenses.txt>`_. + +* `Hitman Pro <http://www.surfright.nl/en>`_ is a malware + scanner for Windows. + +* `Flying Lab Software <http://www.burningsea.com>`_, a Seattle based + game developer, uses botan as a part of their user authentication + process. + +* `CryptoTE <http://idlebox.net/2009/cryptote/>`_ is a text editor + with integrated strong cryptography. + +* `TextEgg <http://www.textegg.com/>`_ is an encrypted document editor. + +* `Seagate <http://www.seagate.com/www/en-us/support/downloads/>`_ + uses botan for the drive encryption in the Maxtor OneTouch III Mini + Edition hard drive. + +* `Aegeus Technology Ltd <http://www.aegeus-technology.com>`_ used + botan in a research implementation of SPKI. + +* `E.V.E. Paradox <http://www.entropicsoftware.com/eve/eve.html>`_, a + suite of games for Windows. + +Research Projects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* `A Unified Approach to Intra-Domain Security + <http://www.csiir.ornl.gov/shue/research/securecom09.pdf>`_ + describes a system by researches from Oak Ridge National Lab and + Indiana University that uses botan to secure ARP and DHCP. + +* `CLL: A Cryptographic Link Layer for Local Area Networks + <http://www.springerlink.com/content/c4681m76808l4621/>`_ describes + a network encryption system using botan. (One of the coauthors, Yves + Jerschow, also contributed a number of optimizations to the + library). + +* The system described in `Enabling Intrusion Detection in IPsec + Protected IPv6 Networks Through Secret-key Sharing + <http://www.stormingmedia.us/01/0151/A015134.pdf>`_ + +* `An experimental tamper detection system + <http://www.cis.udel.edu/~hiper/passages/papers/jochenMILCOM03.pdf>`_ + designed by researchers from the University of Delaware and the US + Army Research Laboratory. + +* A prototype implementation of a telephony signal security system, + described in `Prototyping and evaluation of TCAPsec + <http://www.cs.kau.se/cs/education/courses/davddiss/Uppsatser_2007/D2007-04.pdf>`_ + by Kang Chung and Mathilda Gustafsson. diff --git a/doc/x509.txt b/doc/x509.txt new file mode 100644 index 000000000..d31a84498 --- /dev/null +++ b/doc/x509.txt @@ -0,0 +1,527 @@ + +.. _x509_certificates: + +Certificate Handling +================================= + +A certificate is a binding between some identifying information +(called a *subject*) and a public key. This binding is asserted by a +signature on the certificate, which is placed there by some authority +(the *issuer*) that at least claims that it knows the subject named in +the certificate really "owns" the private key corresponding to the +public key in the certificate. + +The major certificate format in use today is X.509v3, designed by ISO +and further hacked on by dozens (hundreds?) of other organizations. + +When working with certificates, the main class to remember is +``X509_Certificate``. You can read an object of this type, but you can't create +one on the fly; a CA object is necessary for making a new certificate. So for +the most part, you only have to worry about reading them in, verifying the +signatures, and getting the bits of data in them (most commonly the public key, +and the information about the user of that key). An X.509v3 certificate can +contain a literally infinite number of items related to all kinds of +things. Botan doesn't support a lot of them, because nobody uses them and +they're an impossible mess to work with. This section only documents the most +commonly used ones of the ones that are supported; for the rest, read +``x509cert.h`` and ``asn1_obj.h`` (which has the definitions of various common +ASN.1 constructs used in X.509). + +So what's in an X.509 certificate? +----------------------------------- + +Obviously, you want to be able to get the public key. This is achieved by +calling the member function ``subject_public_key``, which will return a +``Public_Key``\*. As to what to do with this, read about ``load_key`` in +:ref:`serializing_public_keys`. In the general case, this could be any kind of +public key, though 99% of the time it will be an RSA key. However, +Diffie-Hellman, DSA, and ECDSA keys are also supported, so be careful about how +you treat this. It is also a wise idea to examine the value returned by +``constraints``, to see what uses the public key is approved for. + +The second major piece of information you'll want is the name/email/etc of the +person to whom this certificate is assigned. Here is where things get a little +nasty. X.509v3 has two (well, mostly just two...) different places where you +can stick information about the user: the *subject* field, and in an extension +called *subjectAlternativeName*. The *subject* field is supposed to only +included the following information: country, organization, an organizational +sub-unit name, and a so-called common name. The common name is usually the name +of the person, or it could be a title associated with a position of some sort +in the organization. It may also include fields for state/province and +locality. What a locality is, nobody knows, but it's usually given as a city +name. + +Botan doesn't currently support any of the Unicode variants used in ASN.1 +(UTF-8, UCS-2, and UCS-4), any of which could be used for the fields in the +DN. This could be problematic, particularly in Asia and other areas where +non-ASCII characters are needed for most names. The UTF-8 and UCS-2 string +types *are* accepted (in fact, UTF-8 is used when encoding much of the time), +but if any of the characters included in the string are not in ISO 8859-1 (ie 0 +... 255), an exception will get thrown. Currently the ``ASN1_String`` type +holds its data as ISO 8859-1 internally (regardless of local character set); +this would have to be changed to hold UCS-2 or UCS-4 in order to support +Unicode (also, many interfaces in the X.509 code would have to accept or return +a ``std::wstring`` instead of a ``std::string``). + +Like the distinguished names, subject alternative names can contain a lot of +things that Botan will flat out ignore (most of which you would likely never +want to use). However, there are three very useful pieces of information that +this extension might hold: an email address ([email protected]), a DNS name +(somehost.example.com), or a URI (http://www.example.com). + +So, how to get the information? Call ``subject_info`` with the name of the +piece of information you want, and it will return a ``std::string`` that is +either empty (signifying that the certificate doesn't have this information), +or has the information requested. There are several names for each possible +item, but the most easily readable ones are: "Name", "Country", "Organization", +"Organizational Unit", "Locality", "State", "RFC822", "URI", and "DNS". These +values are returned as a ``std::string``. + +You can also get information about the issuer of the certificate in the same +way, using ``issuer_info``. + +X.509v3 Extensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +X.509v3 specifies a large number of possible extensions. Botan supports some, +but by no means all of them. This section lists which ones are supported, and +notes areas where there may be problems with the handling. + + - Key Usage and Extended Key Usage: No problems known. + + - Basic Constraints: No problems known. The default for a v1/v2 certificate is + assume it's a CA if and only if the option "x509/default_to_ca" is set. A v3 + certificate is marked as a CA if (and only if) the basic constraints + extension is present and set for a CA cert. + + - Subject Alternative Names: Only the "rfc822Name", "dNSName", and + "uniformResourceIdentifier" fields will be stored; all others are + ignored. + + - Issuer Alternative Names: Same restrictions as the Subject + Alternative Names extension. New certificates generated by Botan + never include the issuer alternative name. + + - Authority Key Identifier: Only the version using KeyIdentifier is + supported. If the GeneralNames version is used and the extension is + critical, an exception is thrown. If both the KeyIdentifier and GeneralNames + versions are present, then the KeyIdentifier will be used, and the + GeneralNames ignored. + + - Subject Key Identifier: No problems known. + +Revocation Lists +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It will occasionally happen that a certificate must be revoked before its +expiration date. Examples of this happening include the private key being +compromised, or the user to which it has been assigned leaving an +organization. Certificate revocation lists are an answer to this problem +(though online certificate validation techniques are starting to become +somewhat more popular). Every once in a while the CA will release a new CRL, +listing all certificates that have been revoked. Also included is various +pieces of information like what time a particular certificate was revoked, and +for what reason. In most systems, it is wise to support some form of +certificate revocation, and CRLs handle this easily. + +For most users, processing a CRL is quite easy. All you have to do is call the +constructor, which will take a filename (or a ``DataSource&``). The CRLs +can either be in raw BER/DER, or in PEM format; the constructor will figure out +which format without any extra information. For example:: + + X509_CRL crl1("crl1.der"); + + DataSource_Stream in("crl2.pem"); + X509_CRL crl2(in); + +After that, pass the ``X509_CRL`` object to a ``X509_Store`` object +with + +.. cpp:function:: X509_Code X509_Store::add_crl(const X509_CRL& crl) + +and all future verifications will take into account the certificates +listed, assuming ``add_crl`` returns ``VERIFIED``. If it doesn't +return ``VERIFIED``, then the return value is an error code signifying +that the CRL could not be processed due to some problem (which could +be something like the issuing certificate could not being found, an +invalid signature, or the CRL having some format problem). For more +about the ``X509_Store`` API, read :ref:`x509_store`. + +Reading Certificates +--------------------------------- + +``X509_Certificate`` has two constructors, each of which takes a source of +data; a filename to read, and a ``DataSource&``:: + + X509_Certificate cert1("cert1.pem"); + + /* This file contains two certificates, concatenated */ + DataSource_Stream in("certs2_and_3.pem"); + + X509_Certificate cert2(in); // read the first cert + X509_Certificate cert3(in); // read the second cert + +.. _x509_store: + +Storing and Using Certificates +--------------------------------- + +If you read a certificate, you probably want to verify the signature on +it. However, consider that to do so, we may have to verify the signature on the +certificate that we used to verify the first certificate, and on and on until +we hit the top of the certificate tree somewhere. It would be a might huge pain +to have to handle all of that manually in every application, so there is +something that does it for you: ``X509_Store``. + +The basic operations are: put certificates and CRLs into it, search for +certificates, and attempt to verify certificates. That's about it. In the +future, there will be support for online retrieval of certificates and CRLs (eg +with the HTTP cert-store interface currently under consideration by PKIX). + +Adding Certificates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can add new certificates to a certificate store using any of these +functions: + +.. cpp:function:: void X509_Store::add_cert(const X509_Certificate& cert, \ + bool trusted = false) + +.. cpp:function:: void X509_Store::add_cert(DataSource& source) + +.. cpp:function:: void X509_Store::add_trusted_certs(DataSource& source) + +The versions that take a ``DataSource&`` will add all the certificates +that it can find in that source. + +All of them add the cert(s) to the store. The "trusted" certificates are the +ones that you are willing to trust for certification purposes. For example, say +your application is working with certificates that are owned by employees of +some company, and all of their certificates are signed by the company CA, whose +certificate is in turned signed by a commercial root CA. What you would then do +is include the certificate of the commercial CA with your application, and read +it in as a trusted certificate. From there, you could verify the company CA's +certificate, and then use that to verify the end user's certificates. Only +self-signed certificates may be considered trusted. + +Adding CRLs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. cpp:function:: X509_Code X509_Store::add_crl(const X509_CRL& crl) + +This will process the CRL and mark the revoked certificates. This will +also work if a revoked certificate is added to the store sometime +after the CRL is processed. The function can return an error code +(listed later), or will return ``VERIFIED`` if everything completed +successfully. + +Storing Certificates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can output a set of certificates by calling ``PEM_encode``, which +will return a ``std::string`` containing each of the certificates in +the store, PEM encoded and concatenated. This simple format can easily +be read by both Botan and other libraries/applications. + +Certificate Stores +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An object of type ``Certificate_Store`` is a generalized interface to an +external source for certificates (and CRLs). Examples of such a store would be +one that looked up the certificates in a SQL database, or by contacting a CGI +script running on a HTTP server. There are currently three mechanisms for +looking up a certificate, and one for retrieving CRLs. By default, most of +these mechanisms will return an empty ``std::vector`` of +``X509_Certificate``. This storage mechanism is *only* queried when doing +certificate validation: it allows you to distribute only the root key with an +application, and let some online method handle getting all the other +certificates that are needed to validate an end entity certificate. In +particular, the search routines will not attempt to access the external +database. + +The three certificate lookup methods are ``by_SKID`` (Subject Key Identifier), +``by_name`` (the CommonName DN entry), and ``by_email`` (stored in either the +distinguished name, or in a subjectAlternativeName extension). The name and +email versions take a ``std::string``, while the SKID version takes a +``SecureVector<byte>`` containing the subject key identifier in raw binary. You +can choose not to implement ``by_name`` or ``by_email``, but ``by_SKID`` is +mandatory to implement, and, currently, is the only version that is used by +``X509_Store``. + +Finally, there is a method for finding CRLs, called ``get_crls_for``, that +takes an ``X509_Certificate`` object, and returns a ``std::vector`` of +``X509_CRL``. While normally there will be only one CRL, the use of the vector +makes it easy to return no CRLs (eg, if the certificate store doesn't support +retrieving them), or return multiple ones (for example, if the certificate +store can't determine precisely which key was used to sign the +certificate). Implementing the function is optional, and by default will return +no CRLs. If it is available, it will be used by ``X509_CRL``. + +As for using such a store, you have to tell ``X509_Store`` about it +with + +.. cpp:function:: void X509_Store::add_new_certstore(Certificate_Store* new_store) + + The store object will be owned by (and deleted by) ``X509_Store``, + so make sure to allocate it with ``new``. + +Verifying Certificates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Verifying a certificate requires that we build up a chain of trust, starting +from the root (usually a commercial CA), down through some number of +intermediate CAs, and finally reaching the actual certificate in +question. Thus, to verify, we actually have to have all those certificates on +hand (or at the very least, know where we can get the ones we need). + +The class which handles both storing certificates, and verifying them, +is + +.. cpp:class:: X509_Store + +.. cpp:type:: Cert_Usage + + Can be any of: + * ``ANY`` (any usage is OK) + * ``CRL_SIGNING`` + * ``TLS_SERVER`` (for SSL/TLS server authentication) + * ``TLS_CLIENT`` (for SSL/TLS client authentication) + * ``CODE_SIGNING`` + * ``EMAIL_PROTECTION`` (usually this means S/MIME) + * ``TIME_STAMPING`` (in theory any time stamp application, + usually IETF PKIX's Time Stamp Protocol) + +.. cpp:function:: X509_Code validate_cert(const X509_Certificate& cert, \ + Cert_Usage usage = ANY) + + Return ``VERIFIED`` if the certificate can safely be considered + valid for the usage(s) described by *usage*, and an error code if + it is not. + +First, how does :cpp:class`X509_Store::validate_cert` know if a certificate is +valid? A certificate is valid if both of the following hold: a) the signature +in the certificate can be verified using the public key in the issuer's +certificate, and b) the issuer's certificate is a valid CA certificate. Note +that this definition is recursive. We get out of this by "bottoming out" when +we reach a certificate that we consider trusted. In general this will either be +a commercial root CA, or an organization or application specific CA. + +There are a few other restrictions (validity periods, key usage restrictions, +etc), but the above summarizes the major points of the validation algorithm. In +theory, Botan implements the certificate path validation algorithm given in RFC +2459, but in practice it does not (yet), because we don't support the X.509v3 +policy or name constraint extensions. + +The default ``ANY`` does not mean valid for any use, it means "is valid for +some usage". This is usually what you want; requiring that a random certificate +support a particular usage will likely result in a lot of failures, unless your +application is very careful to always issue certificates with the proper +extensions, and you never use certificates generated by other apps. + +Return values for ``validate_cert`` (and ``add_crl``) include: + +* VERIFIED: The certificate is valid for the specified use. +* INVALID_USAGE: The certificate cannot be used for the specified use. + +* CANNOT_ESTABLISH_TRUST: The root certificate was not marked as trusted. + +* CERT_CHAIN_TOO_LONG: The certificate chain exceeded the length + allowed by a basicConstraints extension. + +* SIGNATURE_ERROR: An invalid signature was found + +* POLICY_ERROR: Some problem with the certificate policies was found. + +* CERT_FORMAT_ERROR: Some format problem was found in a certificate. +* CERT_ISSUER_NOT_FOUND: The issuer of a certificate could not be found. +* CERT_NOT_YET_VALID: The certificate is not yet valid. +* CERT_HAS_EXPIRED: The certificate has expired. +* CERT_IS_REVOKED: The certificate has been revoked. +* CRL_FORMAT_ERROR: Some format problem was found in a CRL. +* CRL_ISSUER_NOT_FOUND: The issuer of a CRL could not be found. +* CRL_NOT_YET_VALID: The CRL is not yet valid. +* CRL_HAS_EXPIRED: The CRL has expired. +* CA_CERT_CANNOT_SIGN: The CA certificate found does not have an + contain a public key that allows signature verification. +* CA_CERT_NOT_FOR_CERT_ISSUER: The CA cert found is not allowed to + issue certificates. +* CA_CERT_NOT_FOR_CRL_ISSUER: The CA cert found is not allowed to + issue CRLs. +* UNKNOWN_X509_ERROR: Some other error occurred. + +Certificate Authorities +--------------------------------- + +Setting up a CA for X.509 certificates is perhaps the easiest thing to +do related to X.509. A CA is represented by the type ``X509_CA``, +which can be found in ``x509_ca.h``. A CA always needs its own +certificate, which can either be a self-signed certificate (see below +on how to create one) or one issued by another CA (see the section on +PKCS #10 requests). Creating a CA object is done by the following +constructor: + +.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \ + const Private_Key& key) + +The private key is the private key corresponding to the public key in the +CA's certificate. + +Requests for new certificates are supplied to a CA in the form on PKCS +#10 certificate requests (called a ``PKCS10_Request`` object in +Botan). These are decoded in a similar manner to +certificates/CRLs/etc. A request is vetted by humans (who somehow +verify that the name in the request corresponds to the name of the +entity who requested it), and then signed by a CA key, generating a +new certificate: + +.. cpp:function:: X509_Certificate \ + X509_CA::sign_request(const PKCS10_Request& req) const + +Here's an example: + +.. literalinclude examples/ca.cpp + +Generating CRLs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As mentioned previously, the ability to process CRLs is highly important in +many PKI systems. In fact, according to strict X.509 rules, you must not +validate any certificate if the appropriate CRLs are not available (though +hardly any systems are that strict). In any case, a CA should have a valid CRL +available at all times. + +Of course, you might be wondering what to do if no certificates have +been revoked. Never fear; empty CRLs, which revoke nothing at all, can +be issued. To generate a new, empty CRL, just call + +.. cpp:function:: X509_CRL X509_CA::new_crl(u32bit seconds_to_expiration = 0) + + This function will return a new, empty CRL. The + ``seconds_to_expiration`` parameter is the number of seconds before + the CRL expires. If it is set to the (default) value of zero, then a + reasonable default (currently 7 days) will be used. + +On the other hand, you may have issued a CRL before. In that case, you will +want to issue a new CRL that contains all previously revoked +certificates, along with any new ones. This is done by calling + +.. cpp:function:: X509_CRL X509_CA::update_crl(const X509_CRL& old_crl, \ + std::vector<CRL_Entry> new_revoked, size_t seconds_to_expiration = 0) + + Where ``X509_CRL`` is the last CRL this CA issued, and + ``new_revoked`` is a list of any newly revoked certificates. The + function returns a new ``X509_CRL`` to make available for + clients. + +The ``CRL_Entry`` type is a structure that contains, at a minimum, the serial +number of the revoked certificate. As serial numbers are never repeated, the +pairing of an issuer and a serial number (should) distinctly identify any +certificate. In this case, we represent the serial number as a +``SecureVector<byte>`` called ``serial``. There are two additional (optional) +values, an enumeration called ``CRL_Code`` that specifies the reason for +revocation (``reason``), and an object that represents the time that the +certificate became invalid (if this information is known). + +If you wish to remove an old entry from the CRL, insert a new entry for the +same cert, with a ``reason`` code of ``DELETE_CRL_ENTRY``. For example, if a +revoked certificate has expired 'normally', there is no reason to continue to +explicitly revoke it, since clients will reject the cert as expired in any +case. + +Self-Signed Certificates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generating a new self-signed certificate can often be useful, for example when +setting up a new root CA, or for use in email applications. The library +provides a utility function for this: + +.. cpp:function:: X509_Certificate create_self_signed_cert( \ + const X509_Cert_Options& opts, const Private_Key& key) + + Where *key* is the private key you wish to use (the public key, + used in the certificate itself, is extracted from the private key), + and *opts* is an structure that has various bits of information + that will be used in creating the certificate (this structure, and + its use, is discussed below). + +An example: + +.. literalinclude:: examples/self_sig.cpp + +Creating PKCS #10 Requests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Also in ``x509self.h``, there is a function for generating new PKCS #10 +certificate requests: + +.. cpp:function:: PKCS10_Request create_cert_req( \ + const X509_Cert_Options& opts, const Private_Key& key) + +This function acts quite similarly to +:cpp:func:`create_self_signed_cert`, except it instead returns a PKCS +#10 certificate request. After creating it, one would typically +transmit it to a CA, who signs it and returns a freshly minted X.509 +certificate. + +An example: + +.. literalinclude:: examples/pkcs10.cpp + +Certificate Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +What is this ``X509_Cert_Options`` thing we've been passing around? It's a +class representing a bunch of information that will end up being stored into +the certificate. This information comes in 3 major flavors: information about +the subject (CA or end-user), the validity period of the certificate, and +restrictions on the usage of the certificate. + +First and foremost is a number of ``std::string`` members, which contains +various bits of information about the user: ``common_name``, ``serial_number``, +``country``, ``organization``, ``org_unit``, ``locality``, ``state``, +``email``, ``dns_name``, and ``uri``. As many of these as possible should be +filled it (especially an email address), though the only required ones are +``common_name`` and ``country``. + +There is another value that is only useful when creating a PKCS #10 request, +which is called ``challenge``. This is a challenge password, which you can +later use to request certificate revocation (*if* the CA supports doing +revocations in this manner). + +Then there is the validity period; these are set with ``not_before`` and +``not_after``. Both of these functions also take a ``std::string``, which +specifies when the certificate should start being valid, and when it should +stop being valid. If you don't set the starting validity period, it will +automatically choose the current time. If you don't set the ending time, it +will choose the starting time plus a default time period. The arguments to +these functions specify the time in the following format: "2002/11/27 +1:50:14". The time is in 24-hour format, and the date is encoded as +year/month/day. The date must be specified, but you can omit the time or +trailing parts of it, for example "2002/11/27 1:50" or "2002/11/27". + +Lastly, you can set constraints on a key. The one you're mostly likely to want +to use is to create (or request) a CA certificate, which can be done by calling +the member function ``CA_key``. This should only be used when needed. + +Other constraints can be set by calling the member functions +``add_constraints`` and ``add_ex_constraints``. The first takes a +``Key_Constraints`` value, and replaces any previously set value. If no value +is set, then the certificate key is marked as being valid for any usage. You +can set it to any of the following (for more than one usage, OR them together): +``DIGITAL_SIGNATURE``, ``NON_REPUDIATION``, ``KEY_ENCIPHERMENT``, +``DATA_ENCIPHERMENT``, ``KEY_AGREEMENT``, ``KEY_CERT_SIGN``, ``CRL_SIGN``, +``ENCIPHER_ONLY``, ``DECIPHER_ONLY``. Many of these have quite special +semantics, so you should either consult the appropriate standards document +(such as RFC 3280), or just not call ``add_constraints``, in which case the +appropriate values will be chosen for you. + +The second function, ``add_ex_constraints``, allows you to specify an OID that +has some meaning with regards to restricting the key to particular usages. You +can, if you wish, specify any OID you like, but there is a set of standard ones +that other applications will be able to understand. These are the ones +specified by the PKIX standard, and are named "PKIX.ServerAuth" (for TLS server +authentication), "PKIX.ClientAuth" (for TLS client authentication), +"PKIX.CodeSigning", "PKIX.EmailProtection" (most likely for use with S/MIME), +"PKIX.IPsecUser", "PKIX.IPsecTunnel", "PKIX.IPsecEndSystem", and +"PKIX.TimeStamping". You can call "add_ex_constraints" any number of times - +each new OID will be added to the list to include in the certificate. diff --git a/readme.txt b/readme.txt index fde088312..ef6f2c77d 100644 --- a/readme.txt +++ b/readme.txt @@ -1,30 +1,15 @@ -Botan 1.9.15-dev, ????-??-?? +Botan 1.10.0, Not Yet Released http://botan.randombit.net/ Botan is a C++ class library for performing a wide variety of -cryptographic operations. +cryptographic operations. It is released under the 2 clause BSD +license; see doc/license.txt for the specifics. You can file bugs in +Bugzilla (http://bugs.randombit.net/) or by sending a report to the +botan-devel mailing list. More information about the mailing list is +at http://lists.randombit.net/mailman/listinfo/botan-devel/ -Botan is released under the FreeBSD license (see doc/license.txt for -the specifics). More information about the authors and contributors -can be found in doc/credits.txt and doc/thanks.txt. +You can find documentation online at http://botan.randombit.net/docs +and http://botan.randombit.net/doxygen. A set of example programs can +be found in the examples directory. -You can file bugs at http://bugs.randombit.net/ or by sending a report -to the botan-devel mailing list: - http://lists.randombit.net/mailman/listinfo/botan-devel/ - -In the doc directory, there should be a set of PDFs, including - building.pdf - build instructions - api.pdf - the API reference manual - tutorial.pdf - a set of simple examples and tutorials - -A set of example programs can be found in the doc/examples directory. -You can also find Doxygen generated documentation online at - http://botan.randombit.net/doxygen - -Check the project website for announcements and new releases. If -you'll be developing code using this library, consider joining the -mailing lists to keep up to date with changes. - -As always, feel free to contact me with any questions or comments. - - - Jack Lloyd ([email protected]) +Jack Lloyd ([email protected]) diff --git a/src/alloc/alloc_mmap/mmap_mem.cpp b/src/alloc/alloc_mmap/mmap_mem.cpp index 78177bcdd..e4b602764 100644 --- a/src/alloc/alloc_mmap/mmap_mem.cpp +++ b/src/alloc/alloc_mmap/mmap_mem.cpp @@ -85,20 +85,22 @@ void* MemoryMapping_Allocator::alloc_block(size_t n) if(file.get_fd() == -1) throw MemoryMapping_Failed("Could not create file"); - std::vector<byte> zeros(n); + std::vector<byte> zeros(4096); - ssize_t remaining = n; + size_t remaining = n; while(remaining) { - ssize_t wrote_here = ::write(file.get_fd(), - &zeros[0], - remaining); + const size_t write_try = std::min(zeros.size(), remaining); - if(wrote_here == -1 && errno != EINTR) + ssize_t wrote_got = ::write(file.get_fd(), + &zeros[0], + write_try); + + if(wrote_got == -1 && errno != EINTR) throw MemoryMapping_Failed("Could not write to file"); - remaining -= wrote_here; + remaining -= wrote_got; } #ifndef MAP_NOSYNC diff --git a/src/alloc/secmem.h b/src/alloc/secmem.h index b06be0d55..80e8e59aa 100644 --- a/src/alloc/secmem.h +++ b/src/alloc/secmem.h @@ -34,7 +34,6 @@ class MemoryRegion */ bool empty() const { return (used == 0); } -#if 1 /** * Get a pointer to the first element in the buffer. * @return pointer to the first element in the buffer @@ -46,12 +45,6 @@ class MemoryRegion * @return constant pointer to the first element in the buffer */ operator const T* () const { return buf; } -#else - - T& operator[](size_t n) { return buf[n]; } - const T& operator[](size_t n) const { return buf[n]; } - -#endif /** * Get a pointer to the first element in the buffer. diff --git a/src/asn1/alg_id.cpp b/src/asn1/alg_id.cpp index b48db3e50..665e42fb3 100644 --- a/src/asn1/alg_id.cpp +++ b/src/asn1/alg_id.cpp @@ -41,8 +41,12 @@ AlgorithmIdentifier::AlgorithmIdentifier(const OID& alg_id, const byte DER_NULL[] = { 0x05, 0x00 }; oid = alg_id; + if(option == USE_NULL_PARAM) - parameters += std::make_pair(DER_NULL, sizeof(DER_NULL)); + { + parameters += std::make_pair<const byte*, size_t>( + DER_NULL, sizeof(DER_NULL)); + } } /* @@ -54,8 +58,12 @@ AlgorithmIdentifier::AlgorithmIdentifier(const std::string& alg_id, const byte DER_NULL[] = { 0x05, 0x00 }; oid = OIDS::lookup(alg_id); + if(option == USE_NULL_PARAM) - parameters += std::make_pair(DER_NULL, sizeof(DER_NULL)); + { + parameters += std::make_pair<const byte*, size_t>( + DER_NULL, sizeof(DER_NULL)); + } } /* diff --git a/src/block/aes/aes.cpp b/src/block/aes/aes.cpp index 9fb12cd11..5f47762a8 100644 --- a/src/block/aes/aes.cpp +++ b/src/block/aes/aes.cpp @@ -2,6 +2,8 @@ * AES * (C) 1999-2010 Jack Lloyd * +* Based on the public domain reference implemenation +* * Distributed under the terms of the Botan license */ diff --git a/src/block/aes_intel/aes_intel.cpp b/src/block/aes_ni/aes_ni.cpp index a2e660f2c..3ee0e608c 100644 --- a/src/block/aes_intel/aes_intel.cpp +++ b/src/block/aes_ni/aes_ni.cpp @@ -1,11 +1,11 @@ /* -* AES using Intel's AES-NI instructions +* AES using AES-NI instructions * (C) 2009 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/aes_intel.h> +#include <botan/aes_ni.h> #include <botan/loadstor.h> #include <wmmintrin.h> @@ -103,7 +103,7 @@ __m128i aes_256_key_expansion(__m128i key, __m128i key2) /* * AES-128 Encryption */ -void AES_128_Intel::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_128_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = (const __m128i*)in; __m128i* out_mm = (__m128i*)out; @@ -179,7 +179,7 @@ void AES_128_Intel::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-128 Decryption */ -void AES_128_Intel::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_128_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = (const __m128i*)in; __m128i* out_mm = (__m128i*)out; @@ -255,7 +255,7 @@ void AES_128_Intel::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-128 Key Schedule */ -void AES_128_Intel::key_schedule(const byte key[], size_t) +void AES_128_NI::key_schedule(const byte key[], size_t) { #define AES_128_key_exp(K, RCON) \ aes_128_key_expansion(K, _mm_aeskeygenassist_si128(K, RCON)) @@ -304,7 +304,7 @@ void AES_128_Intel::key_schedule(const byte key[], size_t) /* * Clear memory of sensitive data */ -void AES_128_Intel::clear() +void AES_128_NI::clear() { zeroise(EK); zeroise(DK); @@ -313,7 +313,7 @@ void AES_128_Intel::clear() /* * AES-192 Encryption */ -void AES_192_Intel::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_192_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = (const __m128i*)in; __m128i* out_mm = (__m128i*)out; @@ -395,7 +395,7 @@ void AES_192_Intel::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-192 Decryption */ -void AES_192_Intel::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_192_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = (const __m128i*)in; __m128i* out_mm = (__m128i*)out; @@ -477,7 +477,7 @@ void AES_192_Intel::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-192 Key Schedule */ -void AES_192_Intel::key_schedule(const byte key[], size_t) +void AES_192_NI::key_schedule(const byte key[], size_t) { __m128i K0 = _mm_loadu_si128((const __m128i*)(key)); __m128i K1 = _mm_loadu_si128((const __m128i*)(key + 8)); @@ -520,7 +520,7 @@ void AES_192_Intel::key_schedule(const byte key[], size_t) /* * Clear memory of sensitive data */ -void AES_192_Intel::clear() +void AES_192_NI::clear() { zeroise(EK); zeroise(DK); @@ -529,7 +529,7 @@ void AES_192_Intel::clear() /* * AES-256 Encryption */ -void AES_256_Intel::encrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_256_NI::encrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = (const __m128i*)in; __m128i* out_mm = (__m128i*)out; @@ -617,7 +617,7 @@ void AES_256_Intel::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-256 Decryption */ -void AES_256_Intel::decrypt_n(const byte in[], byte out[], size_t blocks) const +void AES_256_NI::decrypt_n(const byte in[], byte out[], size_t blocks) const { const __m128i* in_mm = (const __m128i*)in; __m128i* out_mm = (__m128i*)out; @@ -705,7 +705,7 @@ void AES_256_Intel::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * AES-256 Key Schedule */ -void AES_256_Intel::key_schedule(const byte key[], size_t) +void AES_256_NI::key_schedule(const byte key[], size_t) { __m128i K0 = _mm_loadu_si128((const __m128i*)(key)); __m128i K1 = _mm_loadu_si128((const __m128i*)(key + 16)); @@ -770,7 +770,7 @@ void AES_256_Intel::key_schedule(const byte key[], size_t) /* * Clear memory of sensitive data */ -void AES_256_Intel::clear() +void AES_256_NI::clear() { zeroise(EK); zeroise(DK); diff --git a/src/block/aes_intel/aes_intel.h b/src/block/aes_ni/aes_ni.h index a8e6b53e8..ae9e5b3f4 100644 --- a/src/block/aes_intel/aes_intel.h +++ b/src/block/aes_ni/aes_ni.h @@ -1,12 +1,12 @@ /* -* AES using Intel's AES-NI instructions +* AES using AES-NI instructions * (C) 2009 Jack Lloyd * * Distributed under the terms of the Botan license */ -#ifndef BOTAN_AES_INTEL_H__ -#define BOTAN_AES_INTEL_H__ +#ifndef BOTAN_AES_NI_H__ +#define BOTAN_AES_NI_H__ #include <botan/block_cipher.h> @@ -15,7 +15,7 @@ namespace Botan { /** * AES-128 using AES-NI */ -class BOTAN_DLL AES_128_Intel : public Block_Cipher_Fixed_Params<16, 16> +class BOTAN_DLL AES_128_NI : public Block_Cipher_Fixed_Params<16, 16> { public: size_t parallelism() const { return 4; } @@ -25,9 +25,9 @@ class BOTAN_DLL AES_128_Intel : public Block_Cipher_Fixed_Params<16, 16> void clear(); std::string name() const { return "AES-128"; } - BlockCipher* clone() const { return new AES_128_Intel; } + BlockCipher* clone() const { return new AES_128_NI; } - AES_128_Intel() : EK(44), DK(44) { } + AES_128_NI() : EK(44), DK(44) { } private: void key_schedule(const byte[], size_t); @@ -37,7 +37,7 @@ class BOTAN_DLL AES_128_Intel : public Block_Cipher_Fixed_Params<16, 16> /** * AES-192 using AES-NI */ -class BOTAN_DLL AES_192_Intel : public Block_Cipher_Fixed_Params<16, 24> +class BOTAN_DLL AES_192_NI : public Block_Cipher_Fixed_Params<16, 24> { public: size_t parallelism() const { return 4; } @@ -47,9 +47,9 @@ class BOTAN_DLL AES_192_Intel : public Block_Cipher_Fixed_Params<16, 24> void clear(); std::string name() const { return "AES-192"; } - BlockCipher* clone() const { return new AES_192_Intel; } + BlockCipher* clone() const { return new AES_192_NI; } - AES_192_Intel() : EK(52), DK(52) { } + AES_192_NI() : EK(52), DK(52) { } private: void key_schedule(const byte[], size_t); @@ -59,7 +59,7 @@ class BOTAN_DLL AES_192_Intel : public Block_Cipher_Fixed_Params<16, 24> /** * AES-256 using AES-NI */ -class BOTAN_DLL AES_256_Intel : public Block_Cipher_Fixed_Params<16, 32> +class BOTAN_DLL AES_256_NI : public Block_Cipher_Fixed_Params<16, 32> { public: size_t parallelism() const { return 4; } @@ -69,9 +69,9 @@ class BOTAN_DLL AES_256_Intel : public Block_Cipher_Fixed_Params<16, 32> void clear(); std::string name() const { return "AES-256"; } - BlockCipher* clone() const { return new AES_256_Intel; } + BlockCipher* clone() const { return new AES_256_NI; } - AES_256_Intel() : EK(60), DK(60) { } + AES_256_NI() : EK(60), DK(60) { } private: void key_schedule(const byte[], size_t); diff --git a/src/block/aes_intel/info.txt b/src/block/aes_ni/info.txt index 8bf0f07ee..597948fc3 100644 --- a/src/block/aes_intel/info.txt +++ b/src/block/aes_ni/info.txt @@ -1,4 +1,4 @@ -define AES_INTEL +define AES_NI load_on auto diff --git a/src/block/aes_ssse3/aes_ssse3.cpp b/src/block/aes_ssse3/aes_ssse3.cpp index c5869f899..774ccbabb 100644 --- a/src/block/aes_ssse3/aes_ssse3.cpp +++ b/src/block/aes_ssse3/aes_ssse3.cpp @@ -339,10 +339,10 @@ __m128i aes_ssse3_decrypt(__m128i B, const __m128i* keys, size_t rounds) */ void AES_128_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const { - const __m128i* in_mm = (const __m128i*)in; - __m128i* out_mm = (__m128i*)out; + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); - const __m128i* keys = (const __m128i*)&EK[0]; + const __m128i* keys = reinterpret_cast<const __m128i*>(&EK[0]); for(size_t i = 0; i != blocks; ++i) { @@ -356,10 +356,10 @@ void AES_128_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void AES_128_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const { - const __m128i* in_mm = (const __m128i*)in; - __m128i* out_mm = (__m128i*)out; + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); - const __m128i* keys = (const __m128i*)&DK[0]; + const __m128i* keys = reinterpret_cast<const __m128i*>(&DK[0]); for(size_t i = 0; i != blocks; ++i) { @@ -376,10 +376,10 @@ void AES_128_SSSE3::key_schedule(const byte keyb[], size_t) __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, 0x1F8391B9, 0xAF9DEEB6); - __m128i key = _mm_loadu_si128((const __m128i*)keyb); + __m128i key = _mm_loadu_si128(reinterpret_cast<const __m128i*>(keyb)); - __m128i* EK_mm = (__m128i*)&EK[0]; - __m128i* DK_mm = (__m128i*)&DK[0]; + __m128i* EK_mm = reinterpret_cast<__m128i*>(&EK[0]); + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); _mm_storeu_si128(DK_mm + 10, _mm_shuffle_epi8(key, sr[2])); @@ -408,10 +408,10 @@ void AES_128_SSSE3::key_schedule(const byte keyb[], size_t) */ void AES_192_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const { - const __m128i* in_mm = (const __m128i*)in; - __m128i* out_mm = (__m128i*)out; + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); - const __m128i* keys = (const __m128i*)&EK[0]; + const __m128i* keys = reinterpret_cast<const __m128i*>(&EK[0]); for(size_t i = 0; i != blocks; ++i) { @@ -425,10 +425,10 @@ void AES_192_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void AES_192_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const { - const __m128i* in_mm = (const __m128i*)in; - __m128i* out_mm = (__m128i*)out; + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); - const __m128i* keys = (const __m128i*)&DK[0]; + const __m128i* keys = reinterpret_cast<const __m128i*>(&DK[0]); for(size_t i = 0; i != blocks; ++i) { @@ -445,11 +445,11 @@ void AES_192_SSSE3::key_schedule(const byte keyb[], size_t) __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, 0x1F8391B9, 0xAF9DEEB6); - __m128i* EK_mm = (__m128i*)&EK[0]; - __m128i* DK_mm = (__m128i*)&DK[0]; + __m128i* EK_mm = reinterpret_cast<__m128i*>(&EK[0]); + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); - __m128i key1 = _mm_loadu_si128((const __m128i*)keyb); - __m128i key2 = _mm_loadu_si128((const __m128i*)(keyb + 8)); + __m128i key1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(keyb)); + __m128i key2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>((keyb + 8))); _mm_storeu_si128(DK_mm + 12, _mm_shuffle_epi8(key1, sr[0])); @@ -507,10 +507,10 @@ void AES_192_SSSE3::key_schedule(const byte keyb[], size_t) */ void AES_256_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const { - const __m128i* in_mm = (const __m128i*)in; - __m128i* out_mm = (__m128i*)out; + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); - const __m128i* keys = (const __m128i*)&EK[0]; + const __m128i* keys = reinterpret_cast<const __m128i*>(&EK[0]); for(size_t i = 0; i != blocks; ++i) { @@ -524,10 +524,10 @@ void AES_256_SSSE3::encrypt_n(const byte in[], byte out[], size_t blocks) const */ void AES_256_SSSE3::decrypt_n(const byte in[], byte out[], size_t blocks) const { - const __m128i* in_mm = (const __m128i*)in; - __m128i* out_mm = (__m128i*)out; + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); - const __m128i* keys = (const __m128i*)&DK[0]; + const __m128i* keys = reinterpret_cast<const __m128i*>(&DK[0]); for(size_t i = 0; i != blocks; ++i) { @@ -544,11 +544,11 @@ void AES_256_SSSE3::key_schedule(const byte keyb[], size_t) __m128i rcon = _mm_set_epi32(0x702A9808, 0x4D7C7D81, 0x1F8391B9, 0xAF9DEEB6); - __m128i* EK_mm = (__m128i*)&EK[0]; - __m128i* DK_mm = (__m128i*)&DK[0]; + __m128i* EK_mm = reinterpret_cast<__m128i*>(&EK[0]); + __m128i* DK_mm = reinterpret_cast<__m128i*>(&DK[0]); - __m128i key1 = _mm_loadu_si128((const __m128i*)keyb); - __m128i key2 = _mm_loadu_si128((const __m128i*)(keyb + 16)); + __m128i key1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(keyb)); + __m128i key2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>((keyb + 16))); _mm_storeu_si128(DK_mm + 14, _mm_shuffle_epi8(key1, sr[2])); diff --git a/src/block/des/des.cpp b/src/block/des/des.cpp index 739dfe87c..c500e9bab 100644 --- a/src/block/des/des.cpp +++ b/src/block/des/des.cpp @@ -2,6 +2,9 @@ * DES * (C) 1999-2008 Jack Lloyd * +* Based on a public domain implemenation by Phil Karn (who in turn +* credited Richard Outerbridge and Jim Gillogly) +* * Distributed under the terms of the Botan license */ diff --git a/src/block/idea_sse2/idea_sse2.cpp b/src/block/idea_sse2/idea_sse2.cpp index f2c770103..70698560d 100644 --- a/src/block/idea_sse2/idea_sse2.cpp +++ b/src/block/idea_sse2/idea_sse2.cpp @@ -16,7 +16,6 @@ inline __m128i mul(__m128i X, u16bit K_16) { const __m128i zeros = _mm_set1_epi16(0); const __m128i ones = _mm_set1_epi16(1); - const __m128i high_bit = _mm_set1_epi16(-32767); // 0x8000 const __m128i K = _mm_set1_epi16(K_16); @@ -29,10 +28,9 @@ inline __m128i mul(__m128i X, u16bit K_16) __m128i T = _mm_sub_epi16(mul_lo, mul_hi); // Unsigned compare; cmp = 1 if mul_lo < mul_hi else 0 - const __m128i cmp = _mm_srli_epi16(_mm_cmpgt_epi16( - _mm_add_epi16(mul_hi, high_bit), - _mm_add_epi16(mul_lo, high_bit)), - 15); + const __m128i subs = _mm_subs_epu16(mul_hi, mul_lo); + const __m128i cmp = _mm_min_epu8( + _mm_or_si128(subs, _mm_srli_epi16(subs, 8)), ones); T = _mm_add_epi16(T, cmp); @@ -131,10 +129,12 @@ void transpose_out(__m128i& B0, __m128i& B1, __m128i& B2, __m128i& B3) */ void idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) { - __m128i B0 = _mm_loadu_si128((const __m128i*)in); - __m128i B1 = _mm_loadu_si128((const __m128i*)in + 1); - __m128i B2 = _mm_loadu_si128((const __m128i*)in + 2); - __m128i B3 = _mm_loadu_si128((const __m128i*)in + 3); + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); + + __m128i B0 = _mm_loadu_si128(in_mm + 0); + __m128i B1 = _mm_loadu_si128(in_mm + 1); + __m128i B2 = _mm_loadu_si128(in_mm + 2); + __m128i B3 = _mm_loadu_si128(in_mm + 3); transpose_in(B0, B1, B2, B3); @@ -183,10 +183,12 @@ void idea_op_8(const byte in[64], byte out[64], const u16bit EK[52]) transpose_out(B0, B2, B1, B3); - _mm_storeu_si128((__m128i*)out, B0); - _mm_storeu_si128((__m128i*)out + 1, B2); - _mm_storeu_si128((__m128i*)out + 2, B1); - _mm_storeu_si128((__m128i*)out + 3, B3); + __m128i* out_mm = reinterpret_cast<__m128i*>(out); + + _mm_storeu_si128(out_mm + 0, B0); + _mm_storeu_si128(out_mm + 1, B2); + _mm_storeu_si128(out_mm + 2, B1); + _mm_storeu_si128(out_mm + 3, B3); } } diff --git a/src/block/noekeon_simd/info.txt b/src/block/noekeon_simd/info.txt index b73954cff..deac80702 100644 --- a/src/block/noekeon_simd/info.txt +++ b/src/block/noekeon_simd/info.txt @@ -2,6 +2,6 @@ define NOEKEON_SIMD <requires> noekeon -simd_32 +simd simd_engine </requires> diff --git a/src/block/noekeon_simd/noekeon_simd.cpp b/src/block/noekeon_simd/noekeon_simd.cpp index 97158593a..b2beafc82 100644 --- a/src/block/noekeon_simd/noekeon_simd.cpp +++ b/src/block/noekeon_simd/noekeon_simd.cpp @@ -16,7 +16,12 @@ namespace Botan { #define NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3) \ do { \ SIMD_32 T = A0 ^ A2; \ - T ^= rotate_left(T, 8) ^ rotate_right(T, 8); \ + SIMD_32 T_l8 = T; \ + SIMD_32 T_r8 = T; \ + T_l8.rotate_left(8); \ + T_r8.rotate_right(8); \ + T ^= T_l8; \ + T ^= T_r8; \ A1 ^= T; \ A3 ^= T; \ \ @@ -26,7 +31,12 @@ namespace Botan { A3 ^= K3; \ \ T = A1 ^ A3; \ - T ^= rotate_left(T, 8) ^ rotate_right(T, 8); \ + T_l8 = T; \ + T_r8 = T; \ + T_l8.rotate_left(8); \ + T_r8.rotate_right(8); \ + T ^= T_l8; \ + T ^= T_r8; \ A0 ^= T; \ A2 ^= T; \ } while(0) diff --git a/src/block/serpent/serpent.cpp b/src/block/serpent/serpent.cpp index 1d940cf39..b3cf0f6c9 100644 --- a/src/block/serpent/serpent.cpp +++ b/src/block/serpent/serpent.cpp @@ -2,6 +2,9 @@ * Serpent * (C) 1999-2007 Jack Lloyd * +* The sbox expressions used here were discovered by Dag Arne Osvik and +* are described in his paper "Speeding Up Serpent". +* * Distributed under the terms of the Botan license */ diff --git a/src/block/serpent_simd/info.txt b/src/block/serpent_simd/info.txt index b3bf34972..cd1a0dc7e 100644 --- a/src/block/serpent_simd/info.txt +++ b/src/block/serpent_simd/info.txt @@ -2,7 +2,7 @@ define SERPENT_SIMD <requires> serpent -simd_32 +simd simd_engine </requires> @@ -13,7 +13,3 @@ serp_simd.cpp <header:public> serp_simd.h </header:public> - -<header:internal> -serp_simd_sbox.h -</header:internal> diff --git a/src/block/serpent_simd/serp_simd.cpp b/src/block/serpent_simd/serp_simd.cpp index babe68d40..2b5e429fc 100644 --- a/src/block/serpent_simd/serp_simd.cpp +++ b/src/block/serpent_simd/serp_simd.cpp @@ -6,7 +6,6 @@ */ #include <botan/serp_simd.h> -#include <botan/internal/serp_simd_sbox.h> #include <botan/internal/simd_32.h> #include <botan/loadstor.h> @@ -14,6 +13,420 @@ namespace Botan { namespace { +#define SBoxE1(B0, B1, B2, B3) \ + do { \ + B3 ^= B0; \ + SIMD_32 B4 = B1; \ + B1 &= B3; \ + B4 ^= B2; \ + B1 ^= B0; \ + B0 |= B3; \ + B0 ^= B4; \ + B4 ^= B3; \ + B3 ^= B2; \ + B2 |= B1; \ + B2 ^= B4; \ + B4 = ~B4; \ + B4 |= B1; \ + B1 ^= B3; \ + B1 ^= B4; \ + B3 |= B0; \ + B1 ^= B3; \ + B4 ^= B3; \ + B3 = B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE2(B0, B1, B2, B3) \ + do { \ + B0 = ~B0; \ + B2 = ~B2; \ + SIMD_32 B4 = B0; \ + B0 &= B1; \ + B2 ^= B0; \ + B0 |= B3; \ + B3 ^= B2; \ + B1 ^= B0; \ + B0 ^= B4; \ + B4 |= B1; \ + B1 ^= B3; \ + B2 |= B0; \ + B2 &= B4; \ + B0 ^= B1; \ + B1 &= B2; \ + B1 ^= B0; \ + B0 &= B2; \ + B4 ^= B0; \ + B0 = B2; \ + B2 = B3; \ + B3 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE3(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B0; \ + B0 &= B2; \ + B0 ^= B3; \ + B2 ^= B1; \ + B2 ^= B0; \ + B3 |= B4; \ + B3 ^= B1; \ + B4 ^= B2; \ + B1 = B3; \ + B3 |= B4; \ + B3 ^= B0; \ + B0 &= B1; \ + B4 ^= B0; \ + B1 ^= B3; \ + B1 ^= B4; \ + B0 = B2; \ + B2 = B1; \ + B1 = B3; \ + B3 = ~B4; \ + } while(0); + +#define SBoxE4(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B0; \ + B0 |= B3; \ + B3 ^= B1; \ + B1 &= B4; \ + B4 ^= B2; \ + B2 ^= B3; \ + B3 &= B0; \ + B4 |= B1; \ + B3 ^= B4; \ + B0 ^= B1; \ + B4 &= B0; \ + B1 ^= B3; \ + B4 ^= B2; \ + B1 |= B0; \ + B1 ^= B2; \ + B0 ^= B3; \ + B2 = B1; \ + B1 |= B3; \ + B0 ^= B1; \ + B1 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxE5(B0, B1, B2, B3) \ + do { \ + B1 ^= B3; \ + B3 = ~B3; \ + B2 ^= B3; \ + B3 ^= B0; \ + SIMD_32 B4 = B1; \ + B1 &= B3; \ + B1 ^= B2; \ + B4 ^= B3; \ + B0 ^= B4; \ + B2 &= B4; \ + B2 ^= B0; \ + B0 &= B1; \ + B3 ^= B0; \ + B4 |= B1; \ + B4 ^= B0; \ + B0 |= B3; \ + B0 ^= B2; \ + B2 &= B3; \ + B0 = ~B0; \ + B4 ^= B2; \ + B2 = B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxE6(B0, B1, B2, B3) \ + do { \ + B0 ^= B1; \ + B1 ^= B3; \ + B3 = ~B3; \ + SIMD_32 B4 = B1; \ + B1 &= B0; \ + B2 ^= B3; \ + B1 ^= B2; \ + B2 |= B4; \ + B4 ^= B3; \ + B3 &= B1; \ + B3 ^= B0; \ + B4 ^= B1; \ + B4 ^= B2; \ + B2 ^= B0; \ + B0 &= B3; \ + B2 = ~B2; \ + B0 ^= B4; \ + B4 |= B3; \ + B4 ^= B2; \ + B2 = B0; \ + B0 = B1; \ + B1 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxE7(B0, B1, B2, B3) \ + do { \ + B2 = ~B2; \ + SIMD_32 B4 = B3; \ + B3 &= B0; \ + B0 ^= B4; \ + B3 ^= B2; \ + B2 |= B4; \ + B1 ^= B3; \ + B2 ^= B0; \ + B0 |= B1; \ + B2 ^= B1; \ + B4 ^= B0; \ + B0 |= B3; \ + B0 ^= B2; \ + B4 ^= B3; \ + B4 ^= B0; \ + B3 = ~B3; \ + B2 &= B4; \ + B3 ^= B2; \ + B2 = B4; \ + } while(0); + +#define SBoxE8(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B1; \ + B1 |= B2; \ + B1 ^= B3; \ + B4 ^= B2; \ + B2 ^= B1; \ + B3 |= B4; \ + B3 &= B0; \ + B4 ^= B2; \ + B3 ^= B1; \ + B1 |= B4; \ + B1 ^= B0; \ + B0 |= B4; \ + B0 ^= B2; \ + B1 ^= B4; \ + B2 ^= B1; \ + B1 &= B0; \ + B1 ^= B4; \ + B2 = ~B2; \ + B2 |= B0; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B3; \ + B3 = B0; \ + B0 = B4; \ + } while(0); + +#define SBoxD1(B0, B1, B2, B3) \ + do { \ + B2 = ~B2; \ + SIMD_32 B4 = B1; \ + B1 |= B0; \ + B4 = ~B4; \ + B1 ^= B2; \ + B2 |= B4; \ + B1 ^= B3; \ + B0 ^= B4; \ + B2 ^= B0; \ + B0 &= B3; \ + B4 ^= B0; \ + B0 |= B1; \ + B0 ^= B2; \ + B3 ^= B4; \ + B2 ^= B1; \ + B3 ^= B0; \ + B3 ^= B1; \ + B2 &= B3; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxD2(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B1; \ + B1 ^= B3; \ + B3 &= B1; \ + B4 ^= B2; \ + B3 ^= B0; \ + B0 |= B1; \ + B2 ^= B3; \ + B0 ^= B4; \ + B0 |= B2; \ + B1 ^= B3; \ + B0 ^= B1; \ + B1 |= B3; \ + B1 ^= B0; \ + B4 = ~B4; \ + B4 ^= B1; \ + B1 |= B0; \ + B1 ^= B0; \ + B1 |= B4; \ + B3 ^= B1; \ + B1 = B0; \ + B0 = B4; \ + B4 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD3(B0, B1, B2, B3) \ + do { \ + B2 ^= B3; \ + B3 ^= B0; \ + SIMD_32 B4 = B3; \ + B3 &= B2; \ + B3 ^= B1; \ + B1 |= B2; \ + B1 ^= B4; \ + B4 &= B3; \ + B2 ^= B3; \ + B4 &= B0; \ + B4 ^= B2; \ + B2 &= B1; \ + B2 |= B0; \ + B3 = ~B3; \ + B2 ^= B3; \ + B0 ^= B3; \ + B0 &= B1; \ + B3 ^= B4; \ + B3 ^= B0; \ + B0 = B1; \ + B1 = B4; \ + } while(0); + +#define SBoxD4(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B2; \ + B2 ^= B1; \ + B0 ^= B2; \ + B4 &= B2; \ + B4 ^= B0; \ + B0 &= B1; \ + B1 ^= B3; \ + B3 |= B4; \ + B2 ^= B3; \ + B0 ^= B3; \ + B1 ^= B4; \ + B3 &= B2; \ + B3 ^= B1; \ + B1 ^= B0; \ + B1 |= B2; \ + B0 ^= B3; \ + B1 ^= B4; \ + B0 ^= B1; \ + B4 = B0; \ + B0 = B2; \ + B2 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD5(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B2; \ + B2 &= B3; \ + B2 ^= B1; \ + B1 |= B3; \ + B1 &= B0; \ + B4 ^= B2; \ + B4 ^= B1; \ + B1 &= B2; \ + B0 = ~B0; \ + B3 ^= B4; \ + B1 ^= B3; \ + B3 &= B0; \ + B3 ^= B2; \ + B0 ^= B1; \ + B2 &= B0; \ + B3 ^= B0; \ + B2 ^= B4; \ + B2 |= B3; \ + B3 ^= B0; \ + B2 ^= B1; \ + B1 = B3; \ + B3 = B4; \ + } while(0); + +#define SBoxD6(B0, B1, B2, B3) \ + do { \ + B1 = ~B1; \ + SIMD_32 B4 = B3; \ + B2 ^= B1; \ + B3 |= B0; \ + B3 ^= B2; \ + B2 |= B1; \ + B2 &= B0; \ + B4 ^= B3; \ + B2 ^= B4; \ + B4 |= B0; \ + B4 ^= B1; \ + B1 &= B2; \ + B1 ^= B3; \ + B4 ^= B2; \ + B3 &= B4; \ + B4 ^= B1; \ + B3 ^= B4; \ + B4 = ~B4; \ + B3 ^= B0; \ + B0 = B1; \ + B1 = B4; \ + B4 = B3; \ + B3 = B2; \ + B2 = B4; \ + } while(0); + +#define SBoxD7(B0, B1, B2, B3) \ + do { \ + B0 ^= B2; \ + SIMD_32 B4 = B2; \ + B2 &= B0; \ + B4 ^= B3; \ + B2 = ~B2; \ + B3 ^= B1; \ + B2 ^= B3; \ + B4 |= B0; \ + B0 ^= B2; \ + B3 ^= B4; \ + B4 ^= B1; \ + B1 &= B3; \ + B1 ^= B0; \ + B0 ^= B3; \ + B0 |= B2; \ + B3 ^= B1; \ + B4 ^= B0; \ + B0 = B1; \ + B1 = B2; \ + B2 = B4; \ + } while(0); + +#define SBoxD8(B0, B1, B2, B3) \ + do { \ + SIMD_32 B4 = B2; \ + B2 ^= B0; \ + B0 &= B3; \ + B4 |= B3; \ + B2 = ~B2; \ + B3 ^= B1; \ + B1 |= B0; \ + B0 ^= B2; \ + B2 &= B4; \ + B3 &= B4; \ + B1 ^= B2; \ + B2 ^= B0; \ + B0 |= B2; \ + B4 ^= B1; \ + B0 ^= B3; \ + B3 ^= B4; \ + B4 |= B0; \ + B3 ^= B2; \ + B4 ^= B2; \ + B2 = B1; \ + B1 = B0; \ + B0 = B3; \ + B3 = B4; \ + } while(0); + #define key_xor(round, B0, B1, B2, B3) \ do { \ B0 ^= SIMD_32(keys[4*round ]); \ @@ -175,6 +588,24 @@ void serpent_decrypt_4(const byte in[64], #undef transform #undef i_transform +#undef SBoxE1 +#undef SBoxE2 +#undef SBoxE3 +#undef SBoxE4 +#undef SBoxE5 +#undef SBoxE6 +#undef SBoxE7 +#undef SBoxE8 + +#undef SBoxD1 +#undef SBoxD2 +#undef SBoxD3 +#undef SBoxD4 +#undef SBoxD5 +#undef SBoxD6 +#undef SBoxD7 +#undef SBoxD8 + /* * Serpent Encryption */ diff --git a/src/block/serpent_simd/serp_simd_sbox.h b/src/block/serpent_simd/serp_simd_sbox.h deleted file mode 100644 index 71eca19e5..000000000 --- a/src/block/serpent_simd/serp_simd_sbox.h +++ /dev/null @@ -1,425 +0,0 @@ -/* -* Serpent Sboxes in SIMD form -* (C) 2009 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_SERPENT_SIMD_SBOXES_H__ -#define BOTAN_SERPENT_SIMD_SBOXES_H__ - -#define SBoxE1(B0, B1, B2, B3) \ - do { \ - B3 ^= B0; \ - SIMD_32 B4 = B1; \ - B1 &= B3; \ - B4 ^= B2; \ - B1 ^= B0; \ - B0 |= B3; \ - B0 ^= B4; \ - B4 ^= B3; \ - B3 ^= B2; \ - B2 |= B1; \ - B2 ^= B4; \ - B4 = ~B4; \ - B4 |= B1; \ - B1 ^= B3; \ - B1 ^= B4; \ - B3 |= B0; \ - B1 ^= B3; \ - B4 ^= B3; \ - B3 = B0; \ - B0 = B1; \ - B1 = B4; \ - } while(0); - -#define SBoxE2(B0, B1, B2, B3) \ - do { \ - B0 = ~B0; \ - B2 = ~B2; \ - SIMD_32 B4 = B0; \ - B0 &= B1; \ - B2 ^= B0; \ - B0 |= B3; \ - B3 ^= B2; \ - B1 ^= B0; \ - B0 ^= B4; \ - B4 |= B1; \ - B1 ^= B3; \ - B2 |= B0; \ - B2 &= B4; \ - B0 ^= B1; \ - B1 &= B2; \ - B1 ^= B0; \ - B0 &= B2; \ - B4 ^= B0; \ - B0 = B2; \ - B2 = B3; \ - B3 = B1; \ - B1 = B4; \ - } while(0); - -#define SBoxE3(B0, B1, B2, B3) \ - do { \ - SIMD_32 B4 = B0; \ - B0 &= B2; \ - B0 ^= B3; \ - B2 ^= B1; \ - B2 ^= B0; \ - B3 |= B4; \ - B3 ^= B1; \ - B4 ^= B2; \ - B1 = B3; \ - B3 |= B4; \ - B3 ^= B0; \ - B0 &= B1; \ - B4 ^= B0; \ - B1 ^= B3; \ - B1 ^= B4; \ - B0 = B2; \ - B2 = B1; \ - B1 = B3; \ - B3 = ~B4; \ - } while(0); - -#define SBoxE4(B0, B1, B2, B3) \ - do { \ - SIMD_32 B4 = B0; \ - B0 |= B3; \ - B3 ^= B1; \ - B1 &= B4; \ - B4 ^= B2; \ - B2 ^= B3; \ - B3 &= B0; \ - B4 |= B1; \ - B3 ^= B4; \ - B0 ^= B1; \ - B4 &= B0; \ - B1 ^= B3; \ - B4 ^= B2; \ - B1 |= B0; \ - B1 ^= B2; \ - B0 ^= B3; \ - B2 = B1; \ - B1 |= B3; \ - B0 ^= B1; \ - B1 = B2; \ - B2 = B3; \ - B3 = B4; \ - } while(0); - -#define SBoxE5(B0, B1, B2, B3) \ - do { \ - B1 ^= B3; \ - B3 = ~B3; \ - B2 ^= B3; \ - B3 ^= B0; \ - SIMD_32 B4 = B1; \ - B1 &= B3; \ - B1 ^= B2; \ - B4 ^= B3; \ - B0 ^= B4; \ - B2 &= B4; \ - B2 ^= B0; \ - B0 &= B1; \ - B3 ^= B0; \ - B4 |= B1; \ - B4 ^= B0; \ - B0 |= B3; \ - B0 ^= B2; \ - B2 &= B3; \ - B0 = ~B0; \ - B4 ^= B2; \ - B2 = B0; \ - B0 = B1; \ - B1 = B4; \ - } while(0); - -#define SBoxE6(B0, B1, B2, B3) \ - do { \ - B0 ^= B1; \ - B1 ^= B3; \ - B3 = ~B3; \ - SIMD_32 B4 = B1; \ - B1 &= B0; \ - B2 ^= B3; \ - B1 ^= B2; \ - B2 |= B4; \ - B4 ^= B3; \ - B3 &= B1; \ - B3 ^= B0; \ - B4 ^= B1; \ - B4 ^= B2; \ - B2 ^= B0; \ - B0 &= B3; \ - B2 = ~B2; \ - B0 ^= B4; \ - B4 |= B3; \ - B4 ^= B2; \ - B2 = B0; \ - B0 = B1; \ - B1 = B3; \ - B3 = B4; \ - } while(0); - -#define SBoxE7(B0, B1, B2, B3) \ - do { \ - B2 = ~B2; \ - SIMD_32 B4 = B3; \ - B3 &= B0; \ - B0 ^= B4; \ - B3 ^= B2; \ - B2 |= B4; \ - B1 ^= B3; \ - B2 ^= B0; \ - B0 |= B1; \ - B2 ^= B1; \ - B4 ^= B0; \ - B0 |= B3; \ - B0 ^= B2; \ - B4 ^= B3; \ - B4 ^= B0; \ - B3 = ~B3; \ - B2 &= B4; \ - B3 ^= B2; \ - B2 = B4; \ - } while(0); - -#define SBoxE8(B0, B1, B2, B3) \ - do { \ - SIMD_32 B4 = B1; \ - B1 |= B2; \ - B1 ^= B3; \ - B4 ^= B2; \ - B2 ^= B1; \ - B3 |= B4; \ - B3 &= B0; \ - B4 ^= B2; \ - B3 ^= B1; \ - B1 |= B4; \ - B1 ^= B0; \ - B0 |= B4; \ - B0 ^= B2; \ - B1 ^= B4; \ - B2 ^= B1; \ - B1 &= B0; \ - B1 ^= B4; \ - B2 = ~B2; \ - B2 |= B0; \ - B4 ^= B2; \ - B2 = B1; \ - B1 = B3; \ - B3 = B0; \ - B0 = B4; \ - } while(0); - -#define SBoxD1(B0, B1, B2, B3) \ - do { \ - B2 = ~B2; \ - SIMD_32 B4 = B1; \ - B1 |= B0; \ - B4 = ~B4; \ - B1 ^= B2; \ - B2 |= B4; \ - B1 ^= B3; \ - B0 ^= B4; \ - B2 ^= B0; \ - B0 &= B3; \ - B4 ^= B0; \ - B0 |= B1; \ - B0 ^= B2; \ - B3 ^= B4; \ - B2 ^= B1; \ - B3 ^= B0; \ - B3 ^= B1; \ - B2 &= B3; \ - B4 ^= B2; \ - B2 = B1; \ - B1 = B4; \ - } while(0); - -#define SBoxD2(B0, B1, B2, B3) \ - do { \ - SIMD_32 B4 = B1; \ - B1 ^= B3; \ - B3 &= B1; \ - B4 ^= B2; \ - B3 ^= B0; \ - B0 |= B1; \ - B2 ^= B3; \ - B0 ^= B4; \ - B0 |= B2; \ - B1 ^= B3; \ - B0 ^= B1; \ - B1 |= B3; \ - B1 ^= B0; \ - B4 = ~B4; \ - B4 ^= B1; \ - B1 |= B0; \ - B1 ^= B0; \ - B1 |= B4; \ - B3 ^= B1; \ - B1 = B0; \ - B0 = B4; \ - B4 = B2; \ - B2 = B3; \ - B3 = B4; \ - } while(0); - -#define SBoxD3(B0, B1, B2, B3) \ - do { \ - B2 ^= B3; \ - B3 ^= B0; \ - SIMD_32 B4 = B3; \ - B3 &= B2; \ - B3 ^= B1; \ - B1 |= B2; \ - B1 ^= B4; \ - B4 &= B3; \ - B2 ^= B3; \ - B4 &= B0; \ - B4 ^= B2; \ - B2 &= B1; \ - B2 |= B0; \ - B3 = ~B3; \ - B2 ^= B3; \ - B0 ^= B3; \ - B0 &= B1; \ - B3 ^= B4; \ - B3 ^= B0; \ - B0 = B1; \ - B1 = B4; \ - } while(0); - -#define SBoxD4(B0, B1, B2, B3) \ - do { \ - SIMD_32 B4 = B2; \ - B2 ^= B1; \ - B0 ^= B2; \ - B4 &= B2; \ - B4 ^= B0; \ - B0 &= B1; \ - B1 ^= B3; \ - B3 |= B4; \ - B2 ^= B3; \ - B0 ^= B3; \ - B1 ^= B4; \ - B3 &= B2; \ - B3 ^= B1; \ - B1 ^= B0; \ - B1 |= B2; \ - B0 ^= B3; \ - B1 ^= B4; \ - B0 ^= B1; \ - B4 = B0; \ - B0 = B2; \ - B2 = B3; \ - B3 = B4; \ - } while(0); - -#define SBoxD5(B0, B1, B2, B3) \ - do { \ - SIMD_32 B4 = B2; \ - B2 &= B3; \ - B2 ^= B1; \ - B1 |= B3; \ - B1 &= B0; \ - B4 ^= B2; \ - B4 ^= B1; \ - B1 &= B2; \ - B0 = ~B0; \ - B3 ^= B4; \ - B1 ^= B3; \ - B3 &= B0; \ - B3 ^= B2; \ - B0 ^= B1; \ - B2 &= B0; \ - B3 ^= B0; \ - B2 ^= B4; \ - B2 |= B3; \ - B3 ^= B0; \ - B2 ^= B1; \ - B1 = B3; \ - B3 = B4; \ - } while(0); - -#define SBoxD6(B0, B1, B2, B3) \ - do { \ - B1 = ~B1; \ - SIMD_32 B4 = B3; \ - B2 ^= B1; \ - B3 |= B0; \ - B3 ^= B2; \ - B2 |= B1; \ - B2 &= B0; \ - B4 ^= B3; \ - B2 ^= B4; \ - B4 |= B0; \ - B4 ^= B1; \ - B1 &= B2; \ - B1 ^= B3; \ - B4 ^= B2; \ - B3 &= B4; \ - B4 ^= B1; \ - B3 ^= B4; \ - B4 = ~B4; \ - B3 ^= B0; \ - B0 = B1; \ - B1 = B4; \ - B4 = B3; \ - B3 = B2; \ - B2 = B4; \ - } while(0); - -#define SBoxD7(B0, B1, B2, B3) \ - do { \ - B0 ^= B2; \ - SIMD_32 B4 = B2; \ - B2 &= B0; \ - B4 ^= B3; \ - B2 = ~B2; \ - B3 ^= B1; \ - B2 ^= B3; \ - B4 |= B0; \ - B0 ^= B2; \ - B3 ^= B4; \ - B4 ^= B1; \ - B1 &= B3; \ - B1 ^= B0; \ - B0 ^= B3; \ - B0 |= B2; \ - B3 ^= B1; \ - B4 ^= B0; \ - B0 = B1; \ - B1 = B2; \ - B2 = B4; \ - } while(0); - -#define SBoxD8(B0, B1, B2, B3) \ - do { \ - SIMD_32 B4 = B2; \ - B2 ^= B0; \ - B0 &= B3; \ - B4 |= B3; \ - B2 = ~B2; \ - B3 ^= B1; \ - B1 |= B0; \ - B0 ^= B2; \ - B2 &= B4; \ - B3 &= B4; \ - B1 ^= B2; \ - B2 ^= B0; \ - B0 |= B2; \ - B4 ^= B1; \ - B0 ^= B3; \ - B3 ^= B4; \ - B4 |= B0; \ - B3 ^= B2; \ - B4 ^= B2; \ - B2 = B1; \ - B1 = B0; \ - B0 = B3; \ - B3 = B4; \ - } while(0); - -#endif diff --git a/src/block/serpent_ia32/info.txt b/src/block/serpent_x86_32/info.txt index 3a1dd5919..b9c993546 100644 --- a/src/block/serpent_ia32/info.txt +++ b/src/block/serpent_x86_32/info.txt @@ -1,12 +1,12 @@ -define SERPENT_IA32 +define SERPENT_X86_32 load_on asm_ok <arch> -ia32 +x86_32 </arch> <requires> -asm_ia32 +asm_x86_32 serpent </requires> diff --git a/src/block/serpent_ia32/serp_ia32.cpp b/src/block/serpent_x86_32/serp_x86_32.cpp index d2f8adb62..4cefe1d65 100644 --- a/src/block/serpent_ia32/serp_ia32.cpp +++ b/src/block/serpent_x86_32/serp_x86_32.cpp @@ -1,11 +1,11 @@ /* -* IA-32 Serpent +* Serpent in x86-32 * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/serp_ia32.h> +#include <botan/serp_x86_32.h> #include <botan/loadstor.h> namespace Botan { @@ -18,7 +18,7 @@ extern "C" { * @param out the output block * @param ks the key schedule */ -void botan_serpent_ia32_encrypt(const byte in[16], +void botan_serpent_x86_32_encrypt(const byte in[16], byte out[16], const u32bit ks[132]); @@ -28,7 +28,7 @@ void botan_serpent_ia32_encrypt(const byte in[16], * @param out the output block * @param ks the key schedule */ -void botan_serpent_ia32_decrypt(const byte in[16], +void botan_serpent_x86_32_decrypt(const byte in[16], byte out[16], const u32bit ks[132]); @@ -37,18 +37,18 @@ void botan_serpent_ia32_decrypt(const byte in[16], * @param ks holds the initial working key (padded), and is set to the final key schedule */ -void botan_serpent_ia32_key_schedule(u32bit ks[140]); +void botan_serpent_x86_32_key_schedule(u32bit ks[140]); } /* * Serpent Encryption */ -void Serpent_IA32::encrypt_n(const byte in[], byte out[], size_t blocks) const +void Serpent_X86_32::encrypt_n(const byte in[], byte out[], size_t blocks) const { for(size_t i = 0; i != blocks; ++i) { - botan_serpent_ia32_encrypt(in, out, this->get_round_keys()); + botan_serpent_x86_32_encrypt(in, out, this->get_round_keys()); in += BLOCK_SIZE; out += BLOCK_SIZE; } @@ -57,11 +57,11 @@ void Serpent_IA32::encrypt_n(const byte in[], byte out[], size_t blocks) const /* * Serpent Decryption */ -void Serpent_IA32::decrypt_n(const byte in[], byte out[], size_t blocks) const +void Serpent_X86_32::decrypt_n(const byte in[], byte out[], size_t blocks) const { for(size_t i = 0; i != blocks; ++i) { - botan_serpent_ia32_decrypt(in, out, this->get_round_keys()); + botan_serpent_x86_32_decrypt(in, out, this->get_round_keys()); in += BLOCK_SIZE; out += BLOCK_SIZE; } @@ -70,14 +70,14 @@ void Serpent_IA32::decrypt_n(const byte in[], byte out[], size_t blocks) const /* * Serpent Key Schedule */ -void Serpent_IA32::key_schedule(const byte key[], size_t length) +void Serpent_X86_32::key_schedule(const byte key[], size_t length) { SecureVector<u32bit> W(140); for(size_t i = 0; i != length / 4; ++i) W[i] = load_le<u32bit>(key, i); W[length / 4] |= u32bit(1) << ((length%4)*8); - botan_serpent_ia32_key_schedule(W); + botan_serpent_x86_32_key_schedule(W); this->set_round_keys(W + 8); } diff --git a/src/block/serpent_ia32/serp_ia32.h b/src/block/serpent_x86_32/serp_x86_32.h index d7b5bedc7..f6c4d564a 100644 --- a/src/block/serpent_ia32/serp_ia32.h +++ b/src/block/serpent_x86_32/serp_x86_32.h @@ -1,27 +1,27 @@ /* -* Serpent (IA-32) +* Serpent in x86-32 asm * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#ifndef BOTAN_SERPENT_IA32_H__ -#define BOTAN_SERPENT_IA32_H__ +#ifndef BOTAN_SERPENT_X86_32_H__ +#define BOTAN_SERPENT_X86_32_H__ #include <botan/serpent.h> namespace Botan { /** -* Serpent implementation in x86 assembly +* Serpent implementation in x86-32 assembly */ -class BOTAN_DLL Serpent_IA32 : public Serpent +class BOTAN_DLL Serpent_X86_32 : public Serpent { public: void encrypt_n(const byte in[], byte out[], size_t blocks) const; void decrypt_n(const byte in[], byte out[], size_t blocks) const; - BlockCipher* clone() const { return new Serpent_IA32; } + BlockCipher* clone() const { return new Serpent_X86_32; } private: void key_schedule(const byte[], size_t); }; diff --git a/src/block/serpent_ia32/serp_ia32_imp.S b/src/block/serpent_x86_32/serp_x86_32_imp.S index 768192061..e2549a099 100644 --- a/src/block/serpent_ia32/serp_ia32_imp.S +++ b/src/block/serpent_x86_32/serp_x86_32_imp.S @@ -1,13 +1,13 @@ /* -* Serpent in IA-32 assembler +* Serpent in x86-32 assembler * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/internal/asm_macr_ia32.h> +#include <botan/internal/asm_x86_32.h> -START_LISTING(serp_ia32.S) +START_LISTING(serp_x86_32.S) #define SBOX_E1(A, B, C, D, T) \ XOR(D, A) ; \ @@ -441,7 +441,7 @@ START_LISTING(serp_ia32.S) /* * Serpent Encryption */ -START_FUNCTION(botan_serpent_ia32_encrypt) +START_FUNCTION(botan_serpent_x86_32_encrypt) SPILL_REGS() #define PUSHED 4 @@ -507,12 +507,12 @@ START_FUNCTION(botan_serpent_ia32_encrypt) RESTORE_REGS() #undef PUSHED -END_FUNCTION(botan_serpent_ia32_encrypt) +END_FUNCTION(botan_serpent_x86_32_encrypt) /* * Serpent Decryption */ -START_FUNCTION(botan_serpent_ia32_decrypt) +START_FUNCTION(botan_serpent_x86_32_decrypt) SPILL_REGS() #define PUSHED 4 @@ -578,12 +578,12 @@ START_FUNCTION(botan_serpent_ia32_decrypt) RESTORE_REGS() #undef PUSHED -END_FUNCTION(botan_serpent_ia32_decrypt) +END_FUNCTION(botan_serpent_x86_32_decrypt) /* * Serpent Key Schedule */ -START_FUNCTION(botan_serpent_ia32_key_schedule) +START_FUNCTION(botan_serpent_x86_32_key_schedule) SPILL_REGS() #define PUSHED 4 @@ -591,7 +591,7 @@ START_FUNCTION(botan_serpent_ia32_key_schedule) ASSIGN(ESI, IMM(8)) ADD_IMM(EDI, 32) -START_LOOP(.EXPANSION) +START_LOOP(.L_SERP_EXPANSION) ASSIGN(EAX, ARRAY4(EDI, -1)) ASSIGN(EBX, ARRAY4(EDI, -3)) ASSIGN(ECX, ARRAY4(EDI, -5)) @@ -611,7 +611,7 @@ START_LOOP(.EXPANSION) ADD_IMM(ESI, 1) ADD_IMM(EDI, 4) -LOOP_UNTIL_EQ(ESI, 140, .EXPANSION) +LOOP_UNTIL_EQ(ESI, 140, .L_SERP_EXPANSION) ASSIGN(EDI, ARG(1)) /* round keys */ @@ -666,4 +666,4 @@ LOOP_UNTIL_EQ(ESI, 140, .EXPANSION) RESTORE_REGS() #undef PUSHED -END_FUNCTION(botan_serpent_ia32_key_schedule) +END_FUNCTION(botan_serpent_x86_32_key_schedule) diff --git a/src/block/square/square.cpp b/src/block/square/square.cpp index b1517b990..cd1865582 100644 --- a/src/block/square/square.cpp +++ b/src/block/square/square.cpp @@ -2,6 +2,8 @@ * Square * (C) 1999-2007 Jack Lloyd * +* Based on the public domain reference implemenation +* * Distributed under the terms of the Botan license */ diff --git a/src/block/twofish/twofish.cpp b/src/block/twofish/twofish.cpp index 41bc7ca1c..c0735e202 100644 --- a/src/block/twofish/twofish.cpp +++ b/src/block/twofish/twofish.cpp @@ -2,6 +2,9 @@ * Twofish * (C) 1999-2007 Jack Lloyd * +* The key schedule implemenation is based on a public domain +* implementation by Matthew Skala +* * Distributed under the terms of the Botan license */ diff --git a/src/block/xtea_simd/info.txt b/src/block/xtea_simd/info.txt index 5a8445b35..c16bfa2fa 100644 --- a/src/block/xtea_simd/info.txt +++ b/src/block/xtea_simd/info.txt @@ -2,6 +2,6 @@ define XTEA_SIMD <requires> xtea -simd_32 +simd simd_engine </requires> diff --git a/src/build-data/arch/arm.txt b/src/build-data/arch/arm.txt index 77f15b1d9..b822fe130 100644 --- a/src/build-data/arch/arm.txt +++ b/src/build-data/arch/arm.txt @@ -1,25 +1,43 @@ + +endian little +family arm + +<aliases> +armel # For Debian +armhf # For Debian +</aliases> + <submodels> -arm2 -arm3 -arm6 -arm7 -arm8 -arm9 -strongarm -strongarm110 -strongarm1100 -xscale -cortex-a8 -cortex-a9 +armv2 +armv2a +armv3 +armv3m +armv4 +armv5 +armv5e +armv5te +armv6 +armv6j +armv6t2 +armv6z +armv6zk +armv6-m +armv7 +armv7-a +armv7-r +armv7-m +iwmmxt +iwmmxt2 +ep9312 </submodels> <submodel_aliases> -sa110 -> strongarm110 -sa1100 -> strongarm1100 -strongarm1110 -> strongarm1100 -armv5tel -> xscale +strongarm -> armv4 +xscale -> armv5te +cortex-a8 -> armv7-a +cortex-a9 -> armv7-a </submodel_aliases> <isa_extn> -neon:cortex-a8,cortex-a9 +neon:armv7-a </isa_extn> diff --git a/src/build-data/arch/hitachi-sh.txt b/src/build-data/arch/hitachi-sh.txt deleted file mode 100644 index bab84b48f..000000000 --- a/src/build-data/arch/hitachi-sh.txt +++ /dev/null @@ -1,7 +0,0 @@ -<submodels> -hitachi-sh1 -hitachi-sh2 -hitachi-sh3 -hitachi-sh3e -hitachi-sh4 -</submodels> diff --git a/src/build-data/arch/ppc.txt b/src/build-data/arch/ppc32.txt index dc3ea7829..e33c8ff24 100644 --- a/src/build-data/arch/ppc.txt +++ b/src/build-data/arch/ppc32.txt @@ -5,13 +5,9 @@ family ppc <aliases> powerpc +ppc </aliases> -<submodel_aliases> -g3 -> ppc740 -g4 -> ppc7450 -</submodel_aliases> - <submodels> ppc601 ppc603 @@ -20,8 +16,15 @@ ppc740 ppc750 ppc7400 ppc7450 +e500v2 </submodels> +<submodel_aliases> +g3 -> ppc740 +g4 -> ppc7450 +powerpcspe -> e500v2 # for Debian +</submodel_aliases> + <isa_extn> altivec:ppc7400,ppc7450 </isa_extn> diff --git a/src/build-data/arch/ppc64.txt b/src/build-data/arch/ppc64.txt index 7a2e6b6b3..954d9181e 100644 --- a/src/build-data/arch/ppc64.txt +++ b/src/build-data/arch/ppc64.txt @@ -11,7 +11,6 @@ g5 -> ppc970 </submodel_aliases> <submodels> -rs64a ppc970 power3 power4 diff --git a/src/build-data/arch/sparc32.txt b/src/build-data/arch/sparc32.txt index fc015e520..69f3479aa 100644 --- a/src/build-data/arch/sparc32.txt +++ b/src/build-data/arch/sparc32.txt @@ -26,4 +26,6 @@ sparcv9 -> sparc32-v9 sparc-v7 -> sparc32-v7 sparc-v8 -> sparc32-v8 sparc-v9 -> sparc32-v9 + +sun4u -> sparc32-v9 </submodel_aliases> diff --git a/src/build-data/arch/sparc64.txt b/src/build-data/arch/sparc64.txt index 7344fa390..3a6acd6c3 100644 --- a/src/build-data/arch/sparc64.txt +++ b/src/build-data/arch/sparc64.txt @@ -1,13 +1,11 @@ family sparc -<aliases> -sun4u -</aliases> - <submodels> ultrasparc ultrasparc3 +niagra +niagra2 </submodels> <submodel_aliases> diff --git a/src/build-data/arch/superh.txt b/src/build-data/arch/superh.txt new file mode 100644 index 000000000..c7dc09861 --- /dev/null +++ b/src/build-data/arch/superh.txt @@ -0,0 +1,5 @@ +<submodels> +sh2 +sh3 +sh4 +</submodels> diff --git a/src/build-data/arch/ia32.txt b/src/build-data/arch/x86_32.txt index c2d4d1769..482a53057 100644 --- a/src/build-data/arch/ia32.txt +++ b/src/build-data/arch/x86_32.txt @@ -4,10 +4,13 @@ unaligned ok family x86 <aliases> +ia32 x86 ix86 80x86 i86pc # for Solaris +x86pc # for QNX +bepc # for Haiku </aliases> <submodels> @@ -22,7 +25,7 @@ pentium-m prescott k6 athlon -atom +atom32 </submodels> <submodel_aliases> @@ -59,7 +62,7 @@ intelcput2700 -> prescott </submodel_aliases> <isa_extn> -sse2:pentium4,prescott,pentium-m,atom -ssse3:atom -movbe:atom +sse2:pentium4,prescott,pentium-m,atom32 +ssse3:atom32 +movbe:atom32 </isa_extn> diff --git a/src/build-data/arch/amd64.txt b/src/build-data/arch/x86_64.txt index b3b9879d2..97b84fbde 100644 --- a/src/build-data/arch/amd64.txt +++ b/src/build-data/arch/x86_64.txt @@ -4,8 +4,8 @@ unaligned ok family x86 <aliases> +amd64 x86-64 -x86_64 # for RPM em64t x64 </aliases> @@ -17,6 +17,7 @@ nocona core2 nehalem westmere +atom </submodels> <submodel_aliases> @@ -36,6 +37,6 @@ corei7cpu860 -> nehalem <isa_extn> sse2:all -ssse3:core2,nehalem,westmere +ssse3:core2,nehalem,westmere,atom aes-ni:westmere </isa_extn> diff --git a/src/build-data/botan-config.in b/src/build-data/botan-config.in index f3fa3db94..6780c12b8 100644 --- a/src/build-data/botan-config.in +++ b/src/build-data/botan-config.in @@ -2,7 +2,7 @@ # For normal builds: guess_prefix=`dirname \`dirname $0\`` -includedir=%{includedir} +includedir=%{includedir}/botan-%{version_major}.%{version_minor} libdir=%{libdir} # For workspace builds: @@ -54,9 +54,9 @@ while test $# -gt 0; do --libs) if [ $prefix != "/usr" -a $prefix != "/usr/local" ] then - echo -L$prefix/$libdir -lbotan %{link_to} + echo -L$prefix/$libdir -lbotan-%{version_major}.%{version_minor} %{link_to} else - echo -lbotan %{link_to} + echo -lbotan-%{version_major}.%{version_minor} %{link_to} fi ;; *) diff --git a/src/build-data/botan.doxy.in b/src/build-data/botan.doxy.in index 2f76a756b..52021c01f 100644 --- a/src/build-data/botan.doxy.in +++ b/src/build-data/botan.doxy.in @@ -1,12 +1,9 @@ # Doxyfile 1.5.4 -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = Botan PROJECT_NUMBER = %{version} -OUTPUT_DIRECTORY = doc/doxygen +OUTPUT_DIRECTORY = %{doc_output_dir}/doxygen +DOXYFILE_ENCODING = UTF-8 CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES @@ -33,6 +30,7 @@ SIP_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -63,6 +61,7 @@ MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = + #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- @@ -73,6 +72,7 @@ WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = + #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- @@ -112,7 +112,7 @@ IGNORE_PREFIX = # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES -HTML_OUTPUT = html +HTML_OUTPUT = . HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = @@ -129,56 +129,7 @@ DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4wide -EXTRA_PACKAGES = -LATEX_HEADER = -PDF_HYPERLINKS = NO -USE_PDFLATEX = NO -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- -GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_LINKS = NO -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- -GENERATE_XML = NO -XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = -XML_PROGRAMLISTING = YES -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- -GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = + #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- @@ -191,6 +142,7 @@ INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES + #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- @@ -199,6 +151,7 @@ GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl + #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -226,6 +179,7 @@ DOT_TRANSPARENT = YES DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES + #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- diff --git a/src/build-data/botan.pc.in b/src/build-data/botan.pc.in index 70ed65d70..301f84600 100644 --- a/src/build-data/botan.pc.in +++ b/src/build-data/botan.pc.in @@ -1,12 +1,12 @@ prefix=%{prefix} exec_prefix=${prefix} libdir=${prefix}/%{libdir} -includedir=${prefix}/include +includedir=${prefix}/include/botan-%{version_major}.%{version_minor} Name: Botan Description: Multi-platform C++ crypto library Version: %{version} -Libs: -L${libdir} -lbotan +Libs: -L${libdir} -lbotan-%{version_major}.%{version_minor} Libs.private: %{link_to} Cflags: -I${includedir} diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in index 2682d2ad9..733646524 100644 --- a/src/build-data/buildh.in +++ b/src/build-data/buildh.in @@ -20,7 +20,7 @@ #define BOTAN_DISTRIBUTION_INFO "%{distribution_info}" #ifndef BOTAN_DLL - #define BOTAN_DLL %{dll_import_flags} + #define BOTAN_DLL %{visibility_attribute} #endif /* Chunk sizes */ @@ -35,7 +35,7 @@ /* PK key consistency checking toggles */ #define BOTAN_PUBLIC_KEY_STRONG_CHECKS_ON_LOAD 1 -#define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_LOAD 1 +#define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_LOAD 0 #define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE 1 /* Should we use GCC-style inline assembler? */ diff --git a/src/build-data/cc/bcc.txt b/src/build-data/cc/bcc.txt index 93306dde1..f2ea46ef2 100644 --- a/src/build-data/cc/bcc.txt +++ b/src/build-data/cc/bcc.txt @@ -15,7 +15,6 @@ lang_flags "" warning_flags "" shared_flags "" -dll_import_flags "" ar_command lib diff --git a/src/build-data/cc/clang.txt b/src/build-data/cc/clang.txt index 14c51349c..f4db26ee8 100644 --- a/src/build-data/cc/clang.txt +++ b/src/build-data/cc/clang.txt @@ -17,11 +17,12 @@ makefile_style unix lib_opt_flags "-O2" check_opt_flags "-O2" -shared_flags "-fPIC -fvisibility=hidden" +shared_flags "-fPIC" debug_flags -g no_debug_flags "-finline-functions" -dll_import_flags '__attribute__((visibility("default")))' +visibility_build_flags "-fvisibility=hidden" +visibility_attribute '__attribute__((visibility("default")))' <so_link_flags> # The default works for GNU ld and several other Unix linkers @@ -29,12 +30,12 @@ default -> "$(CXX) -shared -fPIC -Wl,-soname,$(SONAME)" </so_link_flags> <mach_opt> -amd64 -> "-march=SUBMODEL" +x86_64 -> "-march=SUBMODEL" nehalem -> "-march=core2 -mssse3 -msse4.1" </mach_opt> <mach_abi_linking> -amd64 -> "-m64" +x86_64 -> "-m64" mips64 -> "-mabi=64" s390 -> "-m31" s390x -> "-m64" diff --git a/src/build-data/cc/ekopath.txt b/src/build-data/cc/ekopath.txt index ac514261e..c6e8b6550 100644 --- a/src/build-data/cc/ekopath.txt +++ b/src/build-data/cc/ekopath.txt @@ -28,10 +28,9 @@ default -> "$(CXX) -shared -fPIC -Wl,-soname,$(SONAME)" athlon -> "-mcpu=athlon" pentium4 -> "-mcpu=pentium4" -opteron -> "-mcpu=opteron" -em64t -> "-mcpu=em64t" +k8 -> "-mcpu=opteron" core2 -> "-mcpu=core" -ia32 -> "-mcpu=anyx86" -amd64 -> "-mcpu=athlon64" +x86_32 -> "-mcpu=anyx86" +x86_64 -> "-mcpu=athlon64" </mach_opt> diff --git a/src/build-data/cc/gcc.txt b/src/build-data/cc/gcc.txt index 2f71c7a18..84e923764 100644 --- a/src/build-data/cc/gcc.txt +++ b/src/build-data/cc/gcc.txt @@ -1,6 +1,6 @@ macro_name GCC -binary_name g++-4.5.2 +binary_name g++-4.6.0 compile_option "-c " output_to_option "-o " @@ -11,15 +11,16 @@ add_lib_option -l lang_flags "-D_REENTRANT -std=c++0x" warning_flags "-W -Wall" -maintainer_warning_flags "-Werror -Wall -Wextra -Wstrict-aliasing -Wstrict-overflow=5 -Wcast-align -Wmissing-declarations -Wpointer-arith -Wcast-qual" +maintainer_warning_flags "-Werror -Wall -Wextra -Wstrict-aliasing -Wstrict-overflow=5 -Wcast-align -Wmissing-declarations -Wpointer-arith -Wcast-qual -Wold-style-cast" lib_opt_flags "-O3" check_opt_flags "-O2" -shared_flags "-fPIC -fvisibility=hidden" +shared_flags "-fPIC" debug_flags -g no_debug_flags "-finline-functions" -dll_import_flags '__attribute__((visibility("default")))' +visibility_build_flags "-fvisibility=hidden" +visibility_attribute '__attribute__((visibility("default")))' makefile_style unix @@ -33,53 +34,57 @@ aix -> "$(CXX) -shared -fPIC" darwin -> "$(CXX) -dynamiclib -fPIC -install_name $(LIBDIR)/$(SONAME)" hpux -> "$(CXX) -shared -fPIC -Wl,+h,$(SONAME)" solaris -> "$(CXX) -shared -fPIC -Wl,-h,$(SONAME)" -# Gotta use ld directly on BeOS, their GCC is busted -beos -> "ld -shared -h $(SONAME)" </so_link_flags> <mach_opt> -# Specializations first (they don't need to be, just clearer) -i386 -> "-mtune=i686 -momit-leaf-frame-pointer" -ppc601 -> "-mpowerpc -mcpu=601" +ppc601 -> "-mpowerpc -mcpu=601" +cellppu -> "-mcpu=cell" +e500v2 -> "-mcpu=8548" +atom32 -> "-march=atom -momit-leaf-frame-pointer" + +alpha-ev68 -> "-mcpu=ev67" +alpha-ev7 -> "-mcpu=ev67" + +# The patch from Debian bug 594159 has this, don't know why though... +sh4 -> "-m4 -mieee" + +# This is mostly for Debian's benefit +i486 -> "-mtune=generic -momit-leaf-frame-pointer" # Until GCC gets -march support for these models -nehalem -> "-march=core2 -msse4.1 -msse4.2" -westmere -> "-march=core2 -maes -msse4.1 -msse4.2" -atom -> "-march=i686 -msse2 -mssse3" -cellppu -> "" -alpha-ev68 -> "-mcpu=ev6" -alpha-ev7 -> "-mcpu=ev6" +nehalem -> "-march=core2 -msse4.1 -msse4.2 -momit-leaf-frame-pointer" +westmere -> "-march=core2 -maes -msse4.1 -msse4.2 -momit-leaf-frame-pointer" # Default family options (SUBMODEL is substitued with the real submodel) # Anything after the quotes is what should be *removed* from the submodel name # before it's put into SUBMODEL. alpha -> "-mcpu=SUBMODEL" alpha- -amd64 -> "-march=SUBMODEL -momit-leaf-frame-pointer" -arm -> "-mcpu=SUBMODEL" -ia32 -> "-march=SUBMODEL -momit-leaf-frame-pointer" -ia64 -> "-mtune=SUBMODEL" +arm -> "-march=SUBMODEL" +superh -> "-mSUBMODEL" sh hppa -> "-march=SUBMODEL" hppa +ia64 -> "-mtune=SUBMODEL" m68k -> "-mSUBMODEL" -hitachi-sh -> "-mSUBMODEL" hitachi-sh -sparc32 -> "-mcpu=SUBMODEL -Wa,-xarch=v8plus" sparc32- -sparc64 -> "-mcpu=v9 -mtune=SUBMODEL" mips32 -> "-mips1 -mcpu=SUBMODEL" mips32- mips64 -> "-mips3 -mcpu=SUBMODEL" mips64- -ppc -> "-mcpu=SUBMODEL" ppc +ppc32 -> "-mcpu=SUBMODEL" ppc ppc64 -> "-mcpu=SUBMODEL" ppc +sparc32 -> "-mcpu=SUBMODEL -Wa,-xarch=v8plus" sparc32- +sparc64 -> "-mcpu=v9 -mtune=SUBMODEL" +x86_32 -> "-march=SUBMODEL -momit-leaf-frame-pointer" +x86_64 -> "-march=SUBMODEL -momit-leaf-frame-pointer" </mach_opt> -# Note that the 'linking' bit means "use this for both compiling *and* linking" +# The 'linking' bit means "use this for both compiling *and* linking" <mach_abi_linking> all -> "-pthread" -amd64 -> "-m64" mips64 -> "-mabi=64" s390 -> "-m31" s390x -> "-m64" sparc32 -> "-m32 -mno-app-regs" sparc64 -> "-m64 -mno-app-regs" ppc64 -> "-m64" +x86_64 -> "-m64" netbsd -> "-D_NETBSD_SOURCE" qnx -> "-fexceptions -D_QNX_SOURCE" diff --git a/src/build-data/cc/icc.txt b/src/build-data/cc/icc.txt index 1aab4d111..e11875cb1 100644 --- a/src/build-data/cc/icc.txt +++ b/src/build-data/cc/icc.txt @@ -30,5 +30,5 @@ westmere -> "-march=core2" </mach_opt> <so_link_flags> -default -> "$(CXX) -fPIC -shared" +default -> "$(CXX) -fPIC -shared -Wl,-soname,$(SONAME)" </so_link_flags> diff --git a/src/build-data/cc/msvc.txt b/src/build-data/cc/msvc.txt index a854a576d..034ea7444 100644 --- a/src/build-data/cc/msvc.txt +++ b/src/build-data/cc/msvc.txt @@ -14,8 +14,8 @@ check_opt_flags "/O2 /D_CONSOLE" lang_flags "/EHs /GR" warning_flags "/W3 /wd4275 /wd4267" -shared_flags "/DBOTAN_DLL=__declspec(dllexport)" -dll_import_flags "__declspec(dllimport)" +visibility_build_flags "/DBOTAN_DLL=__declspec(dllexport)" +visibility_attribute "__declspec(dllimport)" ar_command lib diff --git a/src/build-data/cc/open64.txt b/src/build-data/cc/open64.txt index 34359ef63..52f35a7e8 100644 --- a/src/build-data/cc/open64.txt +++ b/src/build-data/cc/open64.txt @@ -23,5 +23,5 @@ default -> "$(CXX) -shared -Wl,-soname,$(SONAME)" </so_link_flags> <mach_abi_linking> -amd64 -> "-m64" +x86_64 -> "-m64" </mach_abi_linking> diff --git a/src/build-data/cc/pgi.txt b/src/build-data/cc/pgi.txt index 0e4f8baf2..985c534b9 100644 --- a/src/build-data/cc/pgi.txt +++ b/src/build-data/cc/pgi.txt @@ -24,5 +24,5 @@ i586 -> "-tp p5" i686 -> "-tp p6" athlon -> "-tp k7" pentium4 -> "-tp p6" -ia32 -> "-tp px" +x86_32 -> "-tp px" </mach_opt> diff --git a/src/build-data/cc/sunstudio.txt b/src/build-data/cc/sunstudio.txt index d0b25d144..43e5fcf8a 100644 --- a/src/build-data/cc/sunstudio.txt +++ b/src/build-data/cc/sunstudio.txt @@ -40,14 +40,18 @@ nehalem -> "-xtarget=nehalem" sparc32-v9 -> "-xchip=ultra -xarch=v8" +ultrasparc3 -> "-xchip=ultra3" +niagra1 -> "-xchip=ultraT1" +niagra2 -> "-xchip=ultraT2" + sparc32 -> "-xchip=ultra -xarch=SUBMODEL" sparc32- -sparc64 -> "-xchip=SUBMODEL" sparc64- +sparc64 -> "-xchip=generic" </mach_opt> <mach_abi_linking> # Needed on some Linux distros -#linux -> "-library=stlport4" +linux -> "-library=stlport4" sparc64 -> "-xarch=v9" -amd64 -> "-m64" +x86_64 -> "-m64" </mach_abi_linking> diff --git a/src/build-data/innosetup.in b/src/build-data/innosetup.in index 0a7eeb8f6..ed618e8fb 100644 --- a/src/build-data/innosetup.in +++ b/src/build-data/innosetup.in @@ -41,19 +41,19 @@ name: "docs"; Description: "Developer Documentation"; Types: devel ; DLL and license file is always included Source: "..\doc\license.txt"; DestDir: "{app}"; Components: dll; AfterInstall: ConvertLineEndings Source: "..\botan.dll"; DestDir: "{app}"; Components: dll -Source: "..\botan.dll.manifest"; DestDir: "{app}"; Components: dll +Source: "..\botan.dll.manifest"; DestDir: "{app}"; Components: dll; Flags: skipifsourcedoesntexist Source: "include\botan\*"; DestDir: "{app}\include\botan"; Components: includes; AfterInstall: ConvertLineEndings Source: "..\readme.txt"; DestDir: "{app}\doc"; Components: docs; AfterInstall: ConvertLineEndings -Source: "..\doc\log.txt"; DestDir: "{app}\doc"; Components: docs; AfterInstall: ConvertLineEndings +Source: "..\doc\*.txt"; DestDir: "{app}\doc"; Excludes: "license.txt"; Components: docs; AfterInstall: ConvertLineEndings Source: "..\doc\examples\*.cpp"; DestDir: "{app}\doc\examples"; Components: docs; AfterInstall: ConvertLineEndings Source: "..\botan.exp"; DestDir: "{app}"; Components: implib Source: "..\botan.lib"; DestDir: "{app}"; Components: implib -Source: "..\doc\api.pdf"; DestDir: "{app}\doc"; Components: docs; Flags: skipifsourcedoesntexist +Source: "..\doc\manual.pdf"; DestDir: "{app}\doc"; Components: docs; Flags: skipifsourcedoesntexist Source: "..\doc\tutorial.pdf"; DestDir: "{app}\doc"; Components: docs; Flags: skipifsourcedoesntexist [Code] diff --git a/src/build-data/makefile/nmake.in b/src/build-data/makefile/nmake.in index 9ca071da3..3e20d988a 100644 --- a/src/build-data/makefile/nmake.in +++ b/src/build-data/makefile/nmake.in @@ -17,6 +17,7 @@ DESTDIR = %{prefix} ### Aliases for Common Programs AR = %{ar_command} +COPY = copy CD = @cd ECHO = @echo INSTALL = %{install_cmd_exec} @@ -30,8 +31,6 @@ RMDIR = @rmdir ### File Lists CHECK = check -DOCS = %{doc_files} - HEADERS = %{include_files} LIBOBJS = %{lib_objs} @@ -67,6 +66,9 @@ $(BOTAN_LIB): $(LIBOBJS) !Endif ### Fake Targets +docs: +%{build_doc_commands} + clean: $(RM) %{build_dir}\lib\* %{build_dir}\checks\* $(RM) *.manifest *.exp *.dll diff --git a/src/build-data/makefile/unix.in b/src/build-data/makefile/unix.in index c525aa6bf..5290beda8 100644 --- a/src/build-data/makefile/unix.in +++ b/src/build-data/makefile/unix.in @@ -9,13 +9,14 @@ LINK_TO = %{link_to} # Version Numbers VERSION = %{version} +SERIES = %{version_major}.%{version_minor} # Installation Settings DESTDIR = %{prefix} BINDIR = $(DESTDIR)/bin LIBDIR = $(DESTDIR)/%{libdir} -HEADERDIR = $(DESTDIR)/%{includedir}/botan +HEADERDIR = $(DESTDIR)/%{includedir}/botan-$(SERIES)/botan DOCDIR = $(DESTDIR)/%{docdir}/botan-$(VERSION) PKGCONF_DIR = $(LIBDIR)/pkgconfig @@ -24,6 +25,8 @@ PKGCONFIG = %{botan_pkgconfig} # Aliases for Common Programs AR = %{ar_command} +COPY = cp +COPY_R = cp -r CD = @cd ECHO = @echo INSTALL_CMD_EXEC = %{install_cmd_exec} @@ -38,8 +41,6 @@ RM_R = @rm -rf # File Lists CHECK = %{check_prefix}check -DOCS = %{doc_files} - HEADERS = %{include_files} LIBOBJS = %{lib_objs} @@ -52,7 +53,7 @@ CHECK_FLAGS = $(CHECK_OPT) $(LANG_FLAGS) $(WARN_FLAGS) LIBRARIES = $(STATIC_LIB) LIBNAME = %{lib_prefix}libbotan -STATIC_LIB = $(LIBNAME).a +STATIC_LIB = $(LIBNAME)-$(SERIES).a all: $(LIBRARIES) @@ -63,7 +64,7 @@ all: $(LIBRARIES) # Link Commands $(CHECK): $(LIBRARIES) $(CHECKOBJS) - $(CXX) $(CHECKOBJS) -L. libbotan.a $(LINK_TO) -o $(CHECK) + $(CXX) $(CHECKOBJS) $(STATIC_LIB) $(LINK_TO) -o $(CHECK) $(STATIC_LIB): $(LIBOBJS) $(RM) $(STATIC_LIB) @@ -71,12 +72,12 @@ $(STATIC_LIB): $(LIBOBJS) $(RANLIB) $(STATIC_LIB) # Fake Targets -.PHONY = doxygen clean distclean install static +.PHONY = docs clean distclean install static static: $(STATIC_LIB) -doxygen: - doxygen %{build_dir}/botan.doxy +docs: +%{build_doc_commands} clean: $(RM_R) %{build_dir}/lib/* %{build_dir}/checks/* @@ -84,22 +85,24 @@ clean: distclean: clean $(RM_R) %{build_dir} - $(RM_R) %{doc_src_dir}/doxygen %{doc_src_dir}/botan.doxy $(RM) Makefile* $(CONFIG_SCRIPT) $(PKGCONFIG) + $(RM) botan_all.cpp botan_all.h -install: $(LIBRARIES) +install: $(LIBRARIES) docs $(ECHO) "Installing Botan into $(DESTDIR)... " $(MKDIR_INSTALL) $(DOCDIR) + $(COPY_R) %{doc_output_dir}/* $(DOCDIR) + $(MKDIR_INSTALL) $(HEADERDIR) - $(MKDIR_INSTALL) $(LIBDIR) - $(MKDIR_INSTALL) $(BINDIR) - $(MKDIR_INSTALL) $(PKGCONF_DIR) - for i in $(DOCS); do \ - $(INSTALL_CMD_DATA) $$i $(DOCDIR); \ - done for i in $(HEADERS); do \ $(INSTALL_CMD_DATA) $$i $(HEADERDIR); \ done + + $(MKDIR_INSTALL) $(LIBDIR) $(INSTALL_CMD_DATA) $(STATIC_LIB) $(LIBDIR) + + $(MKDIR_INSTALL) $(BINDIR) $(INSTALL_CMD_EXEC) $(CONFIG_SCRIPT) $(BINDIR) + + $(MKDIR_INSTALL) $(PKGCONF_DIR) $(INSTALL_CMD_DATA) $(PKGCONFIG) $(PKGCONF_DIR) diff --git a/src/build-data/makefile/unix_shr.in b/src/build-data/makefile/unix_shr.in index aaedeeaf8..31060afbb 100644 --- a/src/build-data/makefile/unix_shr.in +++ b/src/build-data/makefile/unix_shr.in @@ -11,14 +11,14 @@ LINK_TO = %{link_to} # Version Numbers VERSION = %{version} -SO_VERSION = %{so_version} +SERIES = %{version_major}.%{version_minor} # Installation Settings DESTDIR = %{prefix} BINDIR = $(DESTDIR)/bin LIBDIR = $(DESTDIR)/%{libdir} -HEADERDIR = $(DESTDIR)/%{includedir}/botan +HEADERDIR = $(DESTDIR)/%{includedir}/botan-$(SERIES)/botan DOCDIR = $(DESTDIR)/%{docdir}/botan-$(VERSION) PKGCONF_DIR = $(LIBDIR)/pkgconfig @@ -27,6 +27,8 @@ PKGCONFIG = %{botan_pkgconfig} # Aliases for Common Programs AR = %{ar_command} +COPY = cp +COPY_R = cp -r CD = @cd ECHO = @echo INSTALL_CMD_EXEC = %{install_cmd_exec} @@ -41,8 +43,6 @@ RM_R = @rm -rf # File Lists CHECK = %{check_prefix}check -DOCS = %{doc_files} - HEADERS = %{include_files} LIBOBJS = %{lib_objs} @@ -55,12 +55,12 @@ CHECK_FLAGS = $(CHECK_OPT) $(LANG_FLAGS) $(WARN_FLAGS) LIBRARIES = $(STATIC_LIB) $(SHARED_LIB) LIBNAME = %{lib_prefix}libbotan -STATIC_LIB = $(LIBNAME).a +STATIC_LIB = $(LIBNAME)-$(SERIES).a -SHARED_LIB = $(LIBNAME)-$(SO_VERSION).%{so_suffix} -SONAME = $(LIBNAME)-$(SO_VERSION).%{so_suffix} +SONAME = $(LIBNAME)-$(SERIES).%{so_suffix}.%{so_abi_rev} +SHARED_LIB = $(SONAME).%{version_patch} -SYMLINK = libbotan.%{so_suffix} +SYMLINK = $(LIBNAME)-$(SERIES).%{so_suffix} all: $(LIBRARIES) @@ -71,7 +71,7 @@ all: $(LIBRARIES) # Link Commands $(CHECK): $(LIBRARIES) $(CHECKOBJS) - $(CXX) $(LDFLAGS) $(CHECKOBJS) -o $(CHECK) -L. -lbotan-%{so_version} $(LINK_TO) + $(CXX) $(LDFLAGS) $(CHECKOBJS) $(SHARED_LIB) $(LINK_TO) -o $(CHECK) $(STATIC_LIB): $(LIBOBJS) $(RM) $(STATIC_LIB) @@ -80,42 +80,46 @@ $(STATIC_LIB): $(LIBOBJS) $(SHARED_LIB): $(LIBOBJS) $(SO_LINK_CMD) $(LDFLAGS) $(LIBOBJS) -o $(SHARED_LIB) $(LINK_TO) + $(LN) $(SHARED_LIB) $(SONAME) $(LN) $(SHARED_LIB) $(SYMLINK) # Fake Targets -.PHONY = doxygen clean distclean install static shared +.PHONY = docs clean distclean install static shared static: $(STATIC_LIB) shared: $(SHARED_LIB) -doxygen: - doxygen %{build_dir}/botan.doxy +docs: +%{build_doc_commands} clean: $(RM_R) %{build_dir}/lib/* %{build_dir}/checks/* - $(RM) $(LIBRARIES) $(SYMLINK) $(CHECK) + $(RM) $(LIBRARIES) $(SYMLINK) $(SONAME) $(CHECK) distclean: clean $(RM_R) %{build_dir} - $(RM_R) %{doc_src_dir}/doxygen %{doc_src_dir}/botan.doxy $(RM) Makefile* $(CONFIG_SCRIPT) $(PKGCONFIG) + $(RM) botan_all.cpp botan_all.h -install: $(LIBRARIES) +install: $(LIBRARIES) docs $(ECHO) "Installing Botan into $(DESTDIR)... " $(MKDIR_INSTALL) $(DOCDIR) + $(COPY_R) %{doc_output_dir}/* $(DOCDIR) + $(MKDIR_INSTALL) $(HEADERDIR) - $(MKDIR_INSTALL) $(LIBDIR) - $(MKDIR_INSTALL) $(BINDIR) - $(MKDIR_INSTALL) $(PKGCONF_DIR) - for i in $(DOCS); do \ - $(INSTALL_CMD_DATA) $$i $(DOCDIR); \ - done for i in $(HEADERS); do \ $(INSTALL_CMD_DATA) $$i $(HEADERDIR); \ done + + $(MKDIR_INSTALL) $(LIBDIR) $(INSTALL_CMD_DATA) $(STATIC_LIB) $(LIBDIR) - $(INSTALL_CMD_EXEC) $(CONFIG_SCRIPT) $(BINDIR) $(INSTALL_CMD_EXEC) $(SHARED_LIB) $(LIBDIR) - $(INSTALL_CMD_DATA) $(PKGCONFIG) $(PKGCONF_DIR) $(CD) $(LIBDIR); $(LN) $(SHARED_LIB) $(SYMLINK) + $(CD) $(LIBDIR); $(LN) $(SHARED_LIB) $(SONAME) + + $(MKDIR_INSTALL) $(BINDIR) + $(INSTALL_CMD_EXEC) $(CONFIG_SCRIPT) $(BINDIR) + + $(MKDIR_INSTALL) $(PKGCONF_DIR) + $(INSTALL_CMD_DATA) $(PKGCONFIG) $(PKGCONF_DIR) diff --git a/src/build-data/os/beos.txt b/src/build-data/os/beos.txt deleted file mode 100644 index 4a16b6326..000000000 --- a/src/build-data/os/beos.txt +++ /dev/null @@ -1,14 +0,0 @@ -os_type beos - -install_root /boot/beos -header_dir ../develop/headers -lib_dir system/lib -doc_dir documentation - -<target_features> -gettimeofday -</target_features> - -<aliases> -haiku -</aliases> diff --git a/src/build-data/os/haiku.txt b/src/build-data/os/haiku.txt new file mode 100644 index 000000000..8e35e76eb --- /dev/null +++ b/src/build-data/os/haiku.txt @@ -0,0 +1,15 @@ +os_type unix + +install_root /boot +header_dir develop/headers +lib_dir system/lib +doc_dir system/documentation + +<target_features> +gettimeofday +gmtime_r +</target_features> + +<aliases> +beos +</aliases> diff --git a/src/build-data/os/mingw.txt b/src/build-data/os/mingw.txt index 08f85b4db..5daabac90 100644 --- a/src/build-data/os/mingw.txt +++ b/src/build-data/os/mingw.txt @@ -14,9 +14,6 @@ header_dir include lib_dir lib doc_dir share/doc -install_cmd_data "install -m 644" -install_cmd_exec "install -m 755" - <aliases> msys mingw32 diff --git a/src/build-data/os/qnx.txt b/src/build-data/os/qnx.txt index 369b720c4..4c0965764 100644 --- a/src/build-data/os/qnx.txt +++ b/src/build-data/os/qnx.txt @@ -1,5 +1,9 @@ os_type unix <target_features> +clock_gettime gettimeofday +posix_mlock +gmtime_r +dlopen </target_features> diff --git a/src/build-data/os/solaris.txt b/src/build-data/os/solaris.txt index 47e7bccbc..0ed785036 100644 --- a/src/build-data/os/solaris.txt +++ b/src/build-data/os/solaris.txt @@ -1,5 +1,8 @@ os_type unix +install_cmd_data '/usr/ucb/install -m 644' +install_cmd_exec '/usr/ucb/install -m 755' + <target_features> posix_mlock gettimeofday diff --git a/src/cert/cvc/cvc_self.cpp b/src/cert/cvc/cvc_self.cpp index 4b6c5af8c..1646adeef 100644 --- a/src/cert/cvc/cvc_self.cpp +++ b/src/cert/cvc/cvc_self.cpp @@ -41,7 +41,7 @@ MemoryVector<byte> eac_1_1_encoding(const EC_PublicKey* key, if(key->domain_format() == EC_DOMPAR_ENC_OID) throw Encoding_Error("CVC encoder: cannot encode parameters by OID"); - const EC_Domain_Params& domain = key->domain(); + const EC_Group& domain = key->domain(); // This is why we can't have nice things diff --git a/src/cert/cvc/info.txt b/src/cert/cvc/info.txt index d6281802b..3cf759188 100644 --- a/src/cert/cvc/info.txt +++ b/src/cert/cvc/info.txt @@ -1,5 +1,5 @@ define CARD_VERIFIABLE_CERTIFICATES -load_on auto +load_on request <header:public> cvc_ado.h diff --git a/src/cert/x509ca/x509_ca.cpp b/src/cert/x509ca/x509_ca.cpp index b97b106f8..37b4f44b4 100644 --- a/src/cert/x509ca/x509_ca.cpp +++ b/src/cert/x509ca/x509_ca.cpp @@ -94,7 +94,7 @@ X509_Certificate X509_CA::make_cert(PK_Signer* signer, const Extensions& extensions) { const size_t X509_CERT_VERSION = 3; - const size_t SERIAL_BITS = 256; + const size_t SERIAL_BITS = 128; BigInt serial_no(rng, SERIAL_BITS); diff --git a/src/cert/x509cert/x509_ext.cpp b/src/cert/x509cert/x509_ext.cpp index 462b29669..6e0befaf3 100644 --- a/src/cert/x509cert/x509_ext.cpp +++ b/src/cert/x509cert/x509_ext.cpp @@ -443,6 +443,9 @@ class Policy_Information : public ASN1_Object public: OID oid; + Policy_Information() {} + Policy_Information(const OID& oid) : oid(oid) {} + void encode_into(DER_Encoder& codec) const { codec.start_cons(SEQUENCE) @@ -466,18 +469,16 @@ class Policy_Information : public ASN1_Object */ MemoryVector<byte> Certificate_Policies::encode_inner() const { - // FIXME -#if 1 - throw Internal_Error("Certificate_Policies::encode_inner: Bugged"); -#else std::vector<Policy_Information> policies; + for(size_t i = 0; i != oids.size(); ++i) + policies.push_back(oids[i]); + return DER_Encoder() .start_cons(SEQUENCE) .encode_list(policies) .end_cons() .get_contents(); -#endif } /* @@ -491,6 +492,10 @@ void Certificate_Policies::decode_inner(const MemoryRegion<byte>& in) .start_cons(SEQUENCE) .decode_list(policies) .end_cons(); + + oids.clear(); + for(size_t i = 0; i != policies.size(); ++i) + oids.push_back(policies[i].oid); } /* diff --git a/src/cert/x509cert/x509cert.cpp b/src/cert/x509cert/x509cert.cpp index 40b61b47d..1d7e51d08 100644 --- a/src/cert/x509cert/x509cert.cpp +++ b/src/cert/x509cert/x509cert.cpp @@ -390,8 +390,12 @@ std::string X509_Certificate::to_string() const OIDS::lookup(this->signature_algorithm().oid) << "\n"; out << "Serial number: " << hex_encode(this->serial_number()) << "\n"; - out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n"; - out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n"; + + if(this->authority_key_id().size()) + out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n"; + + if(this->subject_key_id().size()) + out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n"; X509_PublicKey* pubkey = this->subject_public_key(); out << "Public Key:\n" << X509::PEM_encode(*pubkey); diff --git a/src/cms/cms_algo.cpp b/src/cms/cms_algo.cpp index 50384d85a..3c245cc6f 100644 --- a/src/cms/cms_algo.cpp +++ b/src/cms/cms_algo.cpp @@ -99,7 +99,7 @@ SecureVector<byte> CMS_Encoder::wrap_key(RandomNumberGenerator& rng, throw Encoding_Error("CMS: 128-bit KEKs must be used with " + cipher); SecureVector<byte> lcekpad; - lcekpad.push_back((byte)cek.length()); + lcekpad.push_back(static_cast<byte>(cek.length())); lcekpad += cek.bits_of(); while(lcekpad.size() % 8) lcekpad.push_back(rng.next_byte()); diff --git a/src/cms/cms_dec.cpp b/src/cms/cms_dec.cpp index c86e1d0ae..a9f4e69d9 100644 --- a/src/cms/cms_dec.cpp +++ b/src/cms/cms_dec.cpp @@ -86,7 +86,9 @@ std::string CMS_Decoder::get_data() const { if(layer_type() != DATA) throw Invalid_State("CMS: Cannot retrieve data from non-DATA layer"); - return std::string((const char*)&data[0], data.size()); + + return std::string(reinterpret_cast<const char*>(&data[0]), + data.size()); } /* diff --git a/src/cms/cms_enc.cpp b/src/cms/cms_enc.cpp index cd739ef08..1a45a6a46 100644 --- a/src/cms/cms_enc.cpp +++ b/src/cms/cms_enc.cpp @@ -30,7 +30,7 @@ void CMS_Encoder::set_data(const byte buf[], size_t length) */ void CMS_Encoder::set_data(const std::string& str) { - set_data((const byte*)str.c_str(), str.length()); + set_data(reinterpret_cast<const byte*>(str.c_str()), str.length()); } /* diff --git a/src/cms/info.txt b/src/cms/info.txt index dc2110ae5..34e2c089c 100644 --- a/src/cms/info.txt +++ b/src/cms/info.txt @@ -1,5 +1,7 @@ define CMS +load_on request + <requires> asn1 bigint diff --git a/src/codec/base64/base64.cpp b/src/codec/base64/base64.cpp index d6c5ec7c0..6a53a7a9a 100644 --- a/src/codec/base64/base64.cpp +++ b/src/codec/base64/base64.cpp @@ -97,5 +97,155 @@ std::string base64_encode(const MemoryRegion<byte>& input) return base64_encode(&input[0], input.size()); } +size_t base64_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws) + { + /* + * Base64 Decoder Lookup Table + * Warning: assumes ASCII encodings + */ + static const byte BASE64_TO_BIN[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, + 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, + 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + byte* out_ptr = output; + byte decode_buf[4]; + size_t decode_buf_pos = 0; + size_t final_truncate = 0; + + clear_mem(output, input_length * 3 / 4); + + for(size_t i = 0; i != input_length; ++i) + { + const byte bin = BASE64_TO_BIN[static_cast<byte>(input[i])]; + + if(bin <= 0x3F) + { + decode_buf[decode_buf_pos] = bin; + decode_buf_pos += 1; + } + else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) + { + std::string bad_char(1, input[i]); + if(bad_char == "\t") + bad_char = "\\t"; + else if(bad_char == "\n") + bad_char = "\\n"; + else if(bad_char == "\r") + bad_char = "\\r"; + + throw std::invalid_argument( + std::string("base64_decode: invalid base64 character '") + + bad_char + "'"); + } + + /* + * If we're at the end of the input, pad with 0s and truncate + */ + if(final_inputs && (i == input_length - 1)) + { + if(decode_buf_pos) + { + for(size_t i = decode_buf_pos; i != 4; ++i) + decode_buf[i] = 0; + final_truncate = (4 - decode_buf_pos); + decode_buf_pos = 4; + } + } + + if(decode_buf_pos == 4) + { + out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4); + out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2); + out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3]; + + out_ptr += 3; + decode_buf_pos = 0; + input_consumed = i+1; + } + } + + while(input_consumed < input_length && + BASE64_TO_BIN[static_cast<byte>(input[input_consumed])] == 0x80) + { + ++input_consumed; + } + + size_t written = (out_ptr - output) - final_truncate; + + return written; + } + +size_t base64_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws) + { + size_t consumed = 0; + size_t written = base64_decode(output, input, input_length, + consumed, true, ignore_ws); + + if(consumed != input_length) + throw std::invalid_argument("base64_decode: input did not have full bytes"); + + return written; + } + +size_t base64_decode(byte output[], + const std::string& input, + bool ignore_ws) + { + return base64_decode(output, &input[0], input.length(), ignore_ws); + } + +SecureVector<byte> base64_decode(const char input[], + size_t input_length, + bool ignore_ws) + { + SecureVector<byte> bin((round_up<size_t>(input_length, 4) * 3) / 4); + + size_t written = base64_decode(&bin[0], + input, + input_length, + ignore_ws); + + bin.resize(written); + return bin; + } + +SecureVector<byte> base64_decode(const std::string& input, + bool ignore_ws) + { + return base64_decode(&input[0], input.size(), ignore_ws); + } + } diff --git a/src/codec/base64/base64.h b/src/codec/base64/base64.h index 6daac73d8..23a2558bd 100644 --- a/src/codec/base64/base64.h +++ b/src/codec/base64/base64.h @@ -48,6 +48,76 @@ std::string BOTAN_DLL base64_encode(const byte input[], */ std::string BOTAN_DLL base64_encode(const MemoryRegion<byte>& input); +/** +* Perform base64 decoding +* @param output an array of at least input_length*3/4 bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param input_consumed is an output parameter which says how many +* bytes of input were actually consumed. If less than +* input_length, then the range input[consumed:length] +* should be passed in later along with more input. +* @param final_inputs true iff this is the last input, in which case + padding is allowed +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const char input[], + size_t input_length, + size_t& input_consumed, + bool final_inputs, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least input_length*3/4 bytes +* @param input some base64 input +* @param input_length length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param output an array of at least input_length/3*4 bytes +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return number of bytes written to output +*/ +size_t BOTAN_DLL base64_decode(byte output[], + const std::string& input, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param input_length the length of input in bytes +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +SecureVector<byte> BOTAN_DLL base64_decode(const char input[], + size_t input_length, + bool ignore_ws = true); + +/** +* Perform base64 decoding +* @param input some base64 input +* @param ignore_ws ignore whitespace on input; if false, throw an + exception if whitespace is encountered +* @return decoded base64 output +*/ +SecureVector<byte> BOTAN_DLL base64_decode(const std::string& input, + bool ignore_ws = true); + } #endif diff --git a/src/codec/hex/hex.cpp b/src/codec/hex/hex.cpp index 596e0e235..41ba1298d 100644 --- a/src/codec/hex/hex.cpp +++ b/src/codec/hex/hex.cpp @@ -37,9 +37,7 @@ void hex_encode(char output[], std::string hex_encode(const MemoryRegion<byte>& input, bool uppercase) { - return hex_encode(&input[0], - input.size(), - uppercase); + return hex_encode(&input[0], input.size(), uppercase); } std::string hex_encode(const byte input[], @@ -47,7 +45,10 @@ std::string hex_encode(const byte input[], bool uppercase) { std::string output(2 * input_length, 0); - hex_encode(&output[0], input, input_length, uppercase); + + if(input_length) + hex_encode(&output[0], input, input_length, uppercase); + return output; } @@ -101,7 +102,7 @@ size_t hex_decode(byte output[], for(size_t i = 0; i != input_length; ++i) { - const byte bin = HEX_TO_BIN[(byte)input[i]]; + const byte bin = HEX_TO_BIN[static_cast<byte>(input[i])]; if(bin >= 0x10) { diff --git a/src/constructs/fpe/fpe.cpp b/src/constructs/fpe_fe1/fpe_fe1.cpp index 1023b067c..91d328c17 100644 --- a/src/constructs/fpe/fpe.cpp +++ b/src/constructs/fpe_fe1/fpe_fe1.cpp @@ -8,7 +8,7 @@ * Distributed under the terms of the Botan license */ -#include <botan/fpe.h> +#include <botan/fpe_fe1.h> #include <botan/numthry.h> #include <botan/hmac.h> #include <botan/sha2_32.h> @@ -16,6 +16,8 @@ namespace Botan { +namespace FPE { + namespace { // Normally FPE is for SSNs, CC#s, etc, nothing too big @@ -105,10 +107,10 @@ FPE_Encryptor::FPE_Encryptor(const SymmetricKey& key, if(n_bin.size() > MAX_N_BYTES) throw std::runtime_error("N is too large for FPE encryption"); - mac->update_be((u32bit)n_bin.size()); + mac->update_be(static_cast<u32bit>(n_bin.size())); mac->update(&n_bin[0], n_bin.size()); - mac->update_be((u32bit)tweak.size()); + mac->update_be(static_cast<u32bit>(tweak.size())); mac->update(&tweak[0], tweak.size()); mac_n_t = mac->final(); @@ -119,9 +121,9 @@ BigInt FPE_Encryptor::operator()(size_t round_no, const BigInt& R) SecureVector<byte> r_bin = BigInt::encode(R); mac->update(mac_n_t); - mac->update_be((u32bit)round_no); + mac->update_be(static_cast<u32bit>(round_no)); - mac->update_be((u32bit)r_bin.size()); + mac->update_be(static_cast<u32bit>(r_bin.size())); mac->update(&r_bin[0], r_bin.size()); SecureVector<byte> X = mac->final(); @@ -133,7 +135,7 @@ BigInt FPE_Encryptor::operator()(size_t round_no, const BigInt& R) /* * Generic Z_n FPE encryption, FE1 scheme */ -BigInt fpe_encrypt(const BigInt& n, const BigInt& X0, +BigInt fe1_encrypt(const BigInt& n, const BigInt& X0, const SymmetricKey& key, const MemoryRegion<byte>& tweak) { @@ -161,7 +163,7 @@ BigInt fpe_encrypt(const BigInt& n, const BigInt& X0, /* * Generic Z_n FPE decryption, FD1 scheme */ -BigInt fpe_decrypt(const BigInt& n, const BigInt& X0, +BigInt fe1_decrypt(const BigInt& n, const BigInt& X0, const SymmetricKey& key, const MemoryRegion<byte>& tweak) { @@ -187,3 +189,5 @@ BigInt fpe_decrypt(const BigInt& n, const BigInt& X0, } } + +} diff --git a/src/constructs/fpe/fpe.h b/src/constructs/fpe_fe1/fpe_fe1.h index 7a4a7861a..da9a6bcb6 100644 --- a/src/constructs/fpe/fpe.h +++ b/src/constructs/fpe_fe1/fpe_fe1.h @@ -1,18 +1,20 @@ /* -* Format Preserving Encryption +* Format Preserving Encryption (FE1 scheme) * (C) 2009 Jack Lloyd * * Distributed under the terms of the Botan license */ -#ifndef BOTAN_FORMAT_PRESERVING_ENCRYPTION_H__ -#define BOTAN_FORMAT_PRESERVING_ENCRYPTION_H__ +#ifndef BOTAN_FPE_FE1_H__ +#define BOTAN_FPE_FE1_H__ #include <botan/bigint.h> #include <botan/symkey.h> namespace Botan { +namespace FPE { + /** * Encrypt X from and onto the group Z_n using key and tweak * @param n the modulus @@ -20,7 +22,7 @@ namespace Botan { * @param key a random key * @param tweak will modify the ciphertext (think of as an IV) */ -BigInt BOTAN_DLL fpe_encrypt(const BigInt& n, const BigInt& X, +BigInt BOTAN_DLL fe1_encrypt(const BigInt& n, const BigInt& X, const SymmetricKey& key, const MemoryRegion<byte>& tweak); @@ -31,10 +33,12 @@ BigInt BOTAN_DLL fpe_encrypt(const BigInt& n, const BigInt& X, * @param key is the key used for encryption * @param tweak the same tweak used for encryption */ -BigInt BOTAN_DLL fpe_decrypt(const BigInt& n, const BigInt& X, +BigInt BOTAN_DLL fe1_decrypt(const BigInt& n, const BigInt& X, const SymmetricKey& key, const MemoryRegion<byte>& tweak); } +} + #endif diff --git a/src/constructs/fpe/info.txt b/src/constructs/fpe_fe1/info.txt index 078eb2135..33b5a1c80 100644 --- a/src/constructs/fpe/info.txt +++ b/src/constructs/fpe_fe1/info.txt @@ -1,4 +1,4 @@ -define FORMAT_PRESERVING_ENCRYPTION +define FPE_FE1 <requires> hmac diff --git a/src/engine/aes_isa_eng/aes_isa_engine.cpp b/src/engine/aes_isa_eng/aes_isa_engine.cpp index 7f541d583..e56f6e9ca 100644 --- a/src/engine/aes_isa_eng/aes_isa_engine.cpp +++ b/src/engine/aes_isa_eng/aes_isa_engine.cpp @@ -8,8 +8,8 @@ #include <botan/internal/aes_isa_engine.h> #include <botan/cpuid.h> -#if defined(BOTAN_HAS_AES_INTEL) - #include <botan/aes_intel.h> +#if defined(BOTAN_HAS_AES_NI) + #include <botan/aes_ni.h> #endif namespace Botan { @@ -18,15 +18,15 @@ BlockCipher* AES_ISA_Engine::find_block_cipher(const SCAN_Name& request, Algorithm_Factory&) const { -#if defined(BOTAN_HAS_AES_INTEL) +#if defined(BOTAN_HAS_AES_NI) if(CPUID::has_aes_ni()) { if(request.algo_name() == "AES-128") - return new AES_128_Intel; + return new AES_128_NI; if(request.algo_name() == "AES-192") - return new AES_192_Intel; + return new AES_192_NI; if(request.algo_name() == "AES-256") - return new AES_256_Intel; + return new AES_256_NI; } #endif diff --git a/src/engine/asm_engine/asm_engine.cpp b/src/engine/asm_engine/asm_engine.cpp index 747e8c00f..6d475136f 100644 --- a/src/engine/asm_engine/asm_engine.cpp +++ b/src/engine/asm_engine/asm_engine.cpp @@ -7,24 +7,24 @@ #include <botan/internal/asm_engine.h> -#if defined(BOTAN_HAS_SERPENT_IA32) - #include <botan/serp_ia32.h> +#if defined(BOTAN_HAS_SERPENT_X86_32) + #include <botan/serp_x86_32.h> #endif -#if defined(BOTAN_HAS_MD4_IA32) - #include <botan/md4_ia32.h> +#if defined(BOTAN_HAS_MD4_X86_32) + #include <botan/md4_x86_32.h> #endif -#if defined(BOTAN_HAS_MD5_IA32) - #include <botan/md5_ia32.h> +#if defined(BOTAN_HAS_MD5_X86_32) + #include <botan/md5_x86_32.h> #endif -#if defined(BOTAN_HAS_SHA1_AMD64) - #include <botan/sha1_amd64.h> +#if defined(BOTAN_HAS_SHA1_X86_64) + #include <botan/sha1_x86_64.h> #endif -#if defined(BOTAN_HAS_SHA1_IA32) - #include <botan/sha1_ia32.h> +#if defined(BOTAN_HAS_SHA1_X86_32) + #include <botan/sha1_x86_32.h> #endif namespace Botan { @@ -35,8 +35,8 @@ Assembler_Engine::find_block_cipher(const SCAN_Name& request, { if(request.algo_name() == "Serpent") { -#if defined(BOTAN_HAS_SERPENT_IA32) - return new Serpent_IA32; +#if defined(BOTAN_HAS_SERPENT_X86_32) + return new Serpent_X86_32; #endif } @@ -47,24 +47,24 @@ HashFunction* Assembler_Engine::find_hash(const SCAN_Name& request, Algorithm_Factory&) const { -#if defined(BOTAN_HAS_MD4_IA32) +#if defined(BOTAN_HAS_MD4_X86_32) if(request.algo_name() == "MD4") - return new MD4_IA32; + return new MD4_X86_32; #endif -#if defined(BOTAN_HAS_MD5_IA32) +#if defined(BOTAN_HAS_MD5_X86_32) if(request.algo_name() == "MD5") - return new MD5_IA32; + return new MD5_X86_32; #endif if(request.algo_name() == "SHA-160") - { -#if defined(BOTAN_HAS_SHA1_AMD64) - return new SHA_160_AMD64; -#elif defined(BOTAN_HAS_SHA1_IA32) - return new SHA_160_IA32; + { +#if defined(BOTAN_HAS_SHA1_X86_64) + return new SHA_160_X86_64; +#elif defined(BOTAN_HAS_SHA1_X86_32) + return new SHA_160_X86_32; #endif - } + } return 0; } diff --git a/src/engine/asm_engine/asm_engine.h b/src/engine/asm_engine/asm_engine.h index e3e9a546c..bd82566d3 100644 --- a/src/engine/asm_engine/asm_engine.h +++ b/src/engine/asm_engine/asm_engine.h @@ -5,8 +5,8 @@ * Distributed under the terms of the Botan license */ -#ifndef BOTAN_IA32_ASM_ENGINE_H__ -#define BOTAN_IA32_ASM_ENGINE_H__ +#ifndef BOTAN_X86_32_ASM_ENGINE_H__ +#define BOTAN_X86_32_ASM_ENGINE_H__ #include <botan/engine.h> diff --git a/src/engine/simd_engine/info.txt b/src/engine/simd_engine/info.txt index cddb7524a..229b1daaf 100644 --- a/src/engine/simd_engine/info.txt +++ b/src/engine/simd_engine/info.txt @@ -9,3 +9,7 @@ simd_engine.cpp <header:internal> simd_engine.h </header:internal> + +<requires> +simd +</requires> diff --git a/src/entropy/beos_stats/es_beos.cpp b/src/entropy/beos_stats/es_beos.cpp index 2b4a7a24f..e514eb121 100644 --- a/src/entropy/beos_stats/es_beos.cpp +++ b/src/entropy/beos_stats/es_beos.cpp @@ -26,8 +26,6 @@ void BeOS_EntropySource::poll(Entropy_Accumulator& accum) get_key_info(&info_key); accum.add(info_key, 0); - accum.add(idle_time(), 0); - team_info info_team; int32 cookie_team = 0; diff --git a/src/entropy/beos_stats/info.txt b/src/entropy/beos_stats/info.txt index 088b926f9..c7ed9fe5a 100644 --- a/src/entropy/beos_stats/info.txt +++ b/src/entropy/beos_stats/info.txt @@ -9,9 +9,9 @@ es_beos.h </header:internal> <os> -beos +haiku </os> <libs> -beos -> root,be +haiku -> root,be </libs> diff --git a/src/entropy/dev_random/dev_random.cpp b/src/entropy/dev_random/dev_random.cpp index b15240aba..d14ae43ae 100644 --- a/src/entropy/dev_random/dev_random.cpp +++ b/src/entropy/dev_random/dev_random.cpp @@ -12,6 +12,7 @@ #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> +#include <string.h> namespace Botan { diff --git a/src/entropy/dev_random/info.txt b/src/entropy/dev_random/info.txt index cabb47ea2..4c69a57f4 100644 --- a/src/entropy/dev_random/info.txt +++ b/src/entropy/dev_random/info.txt @@ -10,11 +10,11 @@ dev_random.h <os> aix -beos cygwin darwin -freebsd dragonfly +freebsd +haiku hpux hurd irix diff --git a/src/entropy/egd/es_egd.cpp b/src/entropy/egd/es_egd.cpp index d2ce2706b..b2b629930 100644 --- a/src/entropy/egd/es_egd.cpp +++ b/src/entropy/egd/es_egd.cpp @@ -89,7 +89,7 @@ size_t EGD_EntropySource::EGD_Socket::read(byte outbuf[], size_t length) throw std::runtime_error("Reading response length from EGD failed"); if(out_len > egd_read_command[1]) - throw std::runtime_error("Bogus length field recieved from EGD"); + throw std::runtime_error("Bogus length field received from EGD"); ssize_t count = ::read(m_fd, outbuf, out_len); diff --git a/src/entropy/hres_timer/hres_timer.cpp b/src/entropy/hres_timer/hres_timer.cpp index b0f99170a..a10cdaf46 100644 --- a/src/entropy/hres_timer/hres_timer.cpp +++ b/src/entropy/hres_timer/hres_timer.cpp @@ -32,13 +32,13 @@ void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum) #if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) if(CPUID::has_rdtsc()) // not availble on all x86 CPUs { - size_t rtc_low = 0, rtc_high = 0; + u32bit rtc_low = 0, rtc_high = 0; asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low)); rtc = (static_cast<u64bit>(rtc_high) << 32) | rtc_low; } #elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) - size_t rtc_low = 0, rtc_high = 0; + u32bit rtc_low = 0, rtc_high = 0; asm volatile("mftbu %0; mftb %1" : "=r" (rtc_high), "=r" (rtc_low)); rtc = (static_cast<u64bit>(rtc_high) << 32) | rtc_low; diff --git a/src/entropy/unix_procs/info.txt b/src/entropy/unix_procs/info.txt index 2100584e4..d2a15f13d 100644 --- a/src/entropy/unix_procs/info.txt +++ b/src/entropy/unix_procs/info.txt @@ -13,10 +13,10 @@ unix_cmd.h <os> aix -beos cygwin darwin -#freebsd +freebsd +haiku hpux irix linux diff --git a/src/entropy/unix_procs/unix_cmd.cpp b/src/entropy/unix_procs/unix_cmd.cpp index f4ae5054c..930444075 100644 --- a/src/entropy/unix_procs/unix_cmd.cpp +++ b/src/entropy/unix_procs/unix_cmd.cpp @@ -12,6 +12,7 @@ #include <sys/time.h> #include <sys/types.h> #include <sys/wait.h> +#include <string.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> diff --git a/src/filters/codec_filt/b64_filt.cpp b/src/filters/codec_filt/b64_filt.cpp index 8a90f8b5f..9341571d4 100644 --- a/src/filters/codec_filt/b64_filt.cpp +++ b/src/filters/codec_filt/b64_filt.cpp @@ -14,32 +14,6 @@ namespace Botan { /* -* Base64 Decoder Lookup Table -* Warning: assumes ASCII encodings -*/ -static const byte BASE64_TO_BIN[256] = { -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, 0x34, 0x35, 0x36, 0x37, -0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, -0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, -0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, -0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; - -/* * Base64_Encoder Constructor */ Base64_Encoder::Base64_Encoder(bool breaks, size_t length, bool t_n) : @@ -68,6 +42,7 @@ void Base64_Encoder::encode_and_send(const byte input[], size_t length, do_output(&out[0], produced); + // FIXME: s/proc/consumed/? input += proc; length -= proc; } @@ -138,58 +113,9 @@ void Base64_Encoder::end_msg() /* * Base64_Decoder Constructor */ -Base64_Decoder::Base64_Decoder(Decoder_Checking c) : checking(c) - { - in.resize(48); - out.resize(3); - position = 0; - } - -/* -* Check if a character is a valid Base64 char -*/ -bool Base64_Decoder::is_valid(byte in) - { - return (BASE64_TO_BIN[in] != 0x80); - } - -/* -* Base64 Decoding Operation -*/ -void Base64_Decoder::decode(const byte in[4], byte out[3]) - { - out[0] = ((BASE64_TO_BIN[in[0]] << 2) | (BASE64_TO_BIN[in[1]] >> 4)); - out[1] = ((BASE64_TO_BIN[in[1]] << 4) | (BASE64_TO_BIN[in[2]] >> 2)); - out[2] = ((BASE64_TO_BIN[in[2]] << 6) | (BASE64_TO_BIN[in[3]])); - } - -/* -* Decode and send a block -*/ -void Base64_Decoder::decode_and_send(const byte block[], size_t length) - { - for(size_t i = 0; i != length; i += 4) - { - decode(block + i, &out[0]); - send(out, 3); - } - } - -/* -* Handle processing an invalid character -*/ -void Base64_Decoder::handle_bad_char(byte c) +Base64_Decoder::Base64_Decoder(Decoder_Checking c) : + checking(c), in(64), out(48), position(0) { - if(c == '=' || checking == NONE) - return; - - if((checking == IGNORE_WS) && Charset::is_space(c)) - return; - - throw Decoding_Error( - std::string("Base64_Decoder: Invalid base64 character '") + - static_cast<char>(c) + "'" - ); } /* @@ -197,18 +123,32 @@ void Base64_Decoder::handle_bad_char(byte c) */ void Base64_Decoder::write(const byte input[], size_t length) { - for(size_t i = 0; i != length; ++i) + while(length) { - if(is_valid(input[i])) - in[position++] = input[i]; - else - handle_bad_char(input[i]); + size_t to_copy = std::min<size_t>(length, in.size() - position); + copy_mem(&in[position], input, to_copy); + position += to_copy; + + size_t consumed = 0; + size_t written = base64_decode(&out[0], + reinterpret_cast<const char*>(&in[0]), + position, + consumed, + false, + checking != FULL_CHECK); + + send(out, written); - if(position == in.size()) + if(consumed != position) { - decode_and_send(&in[0], in.size()); - position = 0; + copy_mem(&in[0], &in[consumed], position - consumed); + position = position - consumed; } + else + position = 0; + + length -= to_copy; + input += to_copy; } } @@ -217,21 +157,22 @@ void Base64_Decoder::write(const byte input[], size_t length) */ void Base64_Decoder::end_msg() { - if(position != 0) - { - size_t start_of_last_block = 4 * (position / 4), - left_over = position % 4; - decode_and_send(&in[0], start_of_last_block); + size_t consumed = 0; + size_t written = base64_decode(&out[0], + reinterpret_cast<const char*>(&in[0]), + position, + consumed, + true, + checking != FULL_CHECK); + + send(out, written); + + const bool not_full_bytes = consumed != position; - if(left_over) - { - SecureVector<byte> remainder(4); - copy_mem(&remainder[0], &in[start_of_last_block], left_over); - decode(&remainder[0], &out[0]); - send(out, ((left_over == 1) ? (1) : (left_over - 1))); - } - } position = 0; + + if(not_full_bytes) + throw std::invalid_argument("Base64_Decoder: Input not full bytes"); } } diff --git a/src/filters/codec_filt/b64_filt.h b/src/filters/codec_filt/b64_filt.h index df3896666..afff53f30 100644 --- a/src/filters/codec_filt/b64_filt.h +++ b/src/filters/codec_filt/b64_filt.h @@ -47,7 +47,7 @@ class BOTAN_DLL Base64_Encoder : public Filter const size_t line_length; const bool trailing_newline; - SecureVector<byte> in, out; + MemoryVector<byte> in, out; size_t position, out_position; }; @@ -78,14 +78,8 @@ class BOTAN_DLL Base64_Decoder : public Filter */ Base64_Decoder(Decoder_Checking checking = NONE); private: - static void decode(const byte input[4], byte output[3]); - static bool is_valid(byte c); - - void decode_and_send(const byte[], size_t); - void handle_bad_char(byte); - const Decoder_Checking checking; - SecureVector<byte> in, out; + MemoryVector<byte> in, out; size_t position; }; diff --git a/src/filters/codec_filt/hex_filt.h b/src/filters/codec_filt/hex_filt.h index cfbb818d3..0dc38c804 100644 --- a/src/filters/codec_filt/hex_filt.h +++ b/src/filters/codec_filt/hex_filt.h @@ -49,7 +49,7 @@ class BOTAN_DLL Hex_Encoder : public Filter const Case casing; const size_t line_length; - SecureVector<byte> in, out; + MemoryVector<byte> in, out; size_t position, counter; }; @@ -72,7 +72,7 @@ class BOTAN_DLL Hex_Decoder : public Filter Hex_Decoder(Decoder_Checking checking = NONE); private: const Decoder_Checking checking; - SecureVector<byte> in, out; + MemoryVector<byte> in, out; size_t position; }; diff --git a/src/filters/fd_unix/info.txt b/src/filters/fd_unix/info.txt index 9c3d0acbc..d636035f0 100644 --- a/src/filters/fd_unix/info.txt +++ b/src/filters/fd_unix/info.txt @@ -4,11 +4,11 @@ load_on auto <os> aix -beos cygwin darwin -freebsd dragonfly +freebsd +haiku hpux irix linux diff --git a/src/hash/bmw/bmw_512.cpp b/src/hash/bmw_512/bmw_512.cpp index 40338fdf0..40338fdf0 100644 --- a/src/hash/bmw/bmw_512.cpp +++ b/src/hash/bmw_512/bmw_512.cpp diff --git a/src/hash/bmw/bmw_512.h b/src/hash/bmw_512/bmw_512.h index 474b607bb..474b607bb 100644 --- a/src/hash/bmw/bmw_512.h +++ b/src/hash/bmw_512/bmw_512.h diff --git a/src/hash/bmw/info.txt b/src/hash/bmw_512/info.txt index 7170223d7..7170223d7 100644 --- a/src/hash/bmw/info.txt +++ b/src/hash/bmw_512/info.txt diff --git a/src/hash/md4_ia32/info.txt b/src/hash/md4_x86_32/info.txt index 5d14188f2..fdc534df4 100644 --- a/src/hash/md4_ia32/info.txt +++ b/src/hash/md4_x86_32/info.txt @@ -1,12 +1,12 @@ -define MD4_IA32 +define MD4_X86_32 load_on asm_ok <arch> -ia32 +x86_32 </arch> <requires> -asm_ia32 +asm_x86_32 md4 </requires> diff --git a/src/hash/md4_ia32/md4_ia32.cpp b/src/hash/md4_x86_32/md4_x86_32.cpp index 98d3c7a19..750e65a95 100644 --- a/src/hash/md4_ia32/md4_ia32.cpp +++ b/src/hash/md4_x86_32/md4_x86_32.cpp @@ -1,32 +1,32 @@ /* -* MD4 (IA-32) +* MD4 (x86-32) * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/md4_ia32.h> +#include <botan/md4_x86_32.h> namespace Botan { /** -* MD4 compression function in IA-32 asm +* MD4 compression function in x86-32 asm * @param digest the current digest * @param input the input block * @param M the message buffer */ -extern "C" void botan_md4_ia32_compress(u32bit digest[4], +extern "C" void botan_md4_x86_32_compress(u32bit digest[4], const byte input[64], u32bit M[16]); /* * MD4 Compression Function */ -void MD4_IA32::compress_n(const byte input[], size_t blocks) +void MD4_X86_32::compress_n(const byte input[], size_t blocks) { for(size_t i = 0; i != blocks; ++i) { - botan_md4_ia32_compress(digest, input, M); + botan_md4_x86_32_compress(digest, input, M); input += hash_block_size(); } } diff --git a/src/hash/md4_ia32/md4_ia32.h b/src/hash/md4_x86_32/md4_x86_32.h index 4bb8f1add..a9f23e94f 100644 --- a/src/hash/md4_ia32/md4_ia32.h +++ b/src/hash/md4_x86_32/md4_x86_32.h @@ -1,12 +1,12 @@ /* -* MD4 (IA-32) +* MD4 (x86-32) * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#ifndef BOTAN_MD4_IA32_H__ -#define BOTAN_MD4_IA32_H__ +#ifndef BOTAN_MD4_X86_32_H__ +#define BOTAN_MD4_X86_32_H__ #include <botan/md4.h> @@ -15,10 +15,10 @@ namespace Botan { /** * MD4 using x86 assembly */ -class BOTAN_DLL MD4_IA32 : public MD4 +class BOTAN_DLL MD4_X86_32 : public MD4 { public: - HashFunction* clone() const { return new MD4_IA32; } + HashFunction* clone() const { return new MD4_X86_32; } private: void compress_n(const byte[], size_t blocks); }; diff --git a/src/hash/md4_ia32/md4_ia32_imp.S b/src/hash/md4_x86_32/md4_x86_32_imp.S index c7e108147..192751166 100644 --- a/src/hash/md4_ia32/md4_ia32_imp.S +++ b/src/hash/md4_x86_32/md4_x86_32_imp.S @@ -1,15 +1,15 @@ /* -* MD4 in IA-32 assembler +* MD4 in x86-32 assembler * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/internal/asm_macr_ia32.h> +#include <botan/internal/asm_x86_32.h> -START_LISTING(md4_ia32.S) +START_LISTING(md4_x86_32_imp.S) -START_FUNCTION(botan_md4_ia32_compress) +START_FUNCTION(botan_md4_x86_32_compress) SPILL_REGS() #define PUSHED 4 @@ -134,4 +134,4 @@ LOOP_UNTIL_EQ(ESI, 16, .LOAD_INPUT) ADD(ARRAY4(EBP, 3), EDX) RESTORE_REGS() -END_FUNCTION(botan_md4_ia32_compress) +END_FUNCTION(botan_md4_x86_32_compress) diff --git a/src/hash/md5_ia32/info.txt b/src/hash/md5_x86_32/info.txt index 9be698a3f..adec65f81 100644 --- a/src/hash/md5_ia32/info.txt +++ b/src/hash/md5_x86_32/info.txt @@ -1,12 +1,12 @@ -define MD5_IA32 +define MD5_X86_32 load_on asm_ok <arch> -ia32 +x86_32 </arch> <requires> -asm_ia32 +asm_x86_32 md5 </requires> diff --git a/src/hash/md5_ia32/md5_ia32.cpp b/src/hash/md5_x86_32/md5_x86_32.cpp index 6ae235d2b..123fcff77 100644 --- a/src/hash/md5_ia32/md5_ia32.cpp +++ b/src/hash/md5_x86_32/md5_x86_32.cpp @@ -1,29 +1,29 @@ /* -* MD5 (IA-32) +* MD5 (x86-32) * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/md5_ia32.h> +#include <botan/md5_x86_32.h> namespace Botan { namespace { extern "C" -void botan_md5_ia32_compress(u32bit[4], const byte[64], u32bit[16]); +void botan_md5_x86_32_compress(u32bit[4], const byte[64], u32bit[16]); } /* * MD5 Compression Function */ -void MD5_IA32::compress_n(const byte input[], size_t blocks) +void MD5_X86_32::compress_n(const byte input[], size_t blocks) { for(size_t i = 0; i != blocks; ++i) { - botan_md5_ia32_compress(digest, input, M); + botan_md5_x86_32_compress(digest, input, M); input += hash_block_size(); } } diff --git a/src/hash/md5_ia32/md5_ia32.h b/src/hash/md5_x86_32/md5_x86_32.h index bf4b4c505..0150249ae 100644 --- a/src/hash/md5_ia32/md5_ia32.h +++ b/src/hash/md5_x86_32/md5_x86_32.h @@ -1,12 +1,12 @@ /* -* MD5 (IA-32) +* MD5 (x86-32) * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#ifndef BOTAN_MD5_IA32_H__ -#define BOTAN_MD5_IA32_H__ +#ifndef BOTAN_MD5_X86_32_H__ +#define BOTAN_MD5_X86_32_H__ #include <botan/md5.h> @@ -15,10 +15,10 @@ namespace Botan { /** * MD5 in x86 assembly */ -class BOTAN_DLL MD5_IA32 : public MD5 +class BOTAN_DLL MD5_X86_32 : public MD5 { public: - HashFunction* clone() const { return new MD5_IA32; } + HashFunction* clone() const { return new MD5_X86_32; } private: void compress_n(const byte[], size_t blocks); }; diff --git a/src/hash/md5_ia32/md5_ia32_imp.S b/src/hash/md5_x86_32/md5_x86_32_imp.S index e77836353..f41aaccbf 100644 --- a/src/hash/md5_ia32/md5_ia32_imp.S +++ b/src/hash/md5_x86_32/md5_x86_32_imp.S @@ -1,15 +1,15 @@ /* -* MD5 in IA-32 assembler +* MD5 in x86-32 assembler * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/internal/asm_macr_ia32.h> +#include <botan/internal/asm_x86_32.h> -START_LISTING(md5_ia32.S) +START_LISTING(md5_x86_32.S) -START_FUNCTION(botan_md5_ia32_compress) +START_FUNCTION(botan_md5_x86_32_compress) SPILL_REGS() #define PUSHED 4 @@ -163,4 +163,4 @@ LOOP_UNTIL_EQ(ESI, 16, .LOAD_INPUT) ADD(ARRAY4(EBP, 3), EDX) RESTORE_REGS() -END_FUNCTION(botan_md5_ia32_compress) +END_FUNCTION(botan_md5_x86_32_compress) diff --git a/src/hash/sha1/sha160.cpp b/src/hash/sha1/sha160.cpp index 7a42ca867..f5daaadb2 100644 --- a/src/hash/sha1/sha160.cpp +++ b/src/hash/sha1/sha160.cpp @@ -1,6 +1,6 @@ /* * SHA-160 -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2008,2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -11,6 +11,8 @@ namespace Botan { +namespace SHA1_F { + namespace { /* @@ -51,11 +53,15 @@ inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) } +} + /* * SHA-160 Compression Function */ void SHA_160::compress_n(const byte input[], size_t blocks) { + using namespace SHA1_F; + u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3], E = digest[4]; diff --git a/src/hash/sha1_ia32/sha1_ia32.h b/src/hash/sha1_ia32/sha1_ia32.h deleted file mode 100644 index 5cff03016..000000000 --- a/src/hash/sha1_ia32/sha1_ia32.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -* SHA-160 (IA-32) -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_SHA_160_IA32_H__ -#define BOTAN_SHA_160_IA32_H__ - -#include <botan/sha160.h> - -namespace Botan { - -/** -* SHA-160 in x86 assembly -*/ -class BOTAN_DLL SHA_160_IA32 : public SHA_160 - { - public: - HashFunction* clone() const { return new SHA_160_IA32; } - - // Note 81 instead of normal 80: IA-32 asm needs an extra temp - SHA_160_IA32() : SHA_160(81) {} - private: - void compress_n(const byte[], size_t blocks); - }; - -} - -#endif diff --git a/src/hash/sha1_sse2/sha1_sse2.cpp b/src/hash/sha1_sse2/sha1_sse2.cpp index e890967c6..f96afd9ce 100644 --- a/src/hash/sha1_sse2/sha1_sse2.cpp +++ b/src/hash/sha1_sse2/sha1_sse2.cpp @@ -1,6 +1,6 @@ /* * SHA-1 using SSE2 -* (C) 2009-2010 Jack Lloyd +* (C) 2009-2011 Jack Lloyd * * Distributed under the terms of the Botan license * @@ -14,6 +14,8 @@ namespace Botan { +namespace SHA1_SSE2_F { + namespace { /* @@ -146,11 +148,15 @@ inline void F4(u32bit A, u32bit& B, u32bit C, u32bit D, u32bit& E, u32bit msg) } +} + /* * SHA-160 Compression Function using SSE for message expansion */ void SHA_160_SSE2::compress_n(const byte input_bytes[], size_t blocks) { + using namespace SHA1_SSE2_F; + const __m128i K00_19 = _mm_set1_epi32(0x5A827999); const __m128i K20_39 = _mm_set1_epi32(0x6ED9EBA1); const __m128i K40_59 = _mm_set1_epi32(0x8F1BBCDC); @@ -323,4 +329,7 @@ void SHA_160_SSE2::compress_n(const byte input_bytes[], size_t blocks) #undef GET_P_32 } +#undef prep00_15 +#undef prep + } diff --git a/src/hash/sha1_ia32/info.txt b/src/hash/sha1_x86_32/info.txt index 47d8e753e..7359a6754 100644 --- a/src/hash/sha1_ia32/info.txt +++ b/src/hash/sha1_x86_32/info.txt @@ -1,12 +1,12 @@ -define SHA1_IA32 +define SHA1_X86_32 load_on asm_ok <arch> -ia32 +x86_32 </arch> <requires> -asm_ia32 +asm_x86_32 sha1 </requires> diff --git a/src/hash/sha1_ia32/sha1_ia32.cpp b/src/hash/sha1_x86_32/sha1_x86_32.cpp index 3e9cff047..6a4dc2a1d 100644 --- a/src/hash/sha1_ia32/sha1_ia32.cpp +++ b/src/hash/sha1_x86_32/sha1_x86_32.cpp @@ -1,29 +1,29 @@ /* -* SHA-160 (IA-32) +* SHA-160 in x86-32 * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/sha1_ia32.h> +#include <botan/sha1_x86_32.h> namespace Botan { namespace { extern "C" -void botan_sha160_ia32_compress(u32bit[5], const byte[64], u32bit[81]); +void botan_sha160_x86_32_compress(u32bit[5], const byte[64], u32bit[81]); } /* * SHA-160 Compression Function */ -void SHA_160_IA32::compress_n(const byte input[], size_t blocks) +void SHA_160_X86_32::compress_n(const byte input[], size_t blocks) { for(size_t i = 0; i != blocks; ++i) { - botan_sha160_ia32_compress(&digest[0], input, &W[0]); + botan_sha160_x86_32_compress(&digest[0], input, &W[0]); input += hash_block_size(); } } diff --git a/src/hash/sha1_x86_32/sha1_x86_32.h b/src/hash/sha1_x86_32/sha1_x86_32.h new file mode 100644 index 000000000..b344d4ae2 --- /dev/null +++ b/src/hash/sha1_x86_32/sha1_x86_32.h @@ -0,0 +1,31 @@ +/* +* SHA-160 in x86-32 asm +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SHA_160_X86_32_H__ +#define BOTAN_SHA_160_X86_32_H__ + +#include <botan/sha160.h> + +namespace Botan { + +/** +* SHA-160 in x86 assembly +*/ +class BOTAN_DLL SHA_160_X86_32 : public SHA_160 + { + public: + HashFunction* clone() const { return new SHA_160_X86_32; } + + // Note 81 instead of normal 80: x86-32 asm needs an extra temp + SHA_160_X86_32() : SHA_160(81) {} + private: + void compress_n(const byte[], size_t blocks); + }; + +} + +#endif diff --git a/src/hash/sha1_ia32/sha1_ia32_imp.S b/src/hash/sha1_x86_32/sha1_x86_32_imp.S index c2777b4b5..775ef6854 100644 --- a/src/hash/sha1_ia32/sha1_ia32_imp.S +++ b/src/hash/sha1_x86_32/sha1_x86_32_imp.S @@ -1,15 +1,15 @@ /* -* SHA-1 in IA-32 assembler +* SHA-1 in x86-32 asm * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ -#include <botan/internal/asm_macr_ia32.h> +#include <botan/internal/asm_x86_32.h> -START_LISTING(sha1_ia32.S) +START_LISTING(sha1_x86_32_imp.S) -START_FUNCTION(botan_sha160_ia32_compress) +START_FUNCTION(botan_sha160_x86_32_compress) SPILL_REGS() #define PUSHED 4 @@ -42,7 +42,7 @@ LOOP_UNTIL_EQ(ESI, 16, .LOAD_INPUT) ADD2_IMM(EDI, EBP, 64) -START_LOOP(.EXPANSION) +START_LOOP(.L_SHA_EXPANSION) ADD_IMM(ESI, 4) ZEROIZE(EAX) @@ -77,7 +77,7 @@ START_LOOP(.EXPANSION) ASSIGN(ARRAY4(EDI, 3), EAX) ADD_IMM(EDI, 16) -LOOP_UNTIL_EQ(ESI, 80, .EXPANSION) +LOOP_UNTIL_EQ(ESI, 80, .L_SHA_EXPANSION) #define MAGIC1 0x5A827999 #define MAGIC2 0x6ED9EBA1 @@ -241,4 +241,4 @@ LOOP_UNTIL_EQ(ESI, 80, .EXPANSION) ADD(ARRAY4(EBP, 4), ECX) RESTORE_REGS() -END_FUNCTION(botan_sha160_ia32_compress) +END_FUNCTION(botan_sha160_x86_32_compress) diff --git a/src/hash/sha1_amd64/info.txt b/src/hash/sha1_x86_64/info.txt index 78eaa23c2..3d54c0baa 100644 --- a/src/hash/sha1_amd64/info.txt +++ b/src/hash/sha1_x86_64/info.txt @@ -1,13 +1,13 @@ -define SHA1_AMD64 +define SHA1_X86_64 load_on asm_ok <arch> -amd64 +x86_64 </arch> <requires> asm_engine -asm_amd64 +asm_x86_64 sha1 </requires> diff --git a/src/hash/sha1_amd64/sha1_amd64.cpp b/src/hash/sha1_x86_64/sha1_x86_64.cpp index d32b44901..a3e92e313 100644 --- a/src/hash/sha1_amd64/sha1_amd64.cpp +++ b/src/hash/sha1_x86_64/sha1_x86_64.cpp @@ -5,25 +5,25 @@ * Distributed under the terms of the Botan license */ -#include <botan/sha1_amd64.h> +#include <botan/sha1_x86_64.h> namespace Botan { namespace { extern "C" -void botan_sha160_amd64_compress(u32bit[5], const byte[64], u32bit[80]); +void botan_sha160_x86_64_compress(u32bit[5], const byte[64], u32bit[80]); } /* * SHA-160 Compression Function */ -void SHA_160_AMD64::compress_n(const byte input[], size_t blocks) +void SHA_160_X86_64::compress_n(const byte input[], size_t blocks) { for(size_t i = 0; i != blocks; ++i) { - botan_sha160_amd64_compress(&digest[0], input, &W[0]); + botan_sha160_x86_64_compress(&digest[0], input, &W[0]); input += hash_block_size(); } } diff --git a/src/hash/sha1_amd64/sha1_amd64.h b/src/hash/sha1_x86_64/sha1_x86_64.h index 6b741184d..068a94595 100644 --- a/src/hash/sha1_amd64/sha1_amd64.h +++ b/src/hash/sha1_x86_64/sha1_x86_64.h @@ -5,8 +5,8 @@ * Distributed under the terms of the Botan license */ -#ifndef BOTAN_SHA_160_AMD64_H__ -#define BOTAN_SHA_160_AMD64_H__ +#ifndef BOTAN_SHA_160_X86_64_H__ +#define BOTAN_SHA_160_X86_64_H__ #include <botan/sha160.h> @@ -15,10 +15,10 @@ namespace Botan { /** * SHA-160 in x86-64 assembly */ -class BOTAN_DLL SHA_160_AMD64 : public SHA_160 +class BOTAN_DLL SHA_160_X86_64 : public SHA_160 { public: - HashFunction* clone() const { return new SHA_160_AMD64; } + HashFunction* clone() const { return new SHA_160_X86_64; } private: void compress_n(const byte[], size_t blocks); }; diff --git a/src/hash/sha1_amd64/sha1_amd64_imp.S b/src/hash/sha1_x86_64/sha1_x86_64_imp.S index 4eea75f11..ee35f0d85 100644 --- a/src/hash/sha1_amd64/sha1_amd64_imp.S +++ b/src/hash/sha1_x86_64/sha1_x86_64_imp.S @@ -5,11 +5,11 @@ * Distributed under the terms of the Botan license */ -#include <botan/internal/asm_macr_amd64.h> +#include <botan/internal/asm_x86_64.h> -START_LISTING(sha1_amd64.S) +START_LISTING(sha1_x86_64_imp.S) -START_FUNCTION(botan_sha160_amd64_compress) +START_FUNCTION(botan_sha160_x86_64_compress) #define DIGEST_ARR %rdi #define INPUT %rsi @@ -263,4 +263,4 @@ ALIGN; ADD(ARRAY4(DIGEST_ARR, 3), B) ADD(ARRAY4(DIGEST_ARR, 4), C) -END_FUNCTION(botan_sha160_amd64_compress) +END_FUNCTION(botan_sha160_x86_64_compress) diff --git a/src/hash/sha2_32/sha2_32.cpp b/src/hash/sha2_32/sha2_32.cpp index 4e5f2b38c..6dd780e64 100644 --- a/src/hash/sha2_32/sha2_32.cpp +++ b/src/hash/sha2_32/sha2_32.cpp @@ -14,6 +14,8 @@ namespace Botan { namespace { +namespace SHA2_32 { + /* * SHA-256 Rho Function */ @@ -33,22 +35,23 @@ inline u32bit sigma(u32bit X, u32bit rot1, u32bit rot2, u32bit shift) /* * SHA-256 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. */ -inline void F1(u32bit A, u32bit B, u32bit C, u32bit& D, - u32bit E, u32bit F, u32bit G, u32bit& H, - u32bit msg, u32bit magic) - { - H += magic + rho(E, 6, 11, 25) + ((E & F) ^ (~E & G)) + msg; - D += H; - H += rho(A, 2, 13, 22) + ((A & B) | ((A | B) & C)); - } +#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + H += magic + rho(E, 6, 11, 25) + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += rho(A, 2, 13, 22) + ((A & B) | ((A | B) & C)); \ + M1 += sigma(M2, 17, 19, 10) + M3 + sigma(M4, 7, 18, 3); \ + } while(0); /* * SHA-224 / SHA-256 compression function */ -void sha2_32_compress(MemoryRegion<u32bit>& W, - MemoryRegion<u32bit>& digest, - const byte input[], size_t blocks) +void compress(MemoryRegion<u32bit>& digest, + const byte input[], size_t blocks) { u32bit A = digest[0], B = digest[1], C = digest[2], D = digest[3], E = digest[4], F = digest[5], @@ -56,92 +59,87 @@ void sha2_32_compress(MemoryRegion<u32bit>& W, for(size_t i = 0; i != blocks; ++i) { - load_be(&W[0], input, 16); - - for(size_t j = 16; j != 64; j += 8) - { - W[j ] = sigma(W[j- 2], 17, 19, 10) + W[j-7] + - sigma(W[j-15], 7, 18, 3) + W[j-16]; - W[j+1] = sigma(W[j- 1], 17, 19, 10) + W[j-6] + - sigma(W[j-14], 7, 18, 3) + W[j-15]; - W[j+2] = sigma(W[j ], 17, 19, 10) + W[j-5] + - sigma(W[j-13], 7, 18, 3) + W[j-14]; - W[j+3] = sigma(W[j+ 1], 17, 19, 10) + W[j-4] + - sigma(W[j-12], 7, 18, 3) + W[j-13]; - W[j+4] = sigma(W[j+ 2], 17, 19, 10) + W[j-3] + - sigma(W[j-11], 7, 18, 3) + W[j-12]; - W[j+5] = sigma(W[j+ 3], 17, 19, 10) + W[j-2] + - sigma(W[j-10], 7, 18, 3) + W[j-11]; - W[j+6] = sigma(W[j+ 4], 17, 19, 10) + W[j-1] + - sigma(W[j- 9], 7, 18, 3) + W[j-10]; - W[j+7] = sigma(W[j+ 5], 17, 19, 10) + W[j ] + - sigma(W[j- 8], 7, 18, 3) + W[j- 9]; - } - - F1(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98); - F1(H, A, B, C, D, E, F, G, W[ 1], 0x71374491); - F1(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF); - F1(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5); - F1(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B); - F1(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1); - F1(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4); - F1(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5); - F1(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98); - F1(H, A, B, C, D, E, F, G, W[ 9], 0x12835B01); - F1(G, H, A, B, C, D, E, F, W[10], 0x243185BE); - F1(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3); - F1(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74); - F1(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE); - F1(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7); - F1(B, C, D, E, F, G, H, A, W[15], 0xC19BF174); - F1(A, B, C, D, E, F, G, H, W[16], 0xE49B69C1); - F1(H, A, B, C, D, E, F, G, W[17], 0xEFBE4786); - F1(G, H, A, B, C, D, E, F, W[18], 0x0FC19DC6); - F1(F, G, H, A, B, C, D, E, W[19], 0x240CA1CC); - F1(E, F, G, H, A, B, C, D, W[20], 0x2DE92C6F); - F1(D, E, F, G, H, A, B, C, W[21], 0x4A7484AA); - F1(C, D, E, F, G, H, A, B, W[22], 0x5CB0A9DC); - F1(B, C, D, E, F, G, H, A, W[23], 0x76F988DA); - F1(A, B, C, D, E, F, G, H, W[24], 0x983E5152); - F1(H, A, B, C, D, E, F, G, W[25], 0xA831C66D); - F1(G, H, A, B, C, D, E, F, W[26], 0xB00327C8); - F1(F, G, H, A, B, C, D, E, W[27], 0xBF597FC7); - F1(E, F, G, H, A, B, C, D, W[28], 0xC6E00BF3); - F1(D, E, F, G, H, A, B, C, W[29], 0xD5A79147); - F1(C, D, E, F, G, H, A, B, W[30], 0x06CA6351); - F1(B, C, D, E, F, G, H, A, W[31], 0x14292967); - F1(A, B, C, D, E, F, G, H, W[32], 0x27B70A85); - F1(H, A, B, C, D, E, F, G, W[33], 0x2E1B2138); - F1(G, H, A, B, C, D, E, F, W[34], 0x4D2C6DFC); - F1(F, G, H, A, B, C, D, E, W[35], 0x53380D13); - F1(E, F, G, H, A, B, C, D, W[36], 0x650A7354); - F1(D, E, F, G, H, A, B, C, W[37], 0x766A0ABB); - F1(C, D, E, F, G, H, A, B, W[38], 0x81C2C92E); - F1(B, C, D, E, F, G, H, A, W[39], 0x92722C85); - F1(A, B, C, D, E, F, G, H, W[40], 0xA2BFE8A1); - F1(H, A, B, C, D, E, F, G, W[41], 0xA81A664B); - F1(G, H, A, B, C, D, E, F, W[42], 0xC24B8B70); - F1(F, G, H, A, B, C, D, E, W[43], 0xC76C51A3); - F1(E, F, G, H, A, B, C, D, W[44], 0xD192E819); - F1(D, E, F, G, H, A, B, C, W[45], 0xD6990624); - F1(C, D, E, F, G, H, A, B, W[46], 0xF40E3585); - F1(B, C, D, E, F, G, H, A, W[47], 0x106AA070); - F1(A, B, C, D, E, F, G, H, W[48], 0x19A4C116); - F1(H, A, B, C, D, E, F, G, W[49], 0x1E376C08); - F1(G, H, A, B, C, D, E, F, W[50], 0x2748774C); - F1(F, G, H, A, B, C, D, E, W[51], 0x34B0BCB5); - F1(E, F, G, H, A, B, C, D, W[52], 0x391C0CB3); - F1(D, E, F, G, H, A, B, C, W[53], 0x4ED8AA4A); - F1(C, D, E, F, G, H, A, B, W[54], 0x5B9CCA4F); - F1(B, C, D, E, F, G, H, A, W[55], 0x682E6FF3); - F1(A, B, C, D, E, F, G, H, W[56], 0x748F82EE); - F1(H, A, B, C, D, E, F, G, W[57], 0x78A5636F); - F1(G, H, A, B, C, D, E, F, W[58], 0x84C87814); - F1(F, G, H, A, B, C, D, E, W[59], 0x8CC70208); - F1(E, F, G, H, A, B, C, D, W[60], 0x90BEFFFA); - F1(D, E, F, G, H, A, B, C, W[61], 0xA4506CEB); - F1(C, D, E, F, G, H, A, B, W[62], 0xBEF9A3F7); - F1(B, C, D, E, F, G, H, A, W[63], 0xC67178F2); + u32bit W00 = load_be<u32bit>(input, 0); + u32bit W01 = load_be<u32bit>(input, 1); + u32bit W02 = load_be<u32bit>(input, 2); + u32bit W03 = load_be<u32bit>(input, 3); + u32bit W04 = load_be<u32bit>(input, 4); + u32bit W05 = load_be<u32bit>(input, 5); + u32bit W06 = load_be<u32bit>(input, 6); + u32bit W07 = load_be<u32bit>(input, 7); + u32bit W08 = load_be<u32bit>(input, 8); + u32bit W09 = load_be<u32bit>(input, 9); + u32bit W10 = load_be<u32bit>(input, 10); + u32bit W11 = load_be<u32bit>(input, 11); + u32bit W12 = load_be<u32bit>(input, 12); + u32bit W13 = load_be<u32bit>(input, 13); + u32bit W14 = load_be<u32bit>(input, 14); + u32bit W15 = load_be<u32bit>(input, 15); + + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); + SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); + SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); + SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); + SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); + SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); + SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); + SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); + SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); + SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); + SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); + SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); + SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); + SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); + SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); + SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); + SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); A = (digest[0] += A); B = (digest[1] += B); @@ -158,12 +156,14 @@ void sha2_32_compress(MemoryRegion<u32bit>& W, } +} + /* * SHA-224 compression function */ void SHA_224::compress_n(const byte input[], size_t blocks) { - sha2_32_compress(W, digest, input, blocks); + SHA2_32::compress(digest, input, blocks); } /* @@ -181,7 +181,6 @@ void SHA_224::copy_out(byte output[]) void SHA_224::clear() { MDx_HashFunction::clear(); - zeroise(W); digest[0] = 0xC1059ED8; digest[1] = 0x367CD507; digest[2] = 0x3070DD17; @@ -197,7 +196,7 @@ void SHA_224::clear() */ void SHA_256::compress_n(const byte input[], size_t blocks) { - sha2_32_compress(W, digest, input, blocks); + SHA2_32::compress(digest, input, blocks); } /* @@ -215,7 +214,6 @@ void SHA_256::copy_out(byte output[]) void SHA_256::clear() { MDx_HashFunction::clear(); - zeroise(W); digest[0] = 0x6A09E667; digest[1] = 0xBB67AE85; digest[2] = 0x3C6EF372; diff --git a/src/hash/sha2_32/sha2_32.h b/src/hash/sha2_32/sha2_32.h index ffda11772..807b979d1 100644 --- a/src/hash/sha2_32/sha2_32.h +++ b/src/hash/sha2_32/sha2_32.h @@ -1,6 +1,6 @@ /* * SHA-{224,256} -* (C) 1999-2010 Jack Lloyd +* (C) 1999-2011 Jack Lloyd * 2007 FlexSecure GmbH * * Distributed under the terms of the Botan license @@ -25,13 +25,13 @@ class BOTAN_DLL SHA_224 : public MDx_HashFunction void clear(); - SHA_224() : MDx_HashFunction(64, true, true), W(64), digest(8) + SHA_224() : MDx_HashFunction(64, true, true), digest(8) { clear(); } private: void compress_n(const byte[], size_t blocks); void copy_out(byte[]); - SecureVector<u32bit> W, digest; + SecureVector<u32bit> digest; }; /** @@ -46,13 +46,13 @@ class BOTAN_DLL SHA_256 : public MDx_HashFunction void clear(); - SHA_256() : MDx_HashFunction(64, true, true), W(64), digest(8) + SHA_256() : MDx_HashFunction(64, true, true), digest(8) { clear(); } private: void compress_n(const byte[], size_t blocks); void copy_out(byte[]); - SecureVector<u32bit> W, digest; + SecureVector<u32bit> digest; }; } diff --git a/src/hash/sha2_64/sha2_64.cpp b/src/hash/sha2_64/sha2_64.cpp index 3c1df9be6..3026c3a39 100644 --- a/src/hash/sha2_64/sha2_64.cpp +++ b/src/hash/sha2_64/sha2_64.cpp @@ -1,6 +1,6 @@ /* * SHA-{384,512} -* (C) 1999-2010 Jack Lloyd +* (C) 1999-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -13,6 +13,8 @@ namespace Botan { namespace { +namespace SHA2_64 { + /* * SHA-{384,512} Rho Function */ @@ -23,18 +25,6 @@ inline u64bit rho(u64bit X, u32bit rot1, u32bit rot2, u32bit rot3) } /* -* SHA-{384,512} F1 Function -*/ -inline void F1(u64bit A, u64bit B, u64bit C, u64bit& D, - u64bit E, u64bit F, u64bit G, u64bit& H, - u64bit msg, u64bit magic) - { - magic += rho(E, 14, 18, 41) + ((E & F) ^ (~E & G)) + msg; - D += magic + H; - H += magic + rho(A, 28, 34, 39) + ((A & B) ^ (A & C) ^ (B & C)); - } - -/* * SHA-{384,512} Sigma Function */ inline u64bit sigma(u64bit X, u32bit rot1, u32bit rot2, u32bit shift) @@ -43,11 +33,24 @@ inline u64bit sigma(u64bit X, u32bit rot1, u32bit rot2, u32bit shift) } /* +* SHA-512 F1 Function +* +* Use a macro as many compilers won't inline a function this big, +* even though it is much faster if inlined. +*/ +#define SHA2_64_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) \ + do { \ + H += magic + rho(E, 14, 18, 41) + ((E & F) ^ (~E & G)) + M1; \ + D += H; \ + H += rho(A, 28, 34, 39) + ((A & B) | ((A | B) & C)); \ + M1 += sigma(M2, 19, 61, 6) + M3 + sigma(M4, 1, 8, 7); \ + } while(0); + +/* * SHA-{384,512} Compression Function */ -void sha2_64_compress(MemoryRegion<u64bit>& W, - MemoryRegion<u64bit>& digest, - const byte input[], size_t blocks) +void compress(MemoryRegion<u64bit>& digest, + const byte input[], size_t blocks) { u64bit A = digest[0], B = digest[1], C = digest[2], D = digest[3], E = digest[4], F = digest[5], @@ -55,100 +58,103 @@ void sha2_64_compress(MemoryRegion<u64bit>& W, for(size_t i = 0; i != blocks; ++i) { - load_be(&W[0], input, 16); - - for(size_t j = 16; j != 80; j += 8) - { - W[j ] = sigma(W[j-2], 19, 61, 6) + W[j-7] + sigma(W[j-15], 1, 8, 7) + W[j-16]; - W[j+1] = sigma(W[j-1], 19, 61, 6) + W[j-6] + sigma(W[j-14], 1, 8, 7) + W[j-15]; - W[j+2] = sigma(W[j ], 19, 61, 6) + W[j-5] + sigma(W[j-13], 1, 8, 7) + W[j-14]; - W[j+3] = sigma(W[j+1], 19, 61, 6) + W[j-4] + sigma(W[j-12], 1, 8, 7) + W[j-13]; - W[j+4] = sigma(W[j+2], 19, 61, 6) + W[j-3] + sigma(W[j-11], 1, 8, 7) + W[j-12]; - W[j+5] = sigma(W[j+3], 19, 61, 6) + W[j-2] + sigma(W[j-10], 1, 8, 7) + W[j-11]; - W[j+6] = sigma(W[j+4], 19, 61, 6) + W[j-1] + sigma(W[j- 9], 1, 8, 7) + W[j-10]; - W[j+7] = sigma(W[j+5], 19, 61, 6) + W[j ] + sigma(W[j- 8], 1, 8, 7) + W[j- 9]; - } - - F1(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98D728AE22); - F1(H, A, B, C, D, E, F, G, W[ 1], 0x7137449123EF65CD); - F1(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCFEC4D3B2F); - F1(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA58189DBBC); - F1(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25BF348B538); - F1(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1B605D019); - F1(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4AF194F9B); - F1(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5DA6D8118); - F1(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98A3030242); - F1(H, A, B, C, D, E, F, G, W[ 9], 0x12835B0145706FBE); - F1(G, H, A, B, C, D, E, F, W[10], 0x243185BE4EE4B28C); - F1(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3D5FFB4E2); - F1(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74F27B896F); - F1(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE3B1696B1); - F1(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A725C71235); - F1(B, C, D, E, F, G, H, A, W[15], 0xC19BF174CF692694); - F1(A, B, C, D, E, F, G, H, W[16], 0xE49B69C19EF14AD2); - F1(H, A, B, C, D, E, F, G, W[17], 0xEFBE4786384F25E3); - F1(G, H, A, B, C, D, E, F, W[18], 0x0FC19DC68B8CD5B5); - F1(F, G, H, A, B, C, D, E, W[19], 0x240CA1CC77AC9C65); - F1(E, F, G, H, A, B, C, D, W[20], 0x2DE92C6F592B0275); - F1(D, E, F, G, H, A, B, C, W[21], 0x4A7484AA6EA6E483); - F1(C, D, E, F, G, H, A, B, W[22], 0x5CB0A9DCBD41FBD4); - F1(B, C, D, E, F, G, H, A, W[23], 0x76F988DA831153B5); - F1(A, B, C, D, E, F, G, H, W[24], 0x983E5152EE66DFAB); - F1(H, A, B, C, D, E, F, G, W[25], 0xA831C66D2DB43210); - F1(G, H, A, B, C, D, E, F, W[26], 0xB00327C898FB213F); - F1(F, G, H, A, B, C, D, E, W[27], 0xBF597FC7BEEF0EE4); - F1(E, F, G, H, A, B, C, D, W[28], 0xC6E00BF33DA88FC2); - F1(D, E, F, G, H, A, B, C, W[29], 0xD5A79147930AA725); - F1(C, D, E, F, G, H, A, B, W[30], 0x06CA6351E003826F); - F1(B, C, D, E, F, G, H, A, W[31], 0x142929670A0E6E70); - F1(A, B, C, D, E, F, G, H, W[32], 0x27B70A8546D22FFC); - F1(H, A, B, C, D, E, F, G, W[33], 0x2E1B21385C26C926); - F1(G, H, A, B, C, D, E, F, W[34], 0x4D2C6DFC5AC42AED); - F1(F, G, H, A, B, C, D, E, W[35], 0x53380D139D95B3DF); - F1(E, F, G, H, A, B, C, D, W[36], 0x650A73548BAF63DE); - F1(D, E, F, G, H, A, B, C, W[37], 0x766A0ABB3C77B2A8); - F1(C, D, E, F, G, H, A, B, W[38], 0x81C2C92E47EDAEE6); - F1(B, C, D, E, F, G, H, A, W[39], 0x92722C851482353B); - F1(A, B, C, D, E, F, G, H, W[40], 0xA2BFE8A14CF10364); - F1(H, A, B, C, D, E, F, G, W[41], 0xA81A664BBC423001); - F1(G, H, A, B, C, D, E, F, W[42], 0xC24B8B70D0F89791); - F1(F, G, H, A, B, C, D, E, W[43], 0xC76C51A30654BE30); - F1(E, F, G, H, A, B, C, D, W[44], 0xD192E819D6EF5218); - F1(D, E, F, G, H, A, B, C, W[45], 0xD69906245565A910); - F1(C, D, E, F, G, H, A, B, W[46], 0xF40E35855771202A); - F1(B, C, D, E, F, G, H, A, W[47], 0x106AA07032BBD1B8); - F1(A, B, C, D, E, F, G, H, W[48], 0x19A4C116B8D2D0C8); - F1(H, A, B, C, D, E, F, G, W[49], 0x1E376C085141AB53); - F1(G, H, A, B, C, D, E, F, W[50], 0x2748774CDF8EEB99); - F1(F, G, H, A, B, C, D, E, W[51], 0x34B0BCB5E19B48A8); - F1(E, F, G, H, A, B, C, D, W[52], 0x391C0CB3C5C95A63); - F1(D, E, F, G, H, A, B, C, W[53], 0x4ED8AA4AE3418ACB); - F1(C, D, E, F, G, H, A, B, W[54], 0x5B9CCA4F7763E373); - F1(B, C, D, E, F, G, H, A, W[55], 0x682E6FF3D6B2B8A3); - F1(A, B, C, D, E, F, G, H, W[56], 0x748F82EE5DEFB2FC); - F1(H, A, B, C, D, E, F, G, W[57], 0x78A5636F43172F60); - F1(G, H, A, B, C, D, E, F, W[58], 0x84C87814A1F0AB72); - F1(F, G, H, A, B, C, D, E, W[59], 0x8CC702081A6439EC); - F1(E, F, G, H, A, B, C, D, W[60], 0x90BEFFFA23631E28); - F1(D, E, F, G, H, A, B, C, W[61], 0xA4506CEBDE82BDE9); - F1(C, D, E, F, G, H, A, B, W[62], 0xBEF9A3F7B2C67915); - F1(B, C, D, E, F, G, H, A, W[63], 0xC67178F2E372532B); - F1(A, B, C, D, E, F, G, H, W[64], 0xCA273ECEEA26619C); - F1(H, A, B, C, D, E, F, G, W[65], 0xD186B8C721C0C207); - F1(G, H, A, B, C, D, E, F, W[66], 0xEADA7DD6CDE0EB1E); - F1(F, G, H, A, B, C, D, E, W[67], 0xF57D4F7FEE6ED178); - F1(E, F, G, H, A, B, C, D, W[68], 0x06F067AA72176FBA); - F1(D, E, F, G, H, A, B, C, W[69], 0x0A637DC5A2C898A6); - F1(C, D, E, F, G, H, A, B, W[70], 0x113F9804BEF90DAE); - F1(B, C, D, E, F, G, H, A, W[71], 0x1B710B35131C471B); - F1(A, B, C, D, E, F, G, H, W[72], 0x28DB77F523047D84); - F1(H, A, B, C, D, E, F, G, W[73], 0x32CAAB7B40C72493); - F1(G, H, A, B, C, D, E, F, W[74], 0x3C9EBE0A15C9BEBC); - F1(F, G, H, A, B, C, D, E, W[75], 0x431D67C49C100D4C); - F1(E, F, G, H, A, B, C, D, W[76], 0x4CC5D4BECB3E42B6); - F1(D, E, F, G, H, A, B, C, W[77], 0x597F299CFC657E2A); - F1(C, D, E, F, G, H, A, B, W[78], 0x5FCB6FAB3AD6FAEC); - F1(B, C, D, E, F, G, H, A, W[79], 0x6C44198C4A475817); + u64bit W00 = load_be<u64bit>(input, 0); + u64bit W01 = load_be<u64bit>(input, 1); + u64bit W02 = load_be<u64bit>(input, 2); + u64bit W03 = load_be<u64bit>(input, 3); + u64bit W04 = load_be<u64bit>(input, 4); + u64bit W05 = load_be<u64bit>(input, 5); + u64bit W06 = load_be<u64bit>(input, 6); + u64bit W07 = load_be<u64bit>(input, 7); + u64bit W08 = load_be<u64bit>(input, 8); + u64bit W09 = load_be<u64bit>(input, 9); + u64bit W10 = load_be<u64bit>(input, 10); + u64bit W11 = load_be<u64bit>(input, 11); + u64bit W12 = load_be<u64bit>(input, 12); + u64bit W13 = load_be<u64bit>(input, 13); + u64bit W14 = load_be<u64bit>(input, 14); + u64bit W15 = load_be<u64bit>(input, 15); + + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98D728AE22); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x7137449123EF65CD); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCFEC4D3B2F); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA58189DBBC); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25BF348B538); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1B605D019); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4AF194F9B); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5DA6D8118); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98A3030242); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B0145706FBE); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE4EE4B28C); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3D5FFB4E2); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74F27B896F); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE3B1696B1); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A725C71235); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174CF692694); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C19EF14AD2); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786384F25E3); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC68B8CD5B5); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC77AC9C65); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F592B0275); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA6EA6E483); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DCBD41FBD4); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA831153B5); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152EE66DFAB); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D2DB43210); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C898FB213F); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7BEEF0EE4); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF33DA88FC2); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147930AA725); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351E003826F); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x142929670A0E6E70); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A8546D22FFC); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B21385C26C926); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC5AC42AED); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D139D95B3DF); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A73548BAF63DE); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB3C77B2A8); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E47EDAEE6); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C851482353B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A14CF10364); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664BBC423001); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70D0F89791); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A30654BE30); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819D6EF5218); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD69906245565A910); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E35855771202A); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA07032BBD1B8); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116B8D2D0C8); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C085141AB53); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774CDF8EEB99); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5E19B48A8); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3C5C95A63); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4AE3418ACB); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F7763E373); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3D6B2B8A3); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE5DEFB2FC); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F43172F60); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814A1F0AB72); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC702081A6439EC); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA23631E28); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEBDE82BDE9); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7B2C67915); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2E372532B); + SHA2_64_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xCA273ECEEA26619C); + SHA2_64_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xD186B8C721C0C207); + SHA2_64_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xEADA7DD6CDE0EB1E); + SHA2_64_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xF57D4F7FEE6ED178); + SHA2_64_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x06F067AA72176FBA); + SHA2_64_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x0A637DC5A2C898A6); + SHA2_64_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x113F9804BEF90DAE); + SHA2_64_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x1B710B35131C471B); + SHA2_64_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x28DB77F523047D84); + SHA2_64_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x32CAAB7B40C72493); + SHA2_64_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x3C9EBE0A15C9BEBC); + SHA2_64_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x431D67C49C100D4C); + SHA2_64_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x4CC5D4BECB3E42B6); + SHA2_64_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x597F299CFC657E2A); + SHA2_64_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x5FCB6FAB3AD6FAEC); + SHA2_64_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x6C44198C4A475817); A = (digest[0] += A); B = (digest[1] += B); @@ -165,12 +171,14 @@ void sha2_64_compress(MemoryRegion<u64bit>& W, } +} + /* * SHA-384 compression function */ void SHA_384::compress_n(const byte input[], size_t blocks) { - sha2_64_compress(W, digest, input, blocks); + SHA2_64::compress(digest, input, blocks); } /* @@ -188,7 +196,6 @@ void SHA_384::copy_out(byte output[]) void SHA_384::clear() { MDx_HashFunction::clear(); - zeroise(W); digest[0] = 0xCBBB9D5DC1059ED8; digest[1] = 0x629A292A367CD507; digest[2] = 0x9159015A3070DD17; @@ -204,7 +211,7 @@ void SHA_384::clear() */ void SHA_512::compress_n(const byte input[], size_t blocks) { - sha2_64_compress(W, digest, input, blocks); + SHA2_64::compress(digest, input, blocks); } /* @@ -222,7 +229,6 @@ void SHA_512::copy_out(byte output[]) void SHA_512::clear() { MDx_HashFunction::clear(); - zeroise(W); digest[0] = 0x6A09E667F3BCC908; digest[1] = 0xBB67AE8584CAA73B; digest[2] = 0x3C6EF372FE94F82B; diff --git a/src/hash/sha2_64/sha2_64.h b/src/hash/sha2_64/sha2_64.h index dcfb7224c..124d4bbfb 100644 --- a/src/hash/sha2_64/sha2_64.h +++ b/src/hash/sha2_64/sha2_64.h @@ -24,13 +24,13 @@ class BOTAN_DLL SHA_384 : public MDx_HashFunction void clear(); - SHA_384() : MDx_HashFunction(128, true, true, 16), W(80), digest(8) + SHA_384() : MDx_HashFunction(128, true, true, 16), digest(8) { clear(); } private: void compress_n(const byte[], size_t blocks); void copy_out(byte[]); - SecureVector<u64bit> W, digest; + SecureVector<u64bit> digest; }; /** @@ -45,13 +45,13 @@ class BOTAN_DLL SHA_512 : public MDx_HashFunction void clear(); - SHA_512() : MDx_HashFunction(128, true, true, 16), W(80), digest(8) + SHA_512() : MDx_HashFunction(128, true, true, 16), digest(8) { clear(); } private: void compress_n(const byte[], size_t blocks); void copy_out(byte[]); - SecureVector<u64bit> W, digest; + SecureVector<u64bit> digest; }; } diff --git a/src/hash/skein/skein_512.cpp b/src/hash/skein/skein_512.cpp index 92acf0814..b5f7677db 100644 --- a/src/hash/skein/skein_512.cpp +++ b/src/hash/skein/skein_512.cpp @@ -43,7 +43,7 @@ void ubi_512(MemoryRegion<u64bit>& H, if(to_proc % 8) { for(size_t j = 0; j != to_proc % 8; ++j) - M[to_proc/8] |= ((u64bit)msg[8*(to_proc/8)+j] << (8*j)); + M[to_proc/8] |= static_cast<u64bit>(msg[8*(to_proc/8)+j]) << (8*j); } H[8] = H[0] ^ H[1] ^ H[2] ^ H[3] ^ @@ -117,7 +117,8 @@ void ubi_512(MemoryRegion<u64bit>& H, H[6] = X6 ^ M[6]; H[7] = X7 ^ M[7]; - T[1] &= ~((u64bit)1 << 62); // clear first flag if set + // clear first flag if set + T[1] &= ~(static_cast<u64bit>(1) << 62); msg_len -= to_proc; msg += to_proc; @@ -128,7 +129,10 @@ void reset_tweak(MemoryRegion<u64bit>& T, type_code type, bool final) { T[0] = 0; - T[1] = ((u64bit)type << 56) | ((u64bit)1 << 62) | ((u64bit)final << 63); + + T[1] = (static_cast<u64bit>(type) << 56) | + (static_cast<u64bit>(1) << 62) | + (static_cast<u64bit>(final) << 63); } void initial_block(MemoryRegion<u64bit>& H, @@ -227,7 +231,7 @@ void Skein_512::add_data(const byte input[], size_t length) void Skein_512::final_result(byte out[]) { - T[1] |= ((u64bit)1 << 63); // final block flag + T[1] |= (static_cast<u64bit>(1) << 63); // final block flag for(size_t i = buf_pos; i != buffer.size(); ++i) buffer[i] = 0; diff --git a/src/kdf/ssl_prf/info.txt b/src/kdf/prf_ssl3/info.txt index 0ef297119..0ef297119 100644 --- a/src/kdf/ssl_prf/info.txt +++ b/src/kdf/prf_ssl3/info.txt diff --git a/src/kdf/ssl_prf/prf_ssl3.cpp b/src/kdf/prf_ssl3/prf_ssl3.cpp index 72cf023e2..72cf023e2 100644 --- a/src/kdf/ssl_prf/prf_ssl3.cpp +++ b/src/kdf/prf_ssl3/prf_ssl3.cpp diff --git a/src/kdf/ssl_prf/prf_ssl3.h b/src/kdf/prf_ssl3/prf_ssl3.h index b07454be2..b07454be2 100644 --- a/src/kdf/ssl_prf/prf_ssl3.h +++ b/src/kdf/prf_ssl3/prf_ssl3.h diff --git a/src/kdf/tls_prf/info.txt b/src/kdf/prf_tls/info.txt index 9531a6a83..9531a6a83 100644 --- a/src/kdf/tls_prf/info.txt +++ b/src/kdf/prf_tls/info.txt diff --git a/src/kdf/tls_prf/prf_tls.cpp b/src/kdf/prf_tls/prf_tls.cpp index 2b57cdd25..2b57cdd25 100644 --- a/src/kdf/tls_prf/prf_tls.cpp +++ b/src/kdf/prf_tls/prf_tls.cpp diff --git a/src/kdf/tls_prf/prf_tls.h b/src/kdf/prf_tls/prf_tls.h index 5237f17c0..5237f17c0 100644 --- a/src/kdf/tls_prf/prf_tls.h +++ b/src/kdf/prf_tls/prf_tls.h diff --git a/src/kdf/x942_prf/info.txt b/src/kdf/prf_x942/info.txt index e51aafd08..e51aafd08 100644 --- a/src/kdf/x942_prf/info.txt +++ b/src/kdf/prf_x942/info.txt diff --git a/src/kdf/x942_prf/prf_x942.cpp b/src/kdf/prf_x942/prf_x942.cpp index fc31effe4..fc31effe4 100644 --- a/src/kdf/x942_prf/prf_x942.cpp +++ b/src/kdf/prf_x942/prf_x942.cpp diff --git a/src/kdf/x942_prf/prf_x942.h b/src/kdf/prf_x942/prf_x942.h index e6093eda6..e6093eda6 100644 --- a/src/kdf/x942_prf/prf_x942.h +++ b/src/kdf/prf_x942/prf_x942.h diff --git a/src/libstate/lookup.cpp b/src/libstate/lookup.cpp index 24a46e3e9..0d3f33573 100644 --- a/src/libstate/lookup.cpp +++ b/src/libstate/lookup.cpp @@ -62,6 +62,63 @@ size_t output_length_of(const std::string& name) } /* +* Query the minimum allowed key length of an algorithm implementation +*/ +size_t min_keylength_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* bc = af.prototype_block_cipher(name)) + return bc->key_spec().minimum_keylength(); + + if(const StreamCipher* sc = af.prototype_stream_cipher(name)) + return sc->key_spec().minimum_keylength(); + + if(const MessageAuthenticationCode* mac = af.prototype_mac(name)) + return mac->key_spec().minimum_keylength(); + + throw Algorithm_Not_Found(name); + } + +/* +* Query the maximum allowed keylength of an algorithm implementation +*/ +size_t max_keylength_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* bc = af.prototype_block_cipher(name)) + return bc->key_spec().maximum_keylength(); + + if(const StreamCipher* sc = af.prototype_stream_cipher(name)) + return sc->key_spec().maximum_keylength(); + + if(const MessageAuthenticationCode* mac = af.prototype_mac(name)) + return mac->key_spec().maximum_keylength(); + + throw Algorithm_Not_Found(name); + } + +/* +* Query the number of byte a valid key must be a multiple of +*/ +size_t keylength_multiple_of(const std::string& name) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(const BlockCipher* bc = af.prototype_block_cipher(name)) + return bc->key_spec().keylength_multiple(); + + if(const StreamCipher* sc = af.prototype_stream_cipher(name)) + return sc->key_spec().keylength_multiple(); + + if(const MessageAuthenticationCode* mac = af.prototype_mac(name)) + return mac->key_spec().keylength_multiple(); + + throw Algorithm_Not_Found(name); + } + +/* * Get a cipher object */ Keyed_Filter* get_cipher(const std::string& algo_spec, diff --git a/src/libstate/lookup.h b/src/libstate/lookup.h index 02c1708aa..e10c195b8 100644 --- a/src/libstate/lookup.h +++ b/src/libstate/lookup.h @@ -299,6 +299,36 @@ BOTAN_DLL size_t block_size_of(const std::string& algo_spec); */ BOTAN_DLL size_t output_length_of(const std::string& algo_spec); +/** +* Find out the minimum key size of a certain symmetric algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return minimum key length of the specified algorithm +*/ +BOTAN_DEPRECATED("Retrieve object you want and then call key_spec") +BOTAN_DLL size_t min_keylength_of(const std::string& algo_spec); + +/** +* Find out the maximum key size of a certain symmetric algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return maximum key length of the specified algorithm +*/ +BOTAN_DEPRECATED("Retrieve object you want and then call key_spec") +BOTAN_DLL size_t max_keylength_of(const std::string& algo_spec); + +/** +* Find out the size any valid key is a multiple of for a certain algorithm. +* @deprecated Call algorithm_factory() directly +* +* @param algo_spec the name of the algorithm +* @return size any valid key is a multiple of +*/ +BOTAN_DEPRECATED("Retrieve object you want and then call key_spec") +BOTAN_DLL size_t keylength_multiple_of(const std::string& algo_spec); + } #endif diff --git a/src/math/bigint/bigint.cpp b/src/math/bigint/bigint.cpp index a49335e75..ae536813f 100644 --- a/src/math/bigint/bigint.cpp +++ b/src/math/bigint/bigint.cpp @@ -1,6 +1,6 @@ /* * BigInt Base -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -26,8 +26,8 @@ BigInt::BigInt(u64bit n) const size_t limbs_needed = sizeof(u64bit) / sizeof(word); reg.resize(4*limbs_needed); - for(size_t j = 0; j != limbs_needed; ++j) - reg[j] = ((n >> (j*MP_WORD_BITS)) & MP_WORD_MASK); + for(size_t i = 0; i != limbs_needed; ++i) + reg[i] = ((n >> (i*MP_WORD_BITS)) & MP_WORD_MASK); } /* @@ -190,16 +190,35 @@ u32bit BigInt::get_substring(size_t offset, size_t length) const throw Invalid_Argument("BigInt::get_substring: Substring size too big"); u64bit piece = 0; - for(size_t j = 0; j != 8; ++j) - piece = (piece << 8) | byte_at((offset / 8) + (7-j)); + for(size_t i = 0; i != 8; ++i) + { + const byte part = byte_at((offset / 8) + (7-i)); + piece = (piece << 8) | part; + } - u64bit mask = (1 << length) - 1; - size_t shift = (offset % 8); + const u64bit mask = (static_cast<u64bit>(1) << length) - 1; + const size_t shift = (offset % 8); return static_cast<u32bit>((piece >> shift) & mask); } /* +* Convert this number to a u32bit, if possible +*/ +u32bit BigInt::to_u32bit() const + { + if(is_negative()) + throw Encoding_Error("BigInt::to_u32bit: Number is negative"); + if(bits() >= 32) + throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert"); + + u32bit out = 0; + for(u32bit j = 0; j != 4; ++j) + out = (out << 8) | byte_at(3-j); + return out; + } + +/* * Set bit number n */ void BigInt::set_bit(size_t n) @@ -233,8 +252,8 @@ void BigInt::mask_bits(size_t n) const word mask = (static_cast<word>(1) << (n % MP_WORD_BITS)) - 1; if(top_word < size()) - for(size_t j = top_word + 1; j != size(); ++j) - reg[j] = 0; + for(size_t i = top_word + 1; i != size(); ++i) + reg[i] = 0; reg[top_word] &= mask; } @@ -340,8 +359,8 @@ BigInt BigInt::abs() const void BigInt::binary_encode(byte output[]) const { const size_t sig_bytes = bytes(); - for(size_t j = 0; j != sig_bytes; ++j) - output[sig_bytes-j-1] = byte_at(j); + for(size_t i = 0; i != sig_bytes; ++i) + output[sig_bytes-i-1] = byte_at(i); } /* @@ -354,14 +373,15 @@ void BigInt::binary_decode(const byte buf[], size_t length) clear(); reg.resize(round_up<size_t>((length / WORD_BYTES) + 1, 8)); - for(size_t j = 0; j != length / WORD_BYTES; ++j) + for(size_t i = 0; i != length / WORD_BYTES; ++i) { - size_t top = length - WORD_BYTES*j; - for(size_t k = WORD_BYTES; k > 0; --k) - reg[j] = (reg[j] << 8) | buf[top - k]; + const size_t top = length - WORD_BYTES*i; + for(size_t j = WORD_BYTES; j > 0; --j) + reg[i] = (reg[i] << 8) | buf[top - j]; } - for(size_t j = 0; j != length % WORD_BYTES; ++j) - reg[length / WORD_BYTES] = (reg[length / WORD_BYTES] << 8) | buf[j]; + + for(size_t i = 0; i != length % WORD_BYTES; ++i) + reg[length / WORD_BYTES] = (reg[length / WORD_BYTES] << 8) | buf[i]; } /* diff --git a/src/math/bigint/bigint.h b/src/math/bigint/bigint.h index 5b3dcc2dd..06e3ecd2f 100644 --- a/src/math/bigint/bigint.h +++ b/src/math/bigint/bigint.h @@ -218,6 +218,13 @@ class BOTAN_DLL BigInt u32bit get_substring(size_t offset, size_t length) const; /** + * Convert this value into a u32bit, if it is in the range + * [0 ... 2**32-1], or otherwise throw an exception. + * @result the value as a u32bit if conversion is possible + */ + u32bit to_u32bit() const; + + /** * @param n the offset to get a byte from * @result byte at offset n */ diff --git a/src/math/numbertheory/curve_gfp.h b/src/math/ec_gfp/curve_gfp.h index 1ab803ec9..9867f82fe 100644 --- a/src/math/numbertheory/curve_gfp.h +++ b/src/math/ec_gfp/curve_gfp.h @@ -2,7 +2,7 @@ * Elliptic curves over GF(p) * * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke -* 2010 Jack Lloyd +* 2010-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -11,7 +11,6 @@ #define BOTAN_GFP_CURVE_H__ #include <botan/numthry.h> -#include <botan/reducer.h> namespace Botan { @@ -34,18 +33,15 @@ class BOTAN_DLL CurveGFp * @param b second coefficient */ CurveGFp(const BigInt& p, const BigInt& a, const BigInt& b) : - p(p), a(a), b(b), reducer_p(p) + p(p), a(a), b(b), p_words(p.sig_words()) { - r = 1; - r <<= p.sig_words() * BOTAN_MP_WORD_BITS; + BigInt r(BigInt::Power2, p_words * BOTAN_MP_WORD_BITS); - r_inv = inverse_mod(r, p); + p_dash = (((r * inverse_mod(r, p)) - 1) / p).word_at(0); - p_dash = (((r * r_inv) - 1) / p).word_at(0); - - a_r = reducer_p.multiply(a, r); - - p_words = p.sig_words(); + r2 = (r * r) % p; + a_r = (a * r) % p; + b_r = (b * r) % p; } // CurveGFp(const CurveGFp& other) = default; @@ -68,19 +64,19 @@ class BOTAN_DLL CurveGFp const BigInt& get_p() const { return p; } /** - * @return Montgomery parameter r + * @return Montgomery parameter r^2 % p */ - const BigInt& get_r() const { return r; } + const BigInt& get_r2() const { return r2; } /** - * @return Montgomery parameter r^-1 + * @return a * r mod p */ - const BigInt& get_r_inv() const { return r_inv; } + const BigInt& get_a_r() const { return a_r; } /** - * @return a * r mod p + * @return b * r mod p */ - const BigInt& get_a_r() const { return a_r; } + const BigInt& get_b_r() const { return b_r; } /** * @return Montgomery parameter p-dash @@ -93,23 +89,22 @@ class BOTAN_DLL CurveGFp size_t get_p_words() const { return p_words; } /** - * @return modular reducer for p - */ - const Modular_Reducer& mod_p() const { return reducer_p; } - - /** * swaps the states of *this and other, does not throw * @param other curve to swap values with */ void swap(CurveGFp& other) { + std::swap(p, other.p); + std::swap(a, other.a); std::swap(b, other.b); - std::swap(p, other.p); - std::swap(reducer_p, other.reducer_p); - std::swap(r, other.r); - std::swap(r_inv, other.r_inv); + std::swap(a_r, other.a_r); + std::swap(b_r, other.b_r); + + std::swap(p_words, other.p_words); + + std::swap(r2, other.r2); std::swap(p_dash, other.p_dash); } @@ -120,7 +115,11 @@ class BOTAN_DLL CurveGFp */ bool operator==(const CurveGFp& other) const { - return (p == other.p && a == other.a && b == other.b); + /* + Relies on choice of R, but that is fixed by constructor based + on size of p + */ + return (p == other.p && a_r == other.a_r && b_r == other.b_r); } private: @@ -130,10 +129,8 @@ class BOTAN_DLL CurveGFp size_t p_words; // cache of p.sig_words() // Montgomery parameters - BigInt r, r_inv, a_r; + BigInt r2, a_r, b_r; word p_dash; - - Modular_Reducer reducer_p; }; /** diff --git a/src/math/ec_gfp/info.txt b/src/math/ec_gfp/info.txt new file mode 100644 index 000000000..e6ee1d6bf --- /dev/null +++ b/src/math/ec_gfp/info.txt @@ -0,0 +1,16 @@ +define EC_CURVE_GFP + +load_on auto + +<header:public> +curve_gfp.h +point_gfp.h +</header:public> + +<source> +point_gfp.cpp +</source> + +<requires> +numbertheory +</requires> diff --git a/src/math/numbertheory/point_gfp.cpp b/src/math/ec_gfp/point_gfp.cpp index fab731d29..7ac6b4141 100644 --- a/src/math/numbertheory/point_gfp.cpp +++ b/src/math/ec_gfp/point_gfp.cpp @@ -1,40 +1,37 @@ /* -* Arithmetic for point groups of elliptic curves over GF(p) +* Point arithmetic on elliptic curves over GF(p) * * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke -* 2008-2010 Jack Lloyd +* 2008-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ #include <botan/point_gfp.h> #include <botan/numthry.h> +#include <botan/reducer.h> #include <botan/internal/mp_core.h> namespace Botan { PointGFp::PointGFp(const CurveGFp& curve) : - curve(curve), - coord_x(0), - coord_y(curve.get_r()), - coord_z(0) + curve(curve), ws(2 * (curve.get_p_words() + 2)) { + coord_x = 0; + coord_y = monty_mult(1, curve.get_r2()); + coord_z = 0; } PointGFp::PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y) : - curve(curve) + curve(curve), ws(2 * (curve.get_p_words() + 2)) { - const Modular_Reducer& mod_p = curve.mod_p(); - - coord_x = mod_p.multiply(curve.get_r(), x); - coord_y = mod_p.multiply(curve.get_r(), y); - coord_z = mod_p.reduce(curve.get_r()); + coord_x = monty_mult(x, curve.get_r2()); + coord_y = monty_mult(y, curve.get_r2()); + coord_z = monty_mult(1, curve.get_r2()); } // Montgomery multiplication -void PointGFp::monty_mult(BigInt& z, - const BigInt& x, const BigInt& y, - MemoryRegion<word>& workspace) const +void PointGFp::monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const { //assert(&z != &x && &z != &y); @@ -52,19 +49,15 @@ void PointGFp::monty_mult(BigInt& z, z_reg.resize(2*p_size+1); zeroise(z_reg); - bigint_mul(&z_reg[0], z_reg.size(), - &workspace[0], - x.data(), x.size(), x.sig_words(), - y.data(), y.size(), y.sig_words()); - - bigint_monty_redc(&z[0], z.size(), - &workspace[0], - p.data(), p_size, p_dash); + bigint_monty_mul(&z_reg[0], z_reg.size(), + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), y.sig_words(), + p.data(), p_size, p_dash, + &ws[0]); } // Montgomery squaring -void PointGFp::monty_sqr(BigInt& z, const BigInt& x, - MemoryRegion<word>& workspace) const +void PointGFp::monty_sqr(BigInt& z, const BigInt& x) const { //assert(&z != &x); @@ -82,17 +75,14 @@ void PointGFp::monty_sqr(BigInt& z, const BigInt& x, z_reg.resize(2*p_size+1); zeroise(z_reg); - bigint_sqr(&z[0], z.size(), - &workspace[0], - x.data(), x.size(), x.sig_words()); - - bigint_monty_redc(&z[0], z.size(), - &workspace[0], - p.data(), p_size, p_dash); + bigint_monty_sqr(&z_reg[0], z_reg.size(), + x.data(), x.size(), x.sig_words(), + p.data(), p_size, p_dash, + &ws[0]); } // Point addition -void PointGFp::add(const PointGFp& rhs, Workspace& workspace) +void PointGFp::add(const PointGFp& rhs, std::vector<BigInt>& ws_bn) { if(is_zero()) { @@ -106,9 +96,6 @@ void PointGFp::add(const PointGFp& rhs, Workspace& workspace) const BigInt& p = curve.get_p(); - MemoryRegion<word>& ws = workspace.ws_monty; - std::vector<BigInt>& ws_bn = workspace.ws_bn; - BigInt& rhs_z2 = ws_bn[0]; BigInt& U1 = ws_bn[1]; BigInt& S1 = ws_bn[2]; @@ -120,17 +107,13 @@ void PointGFp::add(const PointGFp& rhs, Workspace& workspace) BigInt& H = ws_bn[6]; BigInt& r = ws_bn[7]; - BigInt& x = ws_bn[8]; - BigInt& y = ws_bn[9]; - BigInt& z = ws_bn[10]; + monty_sqr(rhs_z2, rhs.coord_z); + monty_mult(U1, coord_x, rhs_z2); + monty_mult(S1, coord_y, monty_mult(rhs.coord_z, rhs_z2)); - monty_sqr(rhs_z2, rhs.coord_z, ws); - monty_mult(U1, coord_x, rhs_z2, ws); - monty_mult(S1, coord_y, monty_mult(rhs.coord_z, rhs_z2, ws), ws); - - monty_sqr(lhs_z2, coord_z, ws); - monty_mult(U2, rhs.coord_x, lhs_z2, ws); - monty_mult(S2, rhs.coord_y, monty_mult(coord_z, lhs_z2, ws), ws); + monty_sqr(lhs_z2, coord_z); + monty_mult(U2, rhs.coord_x, lhs_z2); + monty_mult(S2, rhs.coord_y, monty_mult(coord_z, lhs_z2)); H = U2; H -= U1; @@ -146,7 +129,7 @@ void PointGFp::add(const PointGFp& rhs, Workspace& workspace) { if(r.is_zero()) { - mult2(workspace); + mult2(ws_bn); return; } @@ -154,36 +137,32 @@ void PointGFp::add(const PointGFp& rhs, Workspace& workspace) return; } - monty_sqr(U2, H, ws); + monty_sqr(U2, H); - monty_mult(S2, U2, H, ws); + monty_mult(S2, U2, H); - U2 = monty_mult(U1, U2, ws); + U2 = monty_mult(U1, U2); - monty_sqr(x, r, ws); - x -= S2; - x -= (U2 << 1); - while(x.is_negative()) - x += p; + monty_sqr(coord_x, r); + coord_x -= S2; + coord_x -= (U2 << 1); + while(coord_x.is_negative()) + coord_x += p; - U2 -= x; + U2 -= coord_x; if(U2.is_negative()) U2 += p; - monty_mult(y, r, U2, ws); - y -= monty_mult(S1, S2, ws); - if(y.is_negative()) - y += p; - - monty_mult(z, monty_mult(coord_z, rhs.coord_z, ws), H, ws); + monty_mult(coord_y, r, U2); + coord_y -= monty_mult(S1, S2); + if(coord_y.is_negative()) + coord_y += p; - coord_x = x; - coord_y = y; - coord_z = z; + monty_mult(coord_z, monty_mult(coord_z, rhs.coord_z), H); } // *this *= 2 -void PointGFp::mult2(Workspace& workspace) +void PointGFp::mult2(std::vector<BigInt>& ws_bn) { if(is_zero()) return; @@ -195,9 +174,6 @@ void PointGFp::mult2(Workspace& workspace) const BigInt& p = curve.get_p(); - MemoryRegion<word>& ws = workspace.ws_monty; - std::vector<BigInt>& ws_bn = workspace.ws_bn; - BigInt& y_2 = ws_bn[0]; BigInt& S = ws_bn[1]; BigInt& z4 = ws_bn[2]; @@ -208,27 +184,27 @@ void PointGFp::mult2(Workspace& workspace) BigInt& y = ws_bn[7]; BigInt& z = ws_bn[8]; - monty_sqr(y_2, coord_y, ws); + monty_sqr(y_2, coord_y); - monty_mult(S, coord_x, y_2, ws); + monty_mult(S, coord_x, y_2); S <<= 2; // * 4 while(S >= p) S -= p; - monty_sqr(z4, monty_sqr(coord_z, ws), ws); - monty_mult(a_z4, curve.get_a_r(), z4, ws); + monty_sqr(z4, monty_sqr(coord_z)); + monty_mult(a_z4, curve.get_a_r(), z4); - M = 3 * monty_sqr(coord_x, ws); + M = 3 * monty_sqr(coord_x); M += a_z4; while(M >= p) M -= p; - monty_sqr(x, M, ws); + monty_sqr(x, M); x -= (S << 1); while(x.is_negative()) x += p; - monty_sqr(U, y_2, ws); + monty_sqr(U, y_2); U <<= 3; while(U >= p) U -= p; @@ -237,12 +213,12 @@ void PointGFp::mult2(Workspace& workspace) while(S.is_negative()) S += p; - monty_mult(y, M, S, ws); + monty_mult(y, M, S); y -= U; if(y.is_negative()) y += p; - monty_mult(z, coord_y, coord_z, ws); + monty_mult(z, coord_y, coord_z); z <<= 1; if(z >= p) z -= p; @@ -255,7 +231,7 @@ void PointGFp::mult2(Workspace& workspace) // arithmetic operators PointGFp& PointGFp::operator+=(const PointGFp& rhs) { - Workspace ws(curve.get_p_words()); + std::vector<BigInt> ws(9); add(rhs, ws); return *this; } @@ -278,6 +254,39 @@ PointGFp& PointGFp::operator*=(const BigInt& scalar) return *this; } +PointGFp multi_exponentiate(const PointGFp& p1, const BigInt& z1, + const PointGFp& p2, const BigInt& z2) + { + const PointGFp p3 = p1 + p2; + + PointGFp H(p1.curve); // create as zero + size_t bits_left = std::max(z1.bits(), z2.bits()); + + std::vector<BigInt> ws(9); + + while(bits_left) + { + H.mult2(ws); + + const bool z1_b = z1.get_bit(bits_left - 1); + const bool z2_b = z2.get_bit(bits_left - 1); + + if(z1_b == true && z2_b == true) + H.add(p3, ws); + else if(z1_b) + H.add(p1, ws); + else if(z2_b) + H.add(p2, ws); + + --bits_left; + } + + if(z1.is_negative() != z2.is_negative()) + H.negate(); + + return H; + } + PointGFp operator*(const BigInt& scalar, const PointGFp& point) { const CurveGFp& curve = point.get_curve(); @@ -285,7 +294,7 @@ PointGFp operator*(const BigInt& scalar, const PointGFp& point) if(scalar.is_zero()) return PointGFp(curve); // zero point - PointGFp::Workspace ws(curve.get_p_words()); + std::vector<BigInt> ws(9); if(scalar.abs() <= 2) // special cases for small values { @@ -304,6 +313,38 @@ PointGFp operator*(const BigInt& scalar, const PointGFp& point) const size_t scalar_bits = scalar.bits(); +#if 0 + + PointGFp x1 = PointGFp(curve); + PointGFp x2 = point; + + size_t bits_left = scalar_bits; + + // Montgomery Ladder + while(bits_left) + { + const bool bit_set = scalar.get_bit(bits_left - 1); + + if(bit_set) + { + x1.add(x2, ws); + x2.mult2(ws); + } + else + { + x2.add(x1, ws); + x1.mult2(ws); + } + + --bits_left; + } + + if(scalar.is_negative()) + x1.negate(); + + return x1; + +#else const size_t window_size = 4; std::vector<PointGFp> Ps(1 << window_size); @@ -345,6 +386,7 @@ PointGFp operator*(const BigInt& scalar, const PointGFp& point) H.negate(); return H; +#endif } BigInt PointGFp::get_affine_x() const @@ -352,23 +394,13 @@ BigInt PointGFp::get_affine_x() const if(is_zero()) throw Illegal_Transformation("Cannot convert zero point to affine"); - const Modular_Reducer& mod_p = curve.mod_p(); - -#if 1 - BigInt x = mod_p.multiply(curve.get_r_inv(), coord_x); - BigInt z = mod_p.multiply(curve.get_r_inv(), coord_z); - - BigInt z2 = mod_p.square(z); - return mod_p.multiply(x, inverse_mod(z2, curve.get_p())); -#else - - SecureVector<word> ws(2 * (curve.get_p_words() + 2)); + const BigInt& r2 = curve.get_r2(); - BigInt z2 = monty_sqr(coord_z, ws); + BigInt z2 = monty_sqr(coord_z); z2 = inverse_mod(z2, curve.get_p()); - z2 = mod_p.multiply(z2, curve.get_r()); - return monty_mult(coord_x, z2, ws); -#endif + + z2 = monty_mult(z2, r2); + return monty_mult(coord_x, z2); } BigInt PointGFp::get_affine_y() const @@ -376,23 +408,12 @@ BigInt PointGFp::get_affine_y() const if(is_zero()) throw Illegal_Transformation("Cannot convert zero point to affine"); - const Modular_Reducer& mod_p = curve.mod_p(); + const BigInt& r2 = curve.get_r2(); -#if 1 - BigInt y = mod_p.multiply(curve.get_r_inv(), coord_y); - BigInt z = mod_p.multiply(curve.get_r_inv(), coord_z); - - BigInt z3 = mod_p.cube(z); - return mod_p.multiply(y, inverse_mod(z3, curve.get_p())); -#else - - SecureVector<word> ws(2 * (curve.get_p_words() + 2)); - - BigInt z3 = monty_mult(coord_z, monty_sqr(coord_z, ws), ws); + BigInt z3 = monty_mult(coord_z, monty_sqr(coord_z)); z3 = inverse_mod(z3, curve.get_p()); - z3 = mod_p.multiply(z3, curve.get_r()); - return monty_mult(coord_y, z3, ws); -#endif + z3 = monty_mult(z3, r2); + return monty_mult(coord_y, z3); } bool PointGFp::on_the_curve() const @@ -407,31 +428,28 @@ bool PointGFp::on_the_curve() const if(is_zero()) return true; - const Modular_Reducer& mod_p = curve.mod_p(); + BigInt y2 = monty_mult(monty_sqr(coord_y), 1); + BigInt x3 = monty_mult(coord_x, monty_sqr(coord_x)); - BigInt x = mod_p.multiply(curve.get_r_inv(), coord_x); - BigInt y = mod_p.multiply(curve.get_r_inv(), coord_y); - BigInt z = mod_p.multiply(curve.get_r_inv(), coord_z); + BigInt ax = monty_mult(coord_x, curve.get_a_r()); - BigInt y2 = mod_p.square(y); - BigInt x3 = mod_p.cube(x); + const BigInt& b_r = curve.get_b_r(); - BigInt ax = mod_p.multiply(x, curve.get_a()); + BigInt z2 = monty_sqr(coord_z); - if(z == 1) + if(coord_z == z2) // Is z equal to 1 (in Montgomery form)? { - if(mod_p.reduce(x3 + ax + curve.get_b()) != y2) + if(y2 != monty_mult(x3 + ax + b_r, 1)) return false; } - BigInt z2 = mod_p.square(z); - BigInt z3 = mod_p.multiply(z, z2); + BigInt z3 = monty_mult(coord_z, z2); - BigInt ax_z4 = mod_p.multiply(mod_p.multiply(z3, z), ax); + BigInt ax_z4 = monty_mult(ax, monty_sqr(z2)); - BigInt b_z6 = mod_p.multiply(curve.get_b(), mod_p.square(z3)); + BigInt b_z6 = monty_mult(b_r, monty_sqr(z3)); - if(y2 != mod_p.reduce(x3 + ax_z4 + b_z6)) + if(y2 != monty_mult(x3 + ax_z4 + b_z6, 1)) return false; return true; @@ -444,6 +462,7 @@ void PointGFp::swap(PointGFp& other) coord_x.swap(other.coord_x); coord_y.swap(other.coord_y); coord_z.swap(other.coord_z); + ws.swap(other.ws); } bool PointGFp::operator==(const PointGFp& other) const diff --git a/src/math/numbertheory/point_gfp.h b/src/math/ec_gfp/point_gfp.h index 35ec6d503..b2b6fe2f0 100644 --- a/src/math/numbertheory/point_gfp.h +++ b/src/math/ec_gfp/point_gfp.h @@ -1,8 +1,8 @@ /* -* Arithmetic for point groups of elliptic curves over GF(p) +* Point arithmetic on elliptic curves over GF(p) * * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke -* 2008-2010 Jack Lloyd +* 2008-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -99,6 +99,18 @@ class BOTAN_DLL PointGFp friend BOTAN_DLL PointGFp operator*(const BigInt& scalar, const PointGFp& point); /** + * Multiexponentiation + * @param p1 a point + * @param z1 a scalar + * @param p2 a point + * @param z2 a scalar + * @result (p1 * z1 + p2 * z2) + */ + friend BOTAN_DLL PointGFp multi_exponentiate( + const PointGFp& p1, const BigInt& z1, + const PointGFp& p2, const BigInt& z2); + + /** * Negate this point * @return *this */ @@ -153,27 +165,16 @@ class BOTAN_DLL PointGFp bool operator==(const PointGFp& other) const; private: - class Workspace - { - public: - Workspace(size_t p_words) : - ws_monty(2*(p_words+2)), ws_bn(12) {} - - SecureVector<word> ws_monty; - std::vector<BigInt> ws_bn; - }; - /** * Montgomery multiplication/reduction * @param x first multiplicand * @param y second multiplicand * @param workspace temp space */ - BigInt monty_mult(const BigInt& x, const BigInt& y, - MemoryRegion<word>& workspace) const + BigInt monty_mult(const BigInt& x, const BigInt& y) const { BigInt result; - monty_mult(result, x, y, workspace); + monty_mult(result, x, y); return result; } @@ -183,22 +184,17 @@ class BOTAN_DLL PointGFp * @param z output * @param x first multiplicand * @param y second multiplicand - * @param workspace temp space */ - void monty_mult(BigInt& z, - const BigInt& x, const BigInt& y, - MemoryRegion<word>& workspace) const; + void monty_mult(BigInt& z, const BigInt& x, const BigInt& y) const; /** * Montgomery squaring/reduction * @param x multiplicand - * @param workspace temp space */ - BigInt monty_sqr(const BigInt& x, - MemoryRegion<word>& workspace) const + BigInt monty_sqr(const BigInt& x) const { BigInt result; - monty_sqr(result, x, workspace); + monty_sqr(result, x); return result; } @@ -207,24 +203,24 @@ class BOTAN_DLL PointGFp * @warning z cannot alias x * @param z output * @param x multiplicand - * @param workspace temp space */ - void monty_sqr(BigInt& z, const BigInt& x, - MemoryRegion<word>& workspace) const; + void monty_sqr(BigInt& z, const BigInt& x) const; /** * Point addition + * @param workspace temp space, at least 11 elements */ - void add(const PointGFp& other, Workspace& workspace); + void add(const PointGFp& other, std::vector<BigInt>& workspace); /** * Point doubling - * @param workspace temp space + * @param workspace temp space, at least 9 elements */ - void mult2(Workspace& workspace); + void mult2(std::vector<BigInt>& workspace); CurveGFp curve; BigInt coord_x, coord_y, coord_z; + mutable SecureVector<word> ws; // workspace for Montgomery }; // relational operators diff --git a/src/math/mp/info.txt b/src/math/mp/info.txt index a3c994d8b..bf7f40d3c 100644 --- a/src/math/mp/info.txt +++ b/src/math/mp/info.txt @@ -4,6 +4,8 @@ define BIGINT_MP mp_asm.cpp mp_comba.cpp mp_karat.cpp +mp_monty.cpp +mp_mulop.cpp mp_misc.cpp mp_shift.cpp </source> @@ -17,7 +19,5 @@ mp_core.h </header:internal> <requires> -mp_amd64|mp_msvc64|mp_asm64|mp_ia32|mp_ia32_msvc|mp_generic -monty_generic -mulop_generic +mp_x86_64|mp_msvc64|mp_asm64|mp_x86_32|mp_x86_32_msvc|mp_generic </requires> diff --git a/src/math/mp/monty_generic/info.txt b/src/math/mp/monty_generic/info.txt deleted file mode 100644 index cd05ccdc0..000000000 --- a/src/math/mp/monty_generic/info.txt +++ /dev/null @@ -1,5 +0,0 @@ -load_on dep - -<source> -mp_monty.cpp -</source> diff --git a/src/math/mp/monty_generic/mp_monty.cpp b/src/math/mp/monty_generic/mp_monty.cpp deleted file mode 100644 index d7f7e0306..000000000 --- a/src/math/mp/monty_generic/mp_monty.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -* Montgomery Reduction -* (C) 1999-2010 Jack Lloyd -* 2006 Luca Piccarreta -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/internal/mp_core.h> -#include <botan/internal/mp_asm.h> -#include <botan/internal/mp_asmi.h> -#include <botan/mem_ops.h> - -namespace Botan { - -extern "C" { - -/* -* Montgomery Reduction Algorithm -*/ -void bigint_monty_redc(word z[], size_t z_size, - word ws[], - const word x[], size_t x_size, - word u) - { - const size_t blocks_of_8 = x_size - (x_size % 8); - - for(size_t i = 0; i != x_size; ++i) - { - word* z_i = z + i; - - const word y = z_i[0] * u; - - /* - bigint_linmul3(ws, x, x_size, y); - bigint_add2(z_i, z_size - i, ws, x_size+1); - */ - word carry = 0; - - for(size_t j = 0; j != blocks_of_8; j += 8) - carry = word8_madd3(z_i + j, x + j, y, carry); - - for(size_t j = blocks_of_8; j != x_size; ++j) - z_i[j] = word_madd3(x[j], y, z_i[j], &carry); - - word z_sum = z_i[x_size] + carry; - carry = (z_sum < z_i[x_size]); - z_i[x_size] = z_sum; - - // Note: not constant time - for(size_t j = x_size + 1; carry && j != z_size - i; ++j) - { - ++z_i[j]; - carry = !z_i[j]; - } - } - - word borrow = 0; - for(size_t i = 0; i != x_size; ++i) - ws[i] = word_sub(z[x_size + i], x[i], &borrow); - - ws[x_size] = word_sub(z[x_size+x_size], 0, &borrow); - - copy_mem(ws + x_size + 1, z + x_size, x_size + 1); - - copy_mem(z, ws + borrow*(x_size+1), x_size + 1); - clear_mem(z + x_size + 1, z_size - x_size - 1); - } - -} - -} diff --git a/src/math/mp/mp_asm.cpp b/src/math/mp/mp_asm.cpp index d164c1d33..3ba52c4b1 100644 --- a/src/math/mp/mp_asm.cpp +++ b/src/math/mp/mp_asm.cpp @@ -67,7 +67,8 @@ word bigint_add3_nc(word z[], const word x[], size_t x_size, */ void bigint_add2(word x[], size_t x_size, const word y[], size_t y_size) { - x[x_size] += bigint_add2_nc(x, x_size, y, y_size); + if(bigint_add2_nc(x, x_size, y, y_size)) + x[x_size] += 1; } /* diff --git a/src/math/mp/mp_asm64/info.txt b/src/math/mp/mp_asm64/info.txt index fd0242a7a..9af7c4ae7 100644 --- a/src/math/mp/mp_asm64/info.txt +++ b/src/math/mp/mp_asm64/info.txt @@ -8,7 +8,6 @@ mp_generic:mp_asmi.h </header:internal> <arch> -#amd64 alpha ia64 mips64 @@ -21,5 +20,5 @@ sparc64 # win, so it's probably worth using elsewhere. <cc> gcc -sunwspro +sunstudio </cc> diff --git a/src/math/mp/mp_core.h b/src/math/mp/mp_core.h index e1692006e..40327b02b 100644 --- a/src/math/mp/mp_core.h +++ b/src/math/mp/mp_core.h @@ -77,19 +77,35 @@ void bigint_simple_sqr(word z[], const word x[], size_t x_size); void bigint_linmul2(word x[], size_t x_size, word y); void bigint_linmul3(word z[], const word x[], size_t x_size, word y); -/* +/** * Montgomery Reduction -* @param z integer to reduce (also output in first x_size+1 words) -* @param z_size size of z (should be >= 2*x_size+1) -* @param workspace array of at least 2*(x_size+1) words -* @param x modulus -* @param x_size size of x -* @param u Montgomery value +* @param z integer to reduce (also output in first p_size+1 words) +* @param z_size size of z (should be >= 2*p_size+1) +* @param p modulus +* @param p_size size of p +* @param p_dash Montgomery value +* @param workspace array of at least 2*(p_size+1) words */ void bigint_monty_redc(word z[], size_t z_size, - word workspace[], - const word x[], size_t x_size, - word u); + const word p[], size_t p_size, word p_dash, + word workspace[]); + +/* +* Montgomery Multiplication +*/ +void bigint_monty_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + const word p[], size_t p_size, word p_dash, + word workspace[]); + +/* +* Montgomery Squaring +*/ +void bigint_monty_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word p[], size_t p_size, word p_dash, + word workspace[]); /* * Division operation diff --git a/src/math/mp/mp_generic/mp_asm.h b/src/math/mp/mp_generic/mp_asm.h index ee46e1aa9..7c18343ef 100644 --- a/src/math/mp/mp_generic/mp_asm.h +++ b/src/math/mp/mp_generic/mp_asm.h @@ -14,7 +14,7 @@ #if (BOTAN_MP_WORD_BITS == 8) typedef Botan::u16bit dword; #elif (BOTAN_MP_WORD_BITS == 16) - typedef Botan::size_t dword; + typedef Botan::u32bit dword; #elif (BOTAN_MP_WORD_BITS == 32) typedef Botan::u64bit dword; #elif (BOTAN_MP_WORD_BITS == 64) diff --git a/src/math/mp/mp_monty.cpp b/src/math/mp/mp_monty.cpp new file mode 100644 index 000000000..d37fb5844 --- /dev/null +++ b/src/math/mp/mp_monty.cpp @@ -0,0 +1,99 @@ +/* +* Montgomery Reduction +* (C) 1999-2011 Jack Lloyd +* 2006 Luca Piccarreta +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/mp_core.h> +#include <botan/internal/mp_asm.h> +#include <botan/internal/mp_asmi.h> +#include <botan/mem_ops.h> + +namespace Botan { + +extern "C" { + +/* +* Montgomery Reduction Algorithm +*/ +void bigint_monty_redc(word z[], size_t z_size, + const word p[], size_t p_size, + word p_dash, word ws[]) + { + const size_t blocks_of_8 = p_size - (p_size % 8); + + for(size_t i = 0; i != p_size; ++i) + { + word* z_i = z + i; + + const word y = z_i[0] * p_dash; + + /* + bigint_linmul3(ws, p, p_size, y); + bigint_add2(z_i, z_size - i, ws, p_size+1); + */ + + word carry = 0; + + for(size_t j = 0; j != blocks_of_8; j += 8) + carry = word8_madd3(z_i + j, p + j, y, carry); + + for(size_t j = blocks_of_8; j != p_size; ++j) + z_i[j] = word_madd3(p[j], y, z_i[j], &carry); + + word z_sum = z_i[p_size] + carry; + carry = (z_sum < z_i[p_size]); + z_i[p_size] = z_sum; + + for(size_t j = p_size + 1; carry && j != z_size - i; ++j) + { + ++z_i[j]; + carry = !z_i[j]; + } + } + + word borrow = 0; + for(size_t i = 0; i != p_size; ++i) + ws[i] = word_sub(z[p_size + i], p[i], &borrow); + + ws[p_size] = word_sub(z[p_size+p_size], 0, &borrow); + + copy_mem(ws + p_size + 1, z + p_size, p_size + 1); + + copy_mem(z, ws + borrow*(p_size+1), p_size + 1); + clear_mem(z + p_size + 1, z_size - p_size - 1); + } + +void bigint_monty_mul(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word y[], size_t y_size, size_t y_sw, + const word p[], size_t p_size, word p_dash, + word ws[]) + { + bigint_mul(&z[0], z_size, &ws[0], + &x[0], x_size, x_sw, + &y[0], y_size, y_sw); + + bigint_monty_redc(&z[0], z_size, + &p[0], p_size, p_dash, + &ws[0]); + } + +void bigint_monty_sqr(word z[], size_t z_size, + const word x[], size_t x_size, size_t x_sw, + const word p[], size_t p_size, word p_dash, + word ws[]) + { + bigint_sqr(&z[0], z_size, &ws[0], + &x[0], x_size, x_sw); + + bigint_monty_redc(&z[0], z_size, + &p[0], p_size, p_dash, + &ws[0]); + } + +} + +} diff --git a/src/math/mp/mp_msvc64/info.txt b/src/math/mp/mp_msvc64/info.txt index 56ae05927..fa7d90fed 100644 --- a/src/math/mp/mp_msvc64/info.txt +++ b/src/math/mp/mp_msvc64/info.txt @@ -8,7 +8,7 @@ mp_generic:mp_asmi.h </header:internal> <arch> -amd64 +x86_64 ia64 </arch> diff --git a/src/math/mp/mulop_generic/mp_mulop.cpp b/src/math/mp/mp_mulop.cpp index e6a8ba891..e6a8ba891 100644 --- a/src/math/mp/mulop_generic/mp_mulop.cpp +++ b/src/math/mp/mp_mulop.cpp diff --git a/src/math/mp/mp_ia32/info.txt b/src/math/mp/mp_x86_32/info.txt index 1659f74cf..432f909f8 100644 --- a/src/math/mp/mp_ia32/info.txt +++ b/src/math/mp/mp_x86_32/info.txt @@ -8,7 +8,7 @@ mp_asmi.h </header:internal> <arch> -ia32 +x86_32 </arch> <cc> diff --git a/src/math/mp/mp_ia32/mp_asm.h b/src/math/mp/mp_x86_32/mp_asm.h index 4d3afc992..9be5680f8 100644 --- a/src/math/mp/mp_ia32/mp_asm.h +++ b/src/math/mp/mp_x86_32/mp_asm.h @@ -12,7 +12,7 @@ #include <botan/mp_types.h> #if (BOTAN_MP_WORD_BITS != 32) - #error The mp_ia32 module requires that BOTAN_MP_WORD_BITS == 32 + #error The mp_x86_32 module requires that BOTAN_MP_WORD_BITS == 32 #endif namespace Botan { diff --git a/src/math/mp/mp_ia32/mp_asmi.h b/src/math/mp/mp_x86_32/mp_asmi.h index c7b679e80..c7b679e80 100644 --- a/src/math/mp/mp_ia32/mp_asmi.h +++ b/src/math/mp/mp_x86_32/mp_asmi.h diff --git a/src/math/mp/mp_ia32_msvc/info.txt b/src/math/mp/mp_x86_32_msvc/info.txt index 55a42c310..8d35c02e7 100644 --- a/src/math/mp/mp_ia32_msvc/info.txt +++ b/src/math/mp/mp_x86_32_msvc/info.txt @@ -8,7 +8,7 @@ mp_asmi.h </header:internal> <arch> -ia32 +x86_32 </arch> <cc> diff --git a/src/math/mp/mp_ia32_msvc/mp_asmi.h b/src/math/mp/mp_x86_32_msvc/mp_asmi.h index aee457d65..aee457d65 100644 --- a/src/math/mp/mp_ia32_msvc/mp_asmi.h +++ b/src/math/mp/mp_x86_32_msvc/mp_asmi.h diff --git a/src/math/mp/mp_amd64/info.txt b/src/math/mp/mp_x86_64/info.txt index 11cc380e2..fdcc05dd6 100644 --- a/src/math/mp/mp_amd64/info.txt +++ b/src/math/mp/mp_x86_64/info.txt @@ -8,7 +8,7 @@ mp_asmi.h </header:internal> <arch> -amd64 +x86_64 </arch> <cc> diff --git a/src/math/mp/mp_amd64/mp_asm.h b/src/math/mp/mp_x86_64/mp_asm.h index fa66d04f3..edfaf6352 100644 --- a/src/math/mp/mp_amd64/mp_asm.h +++ b/src/math/mp/mp_x86_64/mp_asm.h @@ -12,7 +12,7 @@ #include <botan/mp_types.h> #if (BOTAN_MP_WORD_BITS != 64) - #error The mp_amd64 module requires that BOTAN_MP_WORD_BITS == 64 + #error The mp_x86_64 module requires that BOTAN_MP_WORD_BITS == 64 #endif namespace Botan { @@ -20,7 +20,7 @@ namespace Botan { extern "C" { /* -* Helper Macros for amd64 Assembly +* Helper Macros for x86-64 Assembly */ #define ASM(x) x "\n\t" diff --git a/src/math/mp/mp_amd64/mp_asmi.h b/src/math/mp/mp_x86_64/mp_asmi.h index adf7774ef..f14df0e89 100644 --- a/src/math/mp/mp_amd64/mp_asmi.h +++ b/src/math/mp/mp_x86_64/mp_asmi.h @@ -16,7 +16,7 @@ namespace Botan { extern "C" { /* -* Helper Macros for amd64 Assembly +* Helper Macros for x86-64 Assembly */ #ifndef ASM #define ASM(x) x "\n\t" diff --git a/src/math/mp/mulop_generic/info.txt b/src/math/mp/mulop_generic/info.txt deleted file mode 100644 index 548d0f44b..000000000 --- a/src/math/mp/mulop_generic/info.txt +++ /dev/null @@ -1,5 +0,0 @@ -load_on dep - -<source> -mp_mulop.cpp -</source> diff --git a/src/math/numbertheory/info.txt b/src/math/numbertheory/info.txt index 18349ef78..0c6a9aefc 100644 --- a/src/math/numbertheory/info.txt +++ b/src/math/numbertheory/info.txt @@ -1,11 +1,9 @@ -load_on auto - define BIGINT_MATH +load_on auto + <header:public> -curve_gfp.h numthry.h -point_gfp.h pow_mod.h reducer.h </header:public> @@ -20,7 +18,6 @@ jacobi.cpp make_prm.cpp mp_numth.cpp numthry.cpp -point_gfp.cpp pow_mod.cpp powm_fw.cpp powm_mnt.cpp diff --git a/src/math/numbertheory/pow_mod.cpp b/src/math/numbertheory/pow_mod.cpp index a66a1f7df..bf6b29275 100644 --- a/src/math/numbertheory/pow_mod.cpp +++ b/src/math/numbertheory/pow_mod.cpp @@ -118,7 +118,12 @@ size_t Power_Mod::window_bits(size_t exp_bits, size_t, Power_Mod::Usage_Hints hints) { static const size_t wsize[][2] = { - { 2048, 7 }, { 1024, 6 }, { 256, 5 }, { 128, 4 }, { 64, 3 }, { 0, 0 } + { 1434, 7 }, + { 539, 6 }, + { 197, 4 }, + { 70, 3 }, + { 25, 2 }, + { 0, 0 } }; size_t window_bits = 1; diff --git a/src/math/numbertheory/powm_mnt.cpp b/src/math/numbertheory/powm_mnt.cpp index 421470364..8993f4ba9 100644 --- a/src/math/numbertheory/powm_mnt.cpp +++ b/src/math/numbertheory/powm_mnt.cpp @@ -33,13 +33,12 @@ void Montgomery_Exponentiator::set_base(const BigInt& base) SecureVector<word> workspace(z.size()); g[0] = (base >= modulus) ? (base % modulus) : base; - bigint_mul(&z[0], z.size(), &workspace[0], - g[0].data(), g[0].size(), g[0].sig_words(), - R2.data(), R2.size(), R2.sig_words()); - bigint_monty_redc(&z[0], z.size(), - &workspace[0], - modulus.data(), mod_words, mod_prime); + bigint_monty_mul(&z[0], z.size(), + g[0].data(), g[0].size(), g[0].sig_words(), + R2.data(), R2.size(), R2.sig_words(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); g[0].assign(&z[0], mod_words + 1); @@ -52,13 +51,11 @@ void Montgomery_Exponentiator::set_base(const BigInt& base) const size_t y_sig = y.sig_words(); zeroise(z); - bigint_mul(&z[0], z.size(), &workspace[0], - x.data(), x.size(), x_sig, - y.data(), y.size(), y_sig); - - bigint_monty_redc(&z[0], z.size(), - &workspace[0], - modulus.data(), mod_words, mod_prime); + bigint_monty_mul(&z[0], z.size(), + x.data(), x.size(), x_sig, + y.data(), y.size(), y_sig, + modulus.data(), mod_words, mod_prime, + &workspace[0]); g[i].assign(&z[0], mod_words + 1); } @@ -80,12 +77,11 @@ BigInt Montgomery_Exponentiator::execute() const for(size_t k = 0; k != window_bits; ++k) { zeroise(z); - bigint_sqr(&z[0], z.size(), &workspace[0], - x.data(), x.size(), x.sig_words()); - bigint_monty_redc(&z[0], z.size(), - &workspace[0], - modulus.data(), mod_words, mod_prime); + bigint_monty_sqr(&z[0], z.size(), + x.data(), x.size(), x.sig_words(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); x.assign(&z[0], mod_words + 1); } @@ -95,13 +91,11 @@ BigInt Montgomery_Exponentiator::execute() const const BigInt& y = g[nibble-1]; zeroise(z); - bigint_mul(&z[0], z.size(), &workspace[0], - x.data(), x.size(), x.sig_words(), - y.data(), y.size(), y.sig_words()); - - bigint_monty_redc(&z[0], z.size(), - &workspace[0], - modulus.data(), mod_words, mod_prime); + bigint_monty_mul(&z[0], z.size(), + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), y.sig_words(), + modulus.data(), mod_words, mod_prime, + &workspace[0]); x.assign(&z[0], mod_words + 1); } @@ -110,8 +104,8 @@ BigInt Montgomery_Exponentiator::execute() const x.get_reg().resize(2*mod_words+1); bigint_monty_redc(&x[0], x.size(), - &workspace[0], - modulus.data(), mod_words, mod_prime); + modulus.data(), mod_words, mod_prime, + &workspace[0]); x.get_reg().resize(mod_words+1); @@ -134,14 +128,12 @@ Montgomery_Exponentiator::Montgomery_Exponentiator(const BigInt& mod, mod_words = modulus.sig_words(); - BigInt mod_prime_bn(BigInt::Power2, MP_WORD_BITS); - mod_prime = (mod_prime_bn - inverse_mod(modulus, mod_prime_bn)).word_at(0); + BigInt r(BigInt::Power2, mod_words * BOTAN_MP_WORD_BITS); + mod_prime = (((r * inverse_mod(r, mod)) - 1) / mod).word_at(0); - R_mod = BigInt(BigInt::Power2, MP_WORD_BITS * mod_words); - R_mod %= modulus; + R_mod = r % modulus; - R2 = BigInt(BigInt::Power2, 2 * MP_WORD_BITS * mod_words); - R2 %= modulus; + R2 = (R_mod * R_mod) % modulus; } } diff --git a/src/math/numbertheory/reducer.cpp b/src/math/numbertheory/reducer.cpp index 257ece56e..466996e99 100644 --- a/src/math/numbertheory/reducer.cpp +++ b/src/math/numbertheory/reducer.cpp @@ -1,6 +1,6 @@ /* * Modular Reducer -* (C) 1999-2010 Jack Lloyd +* (C) 1999-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -22,10 +22,8 @@ Modular_Reducer::Modular_Reducer(const BigInt& mod) mod_words = modulus.sig_words(); modulus_2 = Botan::square(modulus); - mod2_words = modulus_2.sig_words(); mu = BigInt(BigInt::Power2, 2 * MP_WORD_BITS * mod_words) / modulus; - mu_words = mu.sig_words(); } /* @@ -36,45 +34,49 @@ BigInt Modular_Reducer::reduce(const BigInt& x) const if(mod_words == 0) throw Invalid_State("Modular_Reducer: Never initalized"); - BigInt t1 = x; - t1.set_sign(BigInt::Positive); - - if(t1 < modulus) + if(x.cmp(modulus, false) < 0) { - if(x.is_negative() && t1.is_nonzero()) - return modulus - t1; + if(x.is_negative()) + return x + modulus; // make positive return x; } + else if(x.cmp(modulus_2, false) < 0) + { + BigInt t1 = x; + t1.set_sign(BigInt::Positive); + t1 >>= (MP_WORD_BITS * (mod_words - 1)); + t1 *= mu; - if(t1 >= modulus_2) - return (x % modulus); + t1 >>= (MP_WORD_BITS * (mod_words + 1)); + t1 *= modulus; - t1 >>= (MP_WORD_BITS * (mod_words - 1)); - t1 *= mu; - t1 >>= (MP_WORD_BITS * (mod_words + 1)); + t1.mask_bits(MP_WORD_BITS * (mod_words + 1)); - t1 *= modulus; - t1.mask_bits(MP_WORD_BITS * (mod_words+1)); + BigInt t2 = x; + t2.set_sign(BigInt::Positive); + t2.mask_bits(MP_WORD_BITS * (mod_words + 1)); - BigInt t2 = x; - t2.set_sign(BigInt::Positive); - t2.mask_bits(MP_WORD_BITS * (mod_words+1)); + t2 -= t1; - t1 = t2 - t1; + if(t2.is_negative()) + { + BigInt b_to_k1(BigInt::Power2, MP_WORD_BITS * (mod_words + 1)); + t2 += b_to_k1; + } - if(t1.is_negative()) + while(t2 >= modulus) + t2 -= modulus; + + if(x.is_positive()) + return t2; + else + return (modulus - t2); + } + else { - BigInt b_to_k1(BigInt::Power2, MP_WORD_BITS * (mod_words+1)); - t1 += b_to_k1; + // too big, fall back to normal division + return (x % modulus); } - - while(t1 >= modulus) - t1 -= modulus; - - if(x.is_negative() && t1.is_nonzero()) - t1 = modulus - t1; - - return t1; } } diff --git a/src/math/numbertheory/reducer.h b/src/math/numbertheory/reducer.h index 05c12a440..76712074c 100644 --- a/src/math/numbertheory/reducer.h +++ b/src/math/numbertheory/reducer.h @@ -13,7 +13,7 @@ namespace Botan { /** -* Modular Reducer +* Modular Reducer (using Barrett's technique) */ class BOTAN_DLL Modular_Reducer { @@ -53,7 +53,7 @@ class BOTAN_DLL Modular_Reducer Modular_Reducer(const BigInt& mod); private: BigInt modulus, modulus_2, mu; - size_t mod_words, mod2_words, mu_words; + size_t mod_words; }; } diff --git a/src/passhash/bcrypt/bcrypt.cpp b/src/passhash/bcrypt/bcrypt.cpp index 3507db879..b0d654717 100644 --- a/src/passhash/bcrypt/bcrypt.cpp +++ b/src/passhash/bcrypt/bcrypt.cpp @@ -11,11 +11,6 @@ #include <botan/blowfish.h> #include <botan/base64.h> -#include <botan/pipe.h> -#include <botan/b64_filt.h> -#include <iostream> -#include <stdio.h> - namespace Botan { namespace { @@ -89,10 +84,7 @@ MemoryVector<byte> bcrypt_base64_decode(std::string input) for(size_t i = 0; i != input.size(); ++i) input[i] = OPENBSD_BASE64_SUB[static_cast<byte>(input[i])]; - //return base64_decode(input); - Pipe pipe(new Base64_Decoder); - pipe.process_msg(input); - return pipe.read_all(); + return base64_decode(input); } std::string make_bcrypt(const std::string& pass, diff --git a/src/passhash/passhash9/passhash9.cpp b/src/passhash/passhash9/passhash9.cpp index 367583a0a..43bfdd36e 100644 --- a/src/passhash/passhash9/passhash9.cpp +++ b/src/passhash/passhash9/passhash9.cpp @@ -23,8 +23,6 @@ const size_t ALGID_BYTES = 1; const size_t SALT_BYTES = 12; // 96 bits of salt const size_t PASSHASH9_PBKDF_OUTPUT_LEN = 24; // 192 bits output -const byte PASSHASH9_DEFAULT_ALGO = 0; // HMAC(SHA-1) - const size_t WORK_FACTOR_SCALE = 10000; MessageAuthenticationCode* get_pbkdf_prf(byte alg_id) @@ -49,15 +47,8 @@ MessageAuthenticationCode* get_pbkdf_prf(byte alg_id) std::string generate_passhash9(const std::string& pass, RandomNumberGenerator& rng, - u16bit work_factor) - { - return generate_passhash9(pass, PASSHASH9_DEFAULT_ALGO, rng, work_factor); - } - -std::string generate_passhash9(const std::string& pass, - byte alg_id, - RandomNumberGenerator& rng, - u16bit work_factor) + u16bit work_factor, + byte alg_id) { MessageAuthenticationCode* prf = get_pbkdf_prf(alg_id); diff --git a/src/passhash/passhash9/passhash9.h b/src/passhash/passhash9/passhash9.h index 92cc391dc..3c0a4be51 100644 --- a/src/passhash/passhash9/passhash9.h +++ b/src/passhash/passhash9/passhash9.h @@ -17,26 +17,16 @@ namespace Botan { * @param password the password * @param rng a random number generator * @param work_factor how much work to do to slow down guessing attacks -*/ -std::string BOTAN_DLL generate_passhash9(const std::string& password, - RandomNumberGenerator& rng, - u16bit work_factor = 10); - -/** -* Create a password hash using PBKDF2 -* @param password the password * @param alg_id specifies which PRF to use with PBKDF2 * 0 is HMAC(SHA-1) * 1 is HMAC(SHA-256) * 2 is CMAC(Blowfish) * all other values are currently undefined -* @param rng a random number generator -* @param work_factor how much work to do to slow down guessing attacks */ std::string BOTAN_DLL generate_passhash9(const std::string& password, - byte alg_id, RandomNumberGenerator& rng, - u16bit work_factor = 10); + u16bit work_factor = 10, + byte alg_id = 0); /** * Check a previously created password hash diff --git a/src/pk_pad/eme1/eme1.cpp b/src/pk_pad/eme1/eme1.cpp index b49fb9af0..1cc0c332d 100644 --- a/src/pk_pad/eme1/eme1.cpp +++ b/src/pk_pad/eme1/eme1.cpp @@ -65,38 +65,47 @@ SecureVector<byte> EME1::unpad(const byte in[], size_t in_length, if(in_length > key_length) in_length = 0; - SecureVector<byte> tmp(key_length); - tmp.copy(key_length - in_length, in, in_length); + SecureVector<byte> input(key_length); + input.copy(key_length - in_length, in, in_length); - mgf->mask(&tmp[Phash.size()], tmp.size() - Phash.size(), - &tmp[0], Phash.size()); - mgf->mask(&tmp[0], Phash.size(), - &tmp[Phash.size()], tmp.size() - Phash.size()); + mgf->mask(&input[Phash.size()], input.size() - Phash.size(), + &input[0], Phash.size()); + mgf->mask(&input[0], Phash.size(), + &input[Phash.size()], input.size() - Phash.size()); - const bool phash_ok = same_mem(&tmp[Phash.size()], &Phash[0], Phash.size()); + bool waiting_for_delim = true; + bool bad_input = false; + size_t delim_idx = 2 * Phash.size(); - bool delim_ok = true; - size_t delim_idx = 0; - - // Is this vulnerable to timing attacks? - for(size_t i = Phash.size() + Phash.size(); i != tmp.size(); ++i) + /* + * GCC 4.5 on x86-64 compiles this in a way that is still vunerable + * to timing analysis. Other compilers, or GCC on other platforms, + * may or may not. + */ + for(size_t i = delim_idx; i != input.size(); ++i) { - if(tmp[i] && !delim_idx) - { - if(tmp[i] == 0x01) - delim_idx = i; - else - delim_ok = false; - } - } + const bool zero_p = !input[i]; + const bool one_p = input[i] == 0x01; - if(delim_idx && delim_ok && phash_ok) - { - return SecureVector<byte>(&tmp[delim_idx + 1], - tmp.size() - delim_idx - 1); + const bool add_1 = waiting_for_delim && zero_p; + + bad_input |= waiting_for_delim && !(zero_p || one_p); + + delim_idx += add_1; + + waiting_for_delim &= zero_p; } - throw Decoding_Error("Invalid EME1 encoding"); + // If we never saw any non-zero byte, then it's not valid input + bad_input |= waiting_for_delim; + + bad_input |= !same_mem(&input[Phash.size()], &Phash[0], Phash.size()); + + if(bad_input) + throw Decoding_Error("Invalid EME1 encoding"); + + return SecureVector<byte>(input + delim_idx + 1, + input.size() - delim_idx - 1); } /* diff --git a/src/pubkey/ec_dompar/ec_dompar.cpp b/src/pubkey/ec_group/ec_group.cpp index deb512518..fe4fae885 100644 --- a/src/pubkey/ec_dompar/ec_dompar.cpp +++ b/src/pubkey/ec_group/ec_group.cpp @@ -7,7 +7,7 @@ * Distributed under the terms of the Botan license */ -#include <botan/ec_dompar.h> +#include <botan/ec_group.h> #include <botan/ber_dec.h> #include <botan/der_enc.h> #include <botan/libstate.h> @@ -16,7 +16,7 @@ namespace Botan { -EC_Domain_Params::EC_Domain_Params(const OID& domain_oid) +EC_Group::EC_Group(const OID& domain_oid) { std::string pem = global_state().get("ec", OIDS::lookup(domain_oid)); @@ -24,31 +24,31 @@ EC_Domain_Params::EC_Domain_Params(const OID& domain_oid) if(pem == "") throw Lookup_Error("No ECC domain data for " + domain_oid.as_string()); - *this = EC_Domain_Params(pem); + *this = EC_Group(pem); oid = domain_oid.as_string(); } -EC_Domain_Params::EC_Domain_Params(const std::string& pem) +EC_Group::EC_Group(const std::string& str) { - if(pem == "") + if(str == "") return; // no initialization / uninitialized try { - DataSource_Memory input(pem); + DataSource_Memory input(str); SecureVector<byte> ber = PEM_Code::decode_check_label(input, "EC PARAMETERS"); - *this = EC_Domain_Params(ber); + *this = EC_Group(ber); } catch(Decoding_Error) // hmm, not PEM? { - *this = EC_Domain_Params(OID(pem)); + *this = EC_Group(OIDS::lookup(str)); } } -EC_Domain_Params::EC_Domain_Params(const MemoryRegion<byte>& ber_data) +EC_Group::EC_Group(const MemoryRegion<byte>& ber_data) { BER_Decoder ber(ber_data); BER_Object obj = ber.get_next_object(); @@ -59,7 +59,7 @@ EC_Domain_Params::EC_Domain_Params(const MemoryRegion<byte>& ber_data) { OID dom_par_oid; BER_Decoder(ber_data).decode(dom_par_oid); - *this = EC_Domain_Params(dom_par_oid); + *this = EC_Group(dom_par_oid); } else if(obj.type_tag == SEQUENCE) { @@ -92,7 +92,7 @@ EC_Domain_Params::EC_Domain_Params(const MemoryRegion<byte>& ber_data) } SecureVector<byte> -EC_Domain_Params::DER_encode(EC_Domain_Params_Encoding form) const +EC_Group::DER_encode(EC_Group_Encoding form) const { if(form == EC_DOMPAR_ENC_EXPLICIT) { @@ -125,10 +125,10 @@ EC_Domain_Params::DER_encode(EC_Domain_Params_Encoding form) const else if(form == EC_DOMPAR_ENC_IMPLICITCA) return DER_Encoder().encode_null().get_contents(); else - throw Internal_Error("EC_Domain_Params::DER_encode: Unknown encoding"); + throw Internal_Error("EC_Group::DER_encode: Unknown encoding"); } -std::string EC_Domain_Params::PEM_encode() const +std::string EC_Group::PEM_encode() const { SecureVector<byte> der = DER_encode(EC_DOMPAR_ENC_EXPLICIT); return PEM_Code::encode(der, "EC PARAMETERS"); diff --git a/src/pubkey/ec_dompar/ec_dompar.h b/src/pubkey/ec_group/ec_group.h index 2508d5a2d..b7b09985e 100644 --- a/src/pubkey/ec_dompar/ec_dompar.h +++ b/src/pubkey/ec_group/ec_group.h @@ -19,7 +19,7 @@ namespace Botan { /** * This class represents elliptic curce domain parameters */ -enum EC_Domain_Params_Encoding { +enum EC_Group_Encoding { EC_DOMPAR_ENC_EXPLICIT = 0, EC_DOMPAR_ENC_IMPLICITCA = 1, EC_DOMPAR_ENC_OID = 2 @@ -28,7 +28,7 @@ enum EC_Domain_Params_Encoding { /** * Class representing an elliptic curve */ -class BOTAN_DLL EC_Domain_Params +class BOTAN_DLL EC_Group { public: @@ -39,7 +39,7 @@ class BOTAN_DLL EC_Domain_Params * @param order the order of the base point * @param cofactor the cofactor */ - EC_Domain_Params(const CurveGFp& curve, + EC_Group(const CurveGFp& curve, const PointGFp& base_point, const BigInt& order, const BigInt& cofactor) : @@ -54,27 +54,27 @@ class BOTAN_DLL EC_Domain_Params * Decode a BER encoded ECC domain parameter set * @param ber_encoding the bytes of the BER encoding */ - EC_Domain_Params(const MemoryRegion<byte>& ber_encoding); + EC_Group(const MemoryRegion<byte>& ber_encoding); /** * Create an EC domain by OID (or throw if unknown) * @param oid the OID of the EC domain to create */ - EC_Domain_Params(const OID& oid); + EC_Group(const OID& oid); /** * Create an EC domain from PEM encoding (as from PEM_encode), * or from an OID name (eg "secp16r1", or "1.3.132.0.8") * @param pem_or_oid PEM-encoded data, or an OID */ - EC_Domain_Params(const std::string& pem_or_oid = ""); + EC_Group(const std::string& pem_or_oid = ""); /** * Create the DER encoding of this domain * @param form of encoding to use * @returns bytes encododed as DER */ - SecureVector<byte> DER_encode(EC_Domain_Params_Encoding form) const; + SecureVector<byte> DER_encode(EC_Group_Encoding form) const; /** * Return the PEM encoding (always in explicit form) @@ -114,7 +114,7 @@ class BOTAN_DLL EC_Domain_Params */ std::string get_oid() const { return oid; } - bool operator==(const EC_Domain_Params& other) const + bool operator==(const EC_Group& other) const { return ((get_curve() == other.get_curve()) && (get_base_point() == other.get_base_point()) && @@ -129,12 +129,15 @@ class BOTAN_DLL EC_Domain_Params std::string oid; }; -inline bool operator!=(const EC_Domain_Params& lhs, - const EC_Domain_Params& rhs) +inline bool operator!=(const EC_Group& lhs, + const EC_Group& rhs) { return !(lhs == rhs); } +// For compatability with 1.8 +typedef EC_Group EC_Domain_Params; + } #endif diff --git a/src/pubkey/ec_dompar/info.txt b/src/pubkey/ec_group/info.txt index ae6c328e2..9a686feeb 100644 --- a/src/pubkey/ec_dompar/info.txt +++ b/src/pubkey/ec_group/info.txt @@ -1,9 +1,10 @@ -define ECC_DOMAIN_PARAMATERS +define ECC_GROUP <requires> asn1 -numbertheory -pem +ec_gfp libstate +numbertheory oid_lookup +pem </requires> diff --git a/src/pubkey/ecc_key/ecc_key.cpp b/src/pubkey/ecc_key/ecc_key.cpp index bd04e3197..991446f07 100644 --- a/src/pubkey/ecc_key/ecc_key.cpp +++ b/src/pubkey/ecc_key/ecc_key.cpp @@ -18,7 +18,7 @@ namespace Botan { -EC_PublicKey::EC_PublicKey(const EC_Domain_Params& dom_par, +EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, const PointGFp& pub_point) : domain_params(dom_par), public_key(pub_point), domain_encoding(EC_DOMPAR_ENC_EXPLICIT) @@ -30,7 +30,7 @@ EC_PublicKey::EC_PublicKey(const EC_Domain_Params& dom_par, EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, const MemoryRegion<byte>& key_bits) { - domain_params = EC_Domain_Params(alg_id.parameters); + domain_params = EC_Group(alg_id.parameters); domain_encoding = EC_DOMPAR_ENC_EXPLICIT; public_key = OS2ECP(key_bits, domain().get_curve()); @@ -52,7 +52,7 @@ MemoryVector<byte> EC_PublicKey::x509_subject_public_key() const return EC2OSP(public_point(), PointGFp::COMPRESSED); } -void EC_PublicKey::set_parameter_encoding(EC_Domain_Params_Encoding form) +void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) { if(form != EC_DOMPAR_ENC_EXPLICIT && form != EC_DOMPAR_ENC_IMPLICITCA && @@ -76,32 +76,24 @@ const BigInt& EC_PrivateKey::private_value() const } /** -* EC_PrivateKey generator -*/ -EC_PrivateKey::EC_PrivateKey(const EC_Domain_Params& dom_par, - const BigInt& priv_key) - { - domain_params = dom_par; - domain_encoding = EC_DOMPAR_ENC_EXPLICIT; - - public_key = domain().get_base_point() * priv_key; - private_key = priv_key; - } - -/** -* EC_PrivateKey generator +* EC_PrivateKey constructor */ EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, - const EC_Domain_Params& dom_par) + const EC_Group& ec_group, + const BigInt& x) { - domain_params = dom_par; + domain_params = ec_group; domain_encoding = EC_DOMPAR_ENC_EXPLICIT; - private_key = BigInt::random_integer(rng, 1, domain().get_order()); + if(x == 0) + private_key = BigInt::random_integer(rng, 1, domain().get_order()); + else + private_key = x; + public_key = domain().get_base_point() * private_key; BOTAN_ASSERT(public_key.on_the_curve(), - "generated ECC private key was not on the curve"); + "ECC private key was not on the curve"); } MemoryVector<byte> EC_PrivateKey::pkcs8_private_key() const @@ -118,7 +110,7 @@ MemoryVector<byte> EC_PrivateKey::pkcs8_private_key() const EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, const MemoryRegion<byte>& key_bits) { - domain_params = EC_Domain_Params(alg_id.parameters); + domain_params = EC_Group(alg_id.parameters); domain_encoding = EC_DOMPAR_ENC_EXPLICIT; BER_Decoder(key_bits) diff --git a/src/pubkey/ecc_key/ecc_key.h b/src/pubkey/ecc_key/ecc_key.h index a20516ec6..cccc8d53c 100644 --- a/src/pubkey/ecc_key/ecc_key.h +++ b/src/pubkey/ecc_key/ecc_key.h @@ -10,7 +10,7 @@ #ifndef BOTAN_ECC_PUBLIC_KEY_BASE_H__ #define BOTAN_ECC_PUBLIC_KEY_BASE_H__ -#include <botan/ec_dompar.h> +#include <botan/ec_group.h> #include <botan/pk_keys.h> #include <botan/x509_key.h> #include <botan/pkcs8.h> @@ -18,7 +18,7 @@ namespace Botan { /** -* This class represents abstract EC Public Keys. When encoding a key +* This class represents abstract ECC public keys. When encoding a key * via an encoder that can be accessed via the corresponding member * functions, the key will decide upon its internally stored encoding * information whether to encode itself with or without domain @@ -30,7 +30,7 @@ namespace Botan { class BOTAN_DLL EC_PublicKey : public virtual Public_Key { public: - EC_PublicKey(const EC_Domain_Params& dom_par, + EC_PublicKey(const EC_Group& dom_par, const PointGFp& pub_point); EC_PublicKey(const AlgorithmIdentifier& alg_id, @@ -57,13 +57,13 @@ class BOTAN_DLL EC_PublicKey : public virtual Public_Key * domain parameters of this point are not set * @result the domain parameters of this key */ - const EC_Domain_Params& domain() const { return domain_params; } + const EC_Group& domain() const { return domain_params; } /** * Set the domain parameter encoding to be used when encoding this key. * @param enc the encoding to use */ - void set_parameter_encoding(EC_Domain_Params_Encoding enc); + void set_parameter_encoding(EC_Group_Encoding enc); /** * Return the DER encoding of this keys domain in whatever format @@ -76,28 +76,26 @@ class BOTAN_DLL EC_PublicKey : public virtual Public_Key * Get the domain parameter encoding to be used when encoding this key. * @result the encoding to use */ - EC_Domain_Params_Encoding domain_format() const + EC_Group_Encoding domain_format() const { return domain_encoding; } protected: EC_PublicKey() : domain_encoding(EC_DOMPAR_ENC_EXPLICIT) {} - EC_Domain_Params domain_params; + EC_Group domain_params; PointGFp public_key; - EC_Domain_Params_Encoding domain_encoding; + EC_Group_Encoding domain_encoding; }; /** -* This abstract class represents general EC Private Keys +* This abstract class represents ECC private keys */ class BOTAN_DLL EC_PrivateKey : public virtual EC_PublicKey, public virtual Private_Key { public: - EC_PrivateKey(const EC_Domain_Params& domain, - const BigInt& private_key); - - EC_PrivateKey(RandomNumberGenerator& rng, - const EC_Domain_Params& domain); + EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& private_key); EC_PrivateKey(const AlgorithmIdentifier& alg_id, const MemoryRegion<byte>& key_bits); diff --git a/src/pubkey/ecc_key/info.txt b/src/pubkey/ecc_key/info.txt index e08a4231d..ceb98a79e 100644 --- a/src/pubkey/ecc_key/info.txt +++ b/src/pubkey/ecc_key/info.txt @@ -4,6 +4,7 @@ define ECC_PUBLIC_KEY_CRYPTO alloc asn1 bigint -ec_dompar +ec_gfp +ec_group numbertheory </requires> diff --git a/src/pubkey/ecdh/ecdh.h b/src/pubkey/ecdh/ecdh.h index 301bb1591..2edbfe86d 100644 --- a/src/pubkey/ecdh/ecdh.h +++ b/src/pubkey/ecdh/ecdh.h @@ -32,7 +32,7 @@ class BOTAN_DLL ECDH_PublicKey : public virtual EC_PublicKey * @param dom_par the domain parameters associated with this key * @param public_point the public point defining this key */ - ECDH_PublicKey(const EC_Domain_Params& dom_par, + ECDH_PublicKey(const EC_Group& dom_par, const PointGFp& public_point) : EC_PublicKey(dom_par, public_point) {} @@ -77,10 +77,12 @@ class BOTAN_DLL ECDH_PrivateKey : public ECDH_PublicKey, * Generate a new private key * @param rng a random number generator * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated */ ECDH_PrivateKey(RandomNumberGenerator& rng, - const EC_Domain_Params& domain) : - EC_PrivateKey(rng, domain) {} + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} MemoryVector<byte> public_value() const { return ECDH_PublicKey::public_value(); } diff --git a/src/pubkey/ecdh/info.txt b/src/pubkey/ecdh/info.txt index 12826c81b..7e7d50fef 100644 --- a/src/pubkey/ecdh/info.txt +++ b/src/pubkey/ecdh/info.txt @@ -3,7 +3,7 @@ define ECDH <requires> alloc asn1 -ec_dompar +ec_group ecc_key libstate numbertheory diff --git a/src/pubkey/ecdsa/ecdsa.cpp b/src/pubkey/ecdsa/ecdsa.cpp index 9a3510c33..5c45c5ed3 100644 --- a/src/pubkey/ecdsa/ecdsa.cpp +++ b/src/pubkey/ecdsa/ecdsa.cpp @@ -80,12 +80,13 @@ bool ECDSA_Verification_Operation::verify(const byte msg[], size_t msg_len, BigInt r(sig, sig_len / 2); BigInt s(sig + sig_len / 2, sig_len / 2); - if(r < 0 || r >= order || s < 0 || s >= order) + if(r <= 0 || r >= order || s <= 0 || s >= order) return false; BigInt w = inverse_mod(s, order); - PointGFp R = w * (e * base_point + r * public_point); + PointGFp R = w * multi_exponentiate(base_point, e, + public_point, r); if(R.is_zero()) return false; diff --git a/src/pubkey/ecdsa/ecdsa.h b/src/pubkey/ecdsa/ecdsa.h index 6d62a168d..f0834abd8 100644 --- a/src/pubkey/ecdsa/ecdsa.h +++ b/src/pubkey/ecdsa/ecdsa.h @@ -28,7 +28,7 @@ class BOTAN_DLL ECDSA_PublicKey : public virtual EC_PublicKey * @param dom_par the domain parameters associated with this key * @param public_point the public point defining this key */ - ECDSA_PublicKey(const EC_Domain_Params& dom_par, + ECDSA_PublicKey(const EC_Group& dom_par, const PointGFp& public_point) : EC_PublicKey(dom_par, public_point) {} @@ -66,6 +66,11 @@ class BOTAN_DLL ECDSA_PrivateKey : public ECDSA_PublicKey, { public: + /** + * Load a private key + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS #8 structure + */ ECDSA_PrivateKey(const AlgorithmIdentifier& alg_id, const MemoryRegion<byte>& key_bits) : EC_PrivateKey(alg_id, key_bits) {} @@ -74,19 +79,12 @@ class BOTAN_DLL ECDSA_PrivateKey : public ECDSA_PublicKey, * Generate a new private key * @param rng a random number generator * @param domain parameters to used for this key + * @param x the private key (if zero, generate a ney random key) */ ECDSA_PrivateKey(RandomNumberGenerator& rng, - const EC_Domain_Params& domain) : - EC_PrivateKey(rng, domain) {} - - /** - * Load a private key - * @param domain parameters - * @param x the private key - */ - ECDSA_PrivateKey(const EC_Domain_Params& domain, - const BigInt& x) : - EC_PrivateKey(domain, x) {} + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} bool check_key(RandomNumberGenerator& rng, bool) const; }; diff --git a/src/pubkey/ecdsa/info.txt b/src/pubkey/ecdsa/info.txt index ca2694ad1..7a2113a30 100644 --- a/src/pubkey/ecdsa/info.txt +++ b/src/pubkey/ecdsa/info.txt @@ -2,7 +2,7 @@ define ECDSA <requires> asn1 -ec_dompar +ec_group ecc_key numbertheory rng diff --git a/src/pubkey/gost_3410/gost_3410.cpp b/src/pubkey/gost_3410/gost_3410.cpp index fa72d0673..f97f83aa0 100644 --- a/src/pubkey/gost_3410/gost_3410.cpp +++ b/src/pubkey/gost_3410/gost_3410.cpp @@ -17,8 +17,8 @@ namespace Botan { MemoryVector<byte> GOST_3410_PublicKey::x509_subject_public_key() const { // Trust CryptoPro to come up with something obnoxious - const BigInt& x = public_point().get_affine_x(); - const BigInt& y = public_point().get_affine_y(); + const BigInt x = public_point().get_affine_x(); + const BigInt y = public_point().get_affine_y(); size_t part_size = std::max(x.bytes(), y.bytes()); @@ -56,7 +56,7 @@ GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, // Also includes hash and cipher OIDs... brilliant design guys BER_Decoder(alg_id.parameters).start_cons(SEQUENCE).decode(ecc_param_id); - domain_params = EC_Domain_Params(ecc_param_id); + domain_params = EC_Group(ecc_param_id); SecureVector<byte> bits; BER_Decoder(key_bits).decode(bits, OCTET_STRING); @@ -153,7 +153,7 @@ bool GOST_3410_Verification_Operation::verify(const byte msg[], size_t msg_len, BigInt s(sig, sig_len / 2); BigInt r(sig + sig_len / 2, sig_len / 2); - if(r < 0 || r >= order || s < 0 || s >= order) + if(r <= 0 || r >= order || s <= 0 || s >= order) return false; e %= order; @@ -165,7 +165,11 @@ bool GOST_3410_Verification_Operation::verify(const byte msg[], size_t msg_len, BigInt z1 = (s*v) % order; BigInt z2 = (-r*v) % order; - PointGFp R = (z1 * base_point + z2 * public_point); + PointGFp R = multi_exponentiate(base_point, z1, + public_point, z2); + + if(R.is_zero()) + return false; return (R.get_affine_x() == r); } diff --git a/src/pubkey/gost_3410/gost_3410.h b/src/pubkey/gost_3410/gost_3410.h index 4fb7b42c3..7b638d7b5 100644 --- a/src/pubkey/gost_3410/gost_3410.h +++ b/src/pubkey/gost_3410/gost_3410.h @@ -27,7 +27,7 @@ class BOTAN_DLL GOST_3410_PublicKey : public virtual EC_PublicKey * @param dom_par the domain parameters associated with this key * @param public_point the public point defining this key */ - GOST_3410_PublicKey(const EC_Domain_Params& dom_par, + GOST_3410_PublicKey(const EC_Group& dom_par, const PointGFp& public_point) : EC_PublicKey(dom_par, public_point) {} @@ -80,18 +80,12 @@ class BOTAN_DLL GOST_3410_PrivateKey : public GOST_3410_PublicKey, * Generate a new private key * @param rng a random number generator * @param domain parameters to used for this key + * @param x the private key; if zero, a new random key is generated */ GOST_3410_PrivateKey(RandomNumberGenerator& rng, - const EC_Domain_Params& domain) : - EC_PrivateKey(rng, domain) {} - - /** - * Load a private key - * @param domain parameters - * @param x the private key - */ - GOST_3410_PrivateKey(const EC_Domain_Params& domain, const BigInt& x) : - EC_PrivateKey(domain, x) {} + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x) {} AlgorithmIdentifier pkcs8_algorithm_identifier() const { return EC_PublicKey::algorithm_identifier(); } diff --git a/src/pubkey/gost_3410/info.txt b/src/pubkey/gost_3410/info.txt index 05df445ec..9fbc3099f 100644 --- a/src/pubkey/gost_3410/info.txt +++ b/src/pubkey/gost_3410/info.txt @@ -5,7 +5,7 @@ load_on auto <requires> alloc asn1 -ec_dompar +ec_group ecc_key libstate numbertheory diff --git a/src/utils/simd_32/info.txt b/src/simd/info.txt index 362e90235..d0601b141 100644 --- a/src/utils/simd_32/info.txt +++ b/src/simd/info.txt @@ -2,7 +2,8 @@ define SIMD_32 <header:internal> simd_32.h -simd_sse.h -simd_scalar.h -simd_altivec.h </header:internal> + +<requires> +simd_sse2|simd_altivec|simd_scalar +</requires> diff --git a/src/simd/simd_32.h b/src/simd/simd_32.h new file mode 100644 index 000000000..4ef0cea85 --- /dev/null +++ b/src/simd/simd_32.h @@ -0,0 +1,30 @@ +/* +* Lightweight wrappers for SIMD operations +* (C) 2009,2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SIMD_32_H__ +#define BOTAN_SIMD_32_H__ + +#include <botan/types.h> + +#if defined(BOTAN_HAS_SIMD_SSE2) + #include <botan/internal/simd_sse2.h> + namespace Botan { typedef SIMD_SSE2 SIMD_32; } + +#elif defined(BOTAN_HAS_SIMD_ALTIVEC) + #include <botan/internal/simd_altivec.h> + namespace Botan { typedef SIMD_Altivec SIMD_32; } + +#elif defined(BOTAN_HAS_SIMD_SCALAR) + #include <botan/internal/simd_scalar.h> + namespace Botan { typedef SIMD_Scalar SIMD_32; } + +#else + #error "No SIMD module defined" + +#endif + +#endif diff --git a/src/simd/simd_altivec/info.txt b/src/simd/simd_altivec/info.txt new file mode 100644 index 000000000..aa2f01c2d --- /dev/null +++ b/src/simd/simd_altivec/info.txt @@ -0,0 +1,9 @@ +define SIMD_ALTIVEC + +need_isa altivec + +load_on dep + +<header:internal> +simd_altivec.h +</header:internal> diff --git a/src/utils/simd_32/simd_altivec.h b/src/simd/simd_altivec/simd_altivec.h index 4c412ddec..4c412ddec 100644 --- a/src/utils/simd_32/simd_altivec.h +++ b/src/simd/simd_altivec/simd_altivec.h diff --git a/src/simd/simd_scalar/info.txt b/src/simd/simd_scalar/info.txt new file mode 100644 index 000000000..6817eab80 --- /dev/null +++ b/src/simd/simd_scalar/info.txt @@ -0,0 +1,7 @@ +define SIMD_SCALAR + +load_on dep + +<header:internal> +simd_scalar.h +</header:internal> diff --git a/src/utils/simd_32/simd_scalar.h b/src/simd/simd_scalar/simd_scalar.h index 2c68622af..2c68622af 100644 --- a/src/utils/simd_32/simd_scalar.h +++ b/src/simd/simd_scalar/simd_scalar.h diff --git a/src/simd/simd_sse2/info.txt b/src/simd/simd_sse2/info.txt new file mode 100644 index 000000000..e56792491 --- /dev/null +++ b/src/simd/simd_sse2/info.txt @@ -0,0 +1,9 @@ +define SIMD_SSE2 + +need_isa sse2 + +load_on dep + +<header:internal> +simd_sse2.h +</header:internal> diff --git a/src/utils/simd_32/simd_sse.h b/src/simd/simd_sse2/simd_sse2.h index 1cb52105c..61fce99a9 100644 --- a/src/utils/simd_32/simd_sse.h +++ b/src/simd/simd_sse2/simd_sse2.h @@ -22,7 +22,7 @@ class SIMD_SSE2 SIMD_SSE2(const u32bit B[4]) { - reg = _mm_loadu_si128((const __m128i*)B); + reg = _mm_loadu_si128(reinterpret_cast<const __m128i*>(B)); } SIMD_SSE2(u32bit B0, u32bit B1, u32bit B2, u32bit B3) @@ -37,7 +37,7 @@ class SIMD_SSE2 static SIMD_SSE2 load_le(const void* in) { - return _mm_loadu_si128((const __m128i*)in); + return _mm_loadu_si128(reinterpret_cast<const __m128i*>(in)); } static SIMD_SSE2 load_be(const void* in) @@ -47,7 +47,7 @@ class SIMD_SSE2 void store_le(byte out[]) const { - _mm_storeu_si128((__m128i*)out, reg); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), reg); } void store_be(byte out[]) const diff --git a/src/ssl/hello.cpp b/src/ssl/hello.cpp index bec316bb1..2c5a9d2ea 100644 --- a/src/ssl/hello.cpp +++ b/src/ssl/hello.cpp @@ -177,8 +177,9 @@ void Client_Hello::deserialize(const MemoryRegion<byte>& buf) std::vector<byte> name = reader.get_range_vector<byte>(2, 1, 65535); - requested_hostname.assign((const char*)&name[0], - name.size()); + requested_hostname.assign( + reinterpret_cast<const char*>(&name[0]), + name.size()); name_bytes -= (2 + name.size()); } diff --git a/src/ssl/info.txt b/src/ssl/info.txt index 1f11772cd..910ed7e97 100644 --- a/src/ssl/info.txt +++ b/src/ssl/info.txt @@ -1,7 +1,11 @@ define SSL_TLS +<comment> +The SSL/TLS code is complex, new, and not yet reviewed, there may be +serious bugs or security issues. +</comment> + <header:public> -socket.h tls_client.h tls_connection.h tls_exceptn.h @@ -51,11 +55,11 @@ emsa3 filters hmac md5 +prf_ssl3 +prf_tls rng rsa sha1 ssl3mac -ssl_prf -tls_prf x509cert </requires> diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp index 042aae0c9..4e5b69780 100644 --- a/src/ssl/rec_read.cpp +++ b/src/ssl/rec_read.cpp @@ -223,7 +223,7 @@ size_t Record_Reader::get_record(byte& msg_type, throw Decoding_Error("Record_Reader: Record truncated"); const size_t mac_offset = plaintext.size() - (mac_size + pad_size); - SecureVector<byte> recieved_mac(&plaintext[mac_offset], + SecureVector<byte> received_mac(&plaintext[mac_offset], mac_size); const u16bit plain_length = plaintext.size() - (mac_size + pad_size + iv_size); @@ -242,7 +242,7 @@ size_t Record_Reader::get_record(byte& msg_type, SecureVector<byte> computed_mac = mac->final(); - if(recieved_mac != computed_mac) + if(received_mac != computed_mac) throw TLS_Exception(BAD_RECORD_MAC, "Record_Reader: MAC failure"); msg_type = header[0]; diff --git a/src/ssl/socket.h b/src/ssl/socket.h deleted file mode 100644 index 6d88bd48a..000000000 --- a/src/ssl/socket.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -* Socket Interface -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SOCKET_H__ -#define BOTAN_TLS_SOCKET_H__ - -#include <botan/types.h> -#include <string> - -namespace Botan { - -/** -* Socket Base Class -*/ -class BOTAN_DLL Socket - { - public: - virtual size_t read(byte[], size_t) = 0; - virtual void write(const byte[], size_t) = 0; - - virtual std::string peer_id() const = 0; - - virtual void close() = 0; - - virtual ~Socket() {} - }; - -/** -* Server Socket Base Class -*/ -class BOTAN_DLL Server_Socket - { - public: - virtual Socket* accept() = 0; - virtual void close() = 0; - - virtual ~Server_Socket() {} - }; - -} - -#endif diff --git a/src/ssl/tls_alerts.h b/src/ssl/tls_alerts.h index f189cf507..241599aa8 100644 --- a/src/ssl/tls_alerts.h +++ b/src/ssl/tls_alerts.h @@ -15,7 +15,7 @@ namespace Botan { /** * SSL/TLS Alert Message */ -class BOTAN_DLL Alert +class Alert { public: /** diff --git a/src/ssl/tls_client.cpp b/src/ssl/tls_client.cpp index 03c8117cc..eeb99e24d 100644 --- a/src/ssl/tls_client.cpp +++ b/src/ssl/tls_client.cpp @@ -294,7 +294,7 @@ void TLS_Client::state_machine() } } else - throw Unexpected_Message("Unknown message type recieved"); + throw Unexpected_Message("Unknown message type received"); } /** @@ -440,7 +440,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, is_rsa = true; else throw TLS_Exception(UNSUPPORTED_CERTIFICATE, - "Unknown key type recieved in server kex"); + "Unknown key type received in server kex"); if((is_dsa && state->suite.sig_type() != TLS_ALGO_SIGNER_DSA) || (is_rsa && state->suite.sig_type() != TLS_ALGO_SIGNER_RSA)) @@ -469,7 +469,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, is_rsa = true; else throw TLS_Exception(HANDSHAKE_FAILURE, - "Unknown key type recieved in server kex"); + "Unknown key type received in server kex"); if((is_dh && state->suite.kex_type() != TLS_ALGO_KEYEXCH_DH) || (is_rsa && state->suite.kex_type() != TLS_ALGO_KEYEXCH_RSA)) @@ -560,7 +560,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, active = true; } else - throw Unexpected_Message("Unknown handshake message recieved"); + throw Unexpected_Message("Unknown handshake message received"); } /** diff --git a/src/ssl/tls_exceptn.h b/src/ssl/tls_exceptn.h index a9efc718a..37b9c0d27 100644 --- a/src/ssl/tls_exceptn.h +++ b/src/ssl/tls_exceptn.h @@ -32,7 +32,7 @@ class BOTAN_DLL TLS_Exception : public Exception /** * Unexpected_Message Exception */ -struct Unexpected_Message : public TLS_Exception +struct BOTAN_DLL Unexpected_Message : public TLS_Exception { Unexpected_Message(const std::string& err) : TLS_Exception(UNEXPECTED_MESSAGE, err) {} diff --git a/src/ssl/tls_handshake_hash.h b/src/ssl/tls_handshake_hash.h index ceaa55584..cea612a71 100644 --- a/src/ssl/tls_handshake_hash.h +++ b/src/ssl/tls_handshake_hash.h @@ -17,7 +17,7 @@ using namespace Botan; /** * TLS Handshake Hash */ -class BOTAN_DLL HandshakeHash +class HandshakeHash { public: void update(const byte in[], size_t length) diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h index c5d4d8cb8..0b3553ac0 100644 --- a/src/ssl/tls_messages.h +++ b/src/ssl/tls_messages.h @@ -21,7 +21,7 @@ namespace Botan { /** * TLS Handshake Message Base Class */ -class BOTAN_DLL HandshakeMessage +class HandshakeMessage { public: void send(Record_Writer&, HandshakeHash&) const; @@ -38,7 +38,7 @@ class BOTAN_DLL HandshakeMessage /** * Client Hello Message */ -class BOTAN_DLL Client_Hello : public HandshakeMessage +class Client_Hello : public HandshakeMessage { public: Handshake_Type type() const { return CLIENT_HELLO; } @@ -80,7 +80,7 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage /** * Client Key Exchange Message */ -class BOTAN_DLL Client_Key_Exchange : public HandshakeMessage +class Client_Key_Exchange : public HandshakeMessage { public: Handshake_Type type() const { return CLIENT_KEX; } @@ -112,7 +112,7 @@ class BOTAN_DLL Client_Key_Exchange : public HandshakeMessage /** * Certificate Message */ -class BOTAN_DLL Certificate : public HandshakeMessage +class Certificate : public HandshakeMessage { public: Handshake_Type type() const { return CERTIFICATE; } @@ -130,7 +130,7 @@ class BOTAN_DLL Certificate : public HandshakeMessage /** * Certificate Request Message */ -class BOTAN_DLL Certificate_Req : public HandshakeMessage +class Certificate_Req : public HandshakeMessage { public: Handshake_Type type() const { return CERTIFICATE_REQUEST; } @@ -157,7 +157,7 @@ class BOTAN_DLL Certificate_Req : public HandshakeMessage /** * Certificate Verify Message */ -class BOTAN_DLL Certificate_Verify : public HandshakeMessage +class Certificate_Verify : public HandshakeMessage { public: Handshake_Type type() const { return CERTIFICATE_VERIFY; } @@ -179,7 +179,7 @@ class BOTAN_DLL Certificate_Verify : public HandshakeMessage /** * Finished Message */ -class BOTAN_DLL Finished : public HandshakeMessage +class Finished : public HandshakeMessage { public: Handshake_Type type() const { return FINISHED; } @@ -205,7 +205,7 @@ class BOTAN_DLL Finished : public HandshakeMessage /** * Hello Request Message */ -class BOTAN_DLL Hello_Request : public HandshakeMessage +class Hello_Request : public HandshakeMessage { public: Handshake_Type type() const { return HELLO_REQUEST; } @@ -220,7 +220,7 @@ class BOTAN_DLL Hello_Request : public HandshakeMessage /** * Server Hello Message */ -class BOTAN_DLL Server_Hello : public HandshakeMessage +class Server_Hello : public HandshakeMessage { public: Handshake_Type type() const { return SERVER_HELLO; } @@ -250,7 +250,7 @@ class BOTAN_DLL Server_Hello : public HandshakeMessage /** * Server Key Exchange Message */ -class BOTAN_DLL Server_Key_Exchange : public HandshakeMessage +class Server_Key_Exchange : public HandshakeMessage { public: Handshake_Type type() const { return SERVER_KEX; } @@ -277,7 +277,7 @@ class BOTAN_DLL Server_Key_Exchange : public HandshakeMessage /** * Server Hello Done Message */ -class BOTAN_DLL Server_Hello_Done : public HandshakeMessage +class Server_Hello_Done : public HandshakeMessage { public: Handshake_Type type() const { return SERVER_HELLO_DONE; } diff --git a/src/ssl/tls_record.h b/src/ssl/tls_record.h index b4c052a1c..7d3bc4c6a 100644 --- a/src/ssl/tls_record.h +++ b/src/ssl/tls_record.h @@ -1,3 +1,4 @@ +1 /* * TLS Record Handling * (C) 2004-2010 Jack Lloyd diff --git a/src/ssl/tls_server.cpp b/src/ssl/tls_server.cpp index 20e98797f..1f301e6b1 100644 --- a/src/ssl/tls_server.cpp +++ b/src/ssl/tls_server.cpp @@ -262,7 +262,7 @@ void TLS_Server::state_machine() } } else - throw Unexpected_Message("Unknown message type recieved"); + throw Unexpected_Message("Unknown message type received"); } /* @@ -471,7 +471,7 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, active = true; } else - throw Unexpected_Message("Unknown handshake message recieved"); + throw Unexpected_Message("Unknown handshake message received"); } /* diff --git a/src/ssl/unix_socket/info.txt b/src/ssl/unix_socket/info.txt deleted file mode 100644 index 15fc50f5b..000000000 --- a/src/ssl/unix_socket/info.txt +++ /dev/null @@ -1,20 +0,0 @@ -define UNIX_SOCKET - -<source> -unx_sock.cpp -</source> - -<header:public> -unx_sock.h -</header:public> - -<requires> -ssl -</requires> - -<os> -linux -freebsd -netbsd -solaris -</os> diff --git a/src/ssl/unix_socket/unx_sock.cpp b/src/ssl/unix_socket/unx_sock.cpp deleted file mode 100644 index a7c19b70c..000000000 --- a/src/ssl/unix_socket/unx_sock.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* -* Unix Socket -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/unx_sock.h> -#include <botan/exceptn.h> - -#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> - -namespace Botan { - -/** -* Unix Socket Constructor -*/ -Unix_Socket::Unix_Socket(const std::string& host, u16bit port) : peer(host) - { - sockfd = -1; - - hostent* host_addr = ::gethostbyname(host.c_str()); - - if(host_addr == 0) - throw Stream_IO_Error("Unix_Socket: gethostbyname failed for " + host); - if(host_addr->h_addrtype != AF_INET) // FIXME - throw Stream_IO_Error("Unix_Socket: " + host + " has IPv6 address"); - - int fd = ::socket(PF_INET, SOCK_STREAM, 0); - if(fd == -1) - throw Stream_IO_Error("Unix_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 Stream_IO_Error("Unix_Socket: connect failed"); - } - - sockfd = fd; - } - -/** -* Unix Socket Constructor -*/ -Unix_Socket::Unix_Socket(int fd, const std::string& peer_id) - { - sockfd = fd; - peer = peer_id; - } - -/** -* Read from a Unix socket -*/ -size_t Unix_Socket::read(byte buf[], size_t length) - { - if(sockfd == -1) - throw Stream_IO_Error("Unix_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 Stream_IO_Error("Unix_Socket::read: Socket read failed"); - } - - got += this_time; - length -= this_time; - } - return got; - } - -/** -* Write to a Unix socket -*/ -void Unix_Socket::write(const byte buf[], size_t length) - { - if(sockfd == -1) - throw Stream_IO_Error("Unix_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 Stream_IO_Error("Unix_Socket::write: Socket write failed"); - } - - offset += sent; - length -= sent; - } - } - -/** -* Close a Unix socket -*/ -void Unix_Socket::close() - { - if(sockfd != -1) - { - if(::close(sockfd) != 0) - throw Stream_IO_Error("Unix_Socket::close failed"); - sockfd = -1; - } - } - -/** -* Return the peer's name -*/ -std::string Unix_Socket::peer_id() const - { - return peer; - } - -/** -* Unix Server Socket Constructor -*/ -Unix_Server_Socket::Unix_Server_Socket(u16bit port) - { - sockfd = -1; - - int fd = ::socket(PF_INET, SOCK_STREAM, 0); - if(fd == -1) - throw Stream_IO_Error("Unix_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 Stream_IO_Error("Unix_Server_Socket: bind failed"); - } - - if(listen(fd, 100) != 0) // FIXME: totally arbitrary - { - ::close(fd); - throw Stream_IO_Error("Unix_Server_Socket: listen failed"); - } - - sockfd = fd; - } - -/** -* Close a Unix socket -*/ -void Unix_Server_Socket::close() - { - if(sockfd != -1) - { - if(::close(sockfd) != 0) - throw Stream_IO_Error("Unix_Server_Socket::close failed"); - sockfd = -1; - } - } - -/** -* Accept a new connection -*/ -Socket* Unix_Server_Socket::accept() - { - // FIXME: grab IP of remote side, use gethostbyaddr, store as peer_id - int retval = ::accept(sockfd, 0, 0); - if(retval == -1) - throw Stream_IO_Error("Unix_Server_Socket: accept failed"); - return new Unix_Socket(retval); - } - -} diff --git a/src/ssl/unix_socket/unx_sock.h b/src/ssl/unix_socket/unx_sock.h deleted file mode 100644 index 58c7ada69..000000000 --- a/src/ssl/unix_socket/unx_sock.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -* Unix Socket -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SOCKET_UNIX_H__ -#define BOTAN_TLS_SOCKET_UNIX_H__ - -#include <botan/socket.h> - -namespace Botan { - -/** - FIXME: the current socket interface is totally unusable - It has to handle (cleanly): - - TCP, UDP, and SCTP, where UDP is only usable with DTLS and - TCP/SCTP is only usable with TLS. - - Alternate socket interfaces (ACE, Netxx, whatever) with - minimal wrapping needed. -*/ - - -/** -* Unix Socket Base Class -*/ -class BOTAN_DLL Unix_Socket : public Socket - { - public: - size_t read(byte[], size_t); - void write(const byte[], size_t); - - std::string peer_id() const; - - void close(); - Unix_Socket(int, const std::string& = ""); - Unix_Socket(const std::string&, u16bit); - ~Unix_Socket() { close(); } - private: - std::string peer; - int sockfd; - }; - -/** -* Unix Server Socket Base Class -*/ -class BOTAN_DLL Unix_Server_Socket : public Server_Socket - { - public: - Socket* accept(); - void close(); - - Unix_Server_Socket(u16bit); - ~Unix_Server_Socket() { close(); } - private: - int sockfd; - }; - -} - -#endif diff --git a/src/stream/ctr/ctr.cpp b/src/stream/ctr/ctr.cpp index d221dc441..3a370eca3 100644 --- a/src/stream/ctr/ctr.cpp +++ b/src/stream/ctr/ctr.cpp @@ -1,6 +1,6 @@ /* * Counter mode -* (C) 1999-2010 Jack Lloyd +* (C) 1999-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -85,20 +85,21 @@ void CTR_BE::set_iv(const byte iv[], size_t iv_len) if(!valid_iv_length(iv_len)) throw Invalid_IV_Length(name(), iv_len); - const size_t BLOCK_SIZE = permutation->block_size(); + const size_t bs = permutation->block_size(); zeroise(counter); counter.copy(0, iv, iv_len); + /* + * Set counter blocks to IV, IV + 1, ... IV + 255 + */ for(size_t i = 1; i != 256; ++i) { - counter.copy(i*BLOCK_SIZE, - &counter[(i-1)*BLOCK_SIZE], - BLOCK_SIZE); + counter.copy(i*bs, &counter[(i-1)*bs], bs); - for(size_t j = 0; j != BLOCK_SIZE; ++j) - if(++counter[i*BLOCK_SIZE + (BLOCK_SIZE-1-j)]) + for(size_t j = 0; j != bs; ++j) + if(++counter[i*bs + (bs - 1 - j)]) break; } @@ -111,12 +112,17 @@ void CTR_BE::set_iv(const byte iv[], size_t iv_len) */ void CTR_BE::increment_counter() { - const size_t BLOCK_SIZE = permutation->block_size(); + const size_t bs = permutation->block_size(); + /* + * Each counter value always needs to be incremented by 256, + * so we don't touch the lowest byte and instead treat it as + * an increment of one starting with the next byte. + */ for(size_t i = 0; i != 256; ++i) { - for(size_t j = 1; j != BLOCK_SIZE; ++j) - if(++counter[i*BLOCK_SIZE + (BLOCK_SIZE-1-j)]) + for(size_t j = 1; j != bs; ++j) + if(++counter[i*bs + (bs - 1 - j)]) break; } diff --git a/src/utils/asm_ia32/asm_macr_ia32.h b/src/utils/asm_x86_32/asm_x86_32.h index 2ea69512b..d5482c419 100644 --- a/src/utils/asm_ia32/asm_macr_ia32.h +++ b/src/utils/asm_x86_32/asm_x86_32.h @@ -1,12 +1,12 @@ /* -* Assembly Macros +* Assembly Macros for 32-bit x86 * (C) 1999-2008 Jack Lloyd * * Distributed under the terms of the Botan license */ -#ifndef BOTAN_IA32_ASM_MACROS_H__ -#define BOTAN_IA32_ASM_MACROS_H__ +#ifndef BOTAN_ASM_MACROS_X86_32_H__ +#define BOTAN_ASM_MACROS_X86_32_H__ /* * General/Global Macros diff --git a/src/utils/asm_ia32/info.txt b/src/utils/asm_x86_32/info.txt index 997d51b8c..21244968f 100644 --- a/src/utils/asm_ia32/info.txt +++ b/src/utils/asm_x86_32/info.txt @@ -1,11 +1,11 @@ load_on dep <header:internal> -asm_macr_ia32.h +asm_x86_32.h </header:internal> <arch> -ia32 +x86_32 </arch> # ELF systems @@ -19,7 +19,6 @@ solaris </os> <cc> -clang gcc icc </cc> diff --git a/src/utils/asm_amd64/asm_macr_amd64.h b/src/utils/asm_x86_64/asm_x86_64.h index 287fa3e88..7abc1f392 100644 --- a/src/utils/asm_amd64/asm_macr_amd64.h +++ b/src/utils/asm_x86_64/asm_x86_64.h @@ -1,12 +1,12 @@ /* -* Assembly Macros +* Assembly Macros for 64-bit x86 * (C) 1999-2008 Jack Lloyd * * Distributed under the terms of the Botan license */ -#ifndef BOTAN_AMD64_ASM_MACROS_H__ -#define BOTAN_AMD64_ASM_MACROS_H__ +#ifndef BOTAN_ASM_MACROS_X86_64_H__ +#define BOTAN_ASM_MACROS_X86_64_H__ /* * General/Global Macros diff --git a/src/utils/asm_amd64/info.txt b/src/utils/asm_x86_64/info.txt index 404aeca7b..3173f3b14 100644 --- a/src/utils/asm_amd64/info.txt +++ b/src/utils/asm_x86_64/info.txt @@ -1,11 +1,11 @@ load_on dep <header:internal> -asm_macr_amd64.h +asm_x86_64.h </header:internal> <arch> -amd64 +x86_64 </arch> <cc> diff --git a/src/utils/bswap.h b/src/utils/bswap.h index 6dfed0ba9..9d2c9bc28 100644 --- a/src/utils/bswap.h +++ b/src/utils/bswap.h @@ -1,6 +1,6 @@ /* * Byte Swapping Operations -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2011 Jack Lloyd * (C) 2007 Yves Jerschow * * Distributed under the terms of the Botan license @@ -21,38 +21,55 @@ namespace Botan { /** * Swap a 16 bit integer */ -inline u16bit reverse_bytes(u16bit input) +inline u16bit reverse_bytes(u16bit val) { - return rotate_left(input, 8); + return rotate_left(val, 8); } /** * Swap a 32 bit integer */ -inline u32bit reverse_bytes(u32bit input) +inline u32bit reverse_bytes(u32bit val) { -#if BOTAN_GCC_VERSION >= 430 +#if BOTAN_GCC_VERSION >= 430 && !defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + /* + GCC intrinsic added in 4.3, works for a number of CPUs - // GCC intrinsic added in 4.3, works for a number of CPUs - return __builtin_bswap32(input); + However avoid under ARM, as it branches to a function in libgcc + instead of generating inline asm, so slower even than the generic + rotate version below. + */ + return __builtin_bswap32(val); #elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) // GCC-style inline assembly for x86 or x86-64 - asm("bswapl %0" : "=r" (input) : "0" (input)); - return input; + asm("bswapl %0" : "=r" (val) : "0" (val)); + return val; + +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) + + asm ("eor r3, %1, %1, ror #16\n\t" + "bic r3, r3, #0x00FF0000\n\t" + "mov %0, %1, ror #8\n\t" + "eor %0, %0, r3, lsr #8" + : "=r" (val) + : "0" (val) + : "r3", "cc"); + + return val; -#elif defined(_MSC_VER) && defined(BOTAN_TARGET_ARCH_IS_IA32) +#elif defined(_MSC_VER) && defined(BOTAN_TARGET_ARCH_IS_X86_32) // Visual C++ inline asm for 32-bit x86, by Yves Jerschow - __asm mov eax, input; + __asm mov eax, val; __asm bswap eax; #else // Generic implementation - return (rotate_right(input, 8) & 0xFF00FF00) | - (rotate_left (input, 8) & 0x00FF00FF); + return (rotate_right(val, 8) & 0xFF00FF00) | + (rotate_left (val, 8) & 0x00FF00FF); #endif } @@ -60,17 +77,17 @@ inline u32bit reverse_bytes(u32bit input) /** * Swap a 64 bit integer */ -inline u64bit reverse_bytes(u64bit input) +inline u64bit reverse_bytes(u64bit val) { #if BOTAN_GCC_VERSION >= 430 // GCC intrinsic added in 4.3, works for a number of CPUs - return __builtin_bswap64(input); + return __builtin_bswap64(val); -#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_ARCH_IS_AMD64) +#elif BOTAN_USE_GCC_INLINE_ASM && defined(BOTAN_TARGET_ARCH_IS_X86_64) // GCC-style inline assembly for x86-64 - asm("bswapq %0" : "=r" (input) : "0" (input)); - return input; + asm("bswapq %0" : "=r" (val) : "0" (val)); + return val; #else /* Generic implementation. Defined in terms of 32-bit bswap so any @@ -78,8 +95,8 @@ inline u64bit reverse_bytes(u64bit input) * useful for 32-bit x86). */ - u32bit hi = static_cast<u32bit>(input >> 32); - u32bit lo = static_cast<u32bit>(input); + u32bit hi = static_cast<u32bit>(val >> 32); + u32bit lo = static_cast<u32bit>(val); hi = reverse_bytes(hi); lo = reverse_bytes(lo); diff --git a/src/utils/cpuid.cpp b/src/utils/cpuid.cpp index 9ea9e82ad..cb6fdaba5 100644 --- a/src/utils/cpuid.cpp +++ b/src/utils/cpuid.cpp @@ -30,8 +30,21 @@ // Only available starting in GCC 4.3 #include <cpuid.h> - #define CALL_CPUID(type, out) \ - do { __get_cpuid(type, out, out+1, out+2, out+3); } while(0); + +namespace { + + /* + * Prevent inlining to work around GCC bug 44174 + */ + void __attribute__((__noinline__)) call_gcc_cpuid(Botan::u32bit type, + Botan::u32bit out[4]) + { + __get_cpuid(type, out, out+1, out+2, out+3); + } + + #define CALL_CPUID call_gcc_cpuid + +} #else #warning "No method of calling CPUID for this compiler" @@ -149,9 +162,9 @@ void CPUID::initialize() u32bit cpuid[4] = { 0 }; CALL_CPUID(1, cpuid); - x86_processor_flags = ((u64bit)cpuid[2] << 32) | cpuid[3]; + x86_processor_flags = (static_cast<u64bit>(cpuid[2]) << 32) | cpuid[3]; -#if defined(BOTAN_TARGET_ARCH_IS_AMD64) +#if defined(BOTAN_TARGET_ARCH_IS_X86_64) /* * If we don't have access to CPUID, we can still safely assume that * any x86-64 processor has SSE2. diff --git a/src/utils/dyn_load/info.txt b/src/utils/dyn_load/info.txt index 512410460..6d74acb86 100644 --- a/src/utils/dyn_load/info.txt +++ b/src/utils/dyn_load/info.txt @@ -1,10 +1,11 @@ define DYNAMIC_LOADER <os> -linux freebsd -openbsd +linux netbsd +openbsd +qnx solaris windows </os> diff --git a/src/utils/mlock.cpp b/src/utils/mlock.cpp index cd92860df..800425665 100644 --- a/src/utils/mlock.cpp +++ b/src/utils/mlock.cpp @@ -31,7 +31,7 @@ bool has_mlock() bool lock_mem(void* ptr, size_t bytes) { #if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) - return (::mlock((char*)ptr, bytes) == 0); + return (::mlock(static_cast<char*>(ptr), bytes) == 0); #elif defined(BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK) return (::VirtualLock(ptr, bytes) != 0); #else @@ -45,7 +45,7 @@ bool lock_mem(void* ptr, size_t bytes) void unlock_mem(void* ptr, size_t bytes) { #if defined(BOTAN_TARGET_OS_HAS_POSIX_MLOCK) - ::munlock((char*)ptr, bytes); + ::munlock(static_cast<char*>(ptr), bytes); #elif defined(BOTAN_TARGET_OS_HAS_WIN32_VIRTUAL_LOCK) ::VirtualUnlock(ptr, bytes); #endif diff --git a/src/utils/simd_32/simd_32.h b/src/utils/simd_32/simd_32.h deleted file mode 100644 index e2c483d20..000000000 --- a/src/utils/simd_32/simd_32.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -* Lightweight wrappers for SIMD operations -* (C) 2009 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_SIMD_32_H__ -#define BOTAN_SIMD_32_H__ - -#include <botan/types.h> -#include <botan/rotate.h> - -#if defined(BOTAN_TARGET_CPU_HAS_SSE2) && !defined(BOTAN_NO_SSE_INTRINSICS) - - #include <botan/internal/simd_sse.h> - namespace Botan { typedef SIMD_SSE2 SIMD_32; } - -#elif defined(BOTAN_TARGET_CPU_HAS_ALTIVEC) - - #include <botan/internal/simd_altivec.h> - namespace Botan { typedef SIMD_Altivec SIMD_32; } - -#else - - #include <botan/internal/simd_scalar.h> - namespace Botan { typedef SIMD_Scalar SIMD_32; } - -#endif - -namespace Botan { - -template<> -inline SIMD_32 rotate_left(SIMD_32 x, size_t rot) - { - x.rotate_left(rot); - return x; - } - -template<> -inline SIMD_32 rotate_right(SIMD_32 x, size_t rot) - { - x.rotate_right(rot); - return x; - } - -} - -#endif diff --git a/src/wrap/python/rsa.cpp b/src/wrap/python/rsa.cpp index 5e2e0ba30..dc6053503 100644 --- a/src/wrap/python/rsa.cpp +++ b/src/wrap/python/rsa.cpp @@ -27,6 +27,8 @@ class Py_RSA_PrivateKey Py_RSA_PrivateKey(std::string pem_str, Python_RandomNumberGenerator& rng, std::string pass); + Py_RSA_PrivateKey(std::string pem_str, + Python_RandomNumberGenerator& rng); Py_RSA_PrivateKey(u32bit bits, Python_RandomNumberGenerator& rng); ~Py_RSA_PrivateKey() { delete rsa_key; } @@ -87,6 +89,21 @@ Py_RSA_PrivateKey::Py_RSA_PrivateKey(u32bit bits, } Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str, + Python_RandomNumberGenerator& rng) + { + DataSource_Memory in(pem_str); + + Private_Key* pkcs8_key = + PKCS8::load_key(in, + rng.get_underlying_rng()); + + rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key); + + if(!rsa_key) + throw std::invalid_argument("Key is not an RSA key"); + } + +Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str, Python_RandomNumberGenerator& rng, std::string passphrase) { @@ -195,6 +212,7 @@ void export_rsa() python::class_<Py_RSA_PrivateKey> ("RSA_PrivateKey", python::init<std::string, Python_RandomNumberGenerator&, std::string>()) + .def(python::init<std::string, Python_RandomNumberGenerator&>()) .def(python::init<u32bit, Python_RandomNumberGenerator&>()) .def("to_string", &Py_RSA_PrivateKey::to_string) .def("to_ber", &Py_RSA_PrivateKey::to_ber) |