aboutsummaryrefslogtreecommitdiffstats
path: root/src/tests
diff options
context:
space:
mode:
authorlloyd <[email protected]>2014-01-01 21:20:55 +0000
committerlloyd <[email protected]>2014-01-01 21:20:55 +0000
commit197dc467dec28a04c3b2f30da7cef122dfbb13e9 (patch)
treecdbd3ddaec051c72f0a757db461973d90c37b97a /src/tests
parent62faac373c07cfe10bc8c309e89ebdd30d8e5eaa (diff)
Shuffle things around. Add NIST X.509 test to build.
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/nist_x509.cpp331
-rw-r--r--src/tests/test_aead.cpp88
-rw-r--r--src/tests/test_bigint.cpp357
-rw-r--r--src/tests/test_block.cpp75
-rw-r--r--src/tests/test_cryptobox.cpp45
-rw-r--r--src/tests/test_cvc.cpp573
-rw-r--r--src/tests/test_eax.cpp229
-rw-r--r--src/tests/test_ecc.cpp842
-rw-r--r--src/tests/test_ecdh.cpp132
-rw-r--r--src/tests/test_ecdsa.cpp490
-rw-r--r--src/tests/test_hash.cpp60
-rw-r--r--src/tests/test_hkdf.cpp70
-rw-r--r--src/tests/test_kdf.cpp43
-rw-r--r--src/tests/test_keywrap.cpp90
-rw-r--r--src/tests/test_mac.cpp62
-rw-r--r--src/tests/test_modes.cpp79
-rw-r--r--src/tests/test_ocb.cpp142
-rw-r--r--src/tests/test_passhash.cpp94
-rw-r--r--src/tests/test_pbkdf.cpp48
-rw-r--r--src/tests/test_pubkey.cpp935
-rw-r--r--src/tests/test_rng.cpp63
-rw-r--r--src/tests/test_rng.h61
-rw-r--r--src/tests/test_stream.cpp71
-rw-r--r--src/tests/test_tls.cpp281
-rw-r--r--src/tests/test_transform.cpp50
-rw-r--r--src/tests/test_x509.cpp255
-rw-r--r--src/tests/tests.cpp190
-rw-r--r--src/tests/tests.h77
28 files changed, 5833 insertions, 0 deletions
diff --git a/src/tests/nist_x509.cpp b/src/tests/nist_x509.cpp
new file mode 100644
index 000000000..4f75c9f88
--- /dev/null
+++ b/src/tests/nist_x509.cpp
@@ -0,0 +1,331 @@
+/*
+ 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.
+
+Known Failures/Problems
+
+Policy extensions are not implemented, so we skip tests #34-#53.
+
+Tests #75 and #76 are skipped as they make use of relatively obscure CRL
+extensions which are not supported.
+
+In addition, please note that some of the tests have their results altered from
+what the test result should be according to NIST's documentation. The changes
+are clearly marked (see x509test.cpp; search for "CHANGE OF TEST RESULT") and
+there are comments explaining why the results where changed. Currently, tests
+#19, #65, and #67 have had their results changed from the official results.
+*/
+
+#include "tests.h"
+
+#include <botan/x509path.h>
+#include <botan/init.h>
+
+#include <algorithm>
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <vector>
+#include <map>
+#include <cstdlib>
+
+#include <dirent.h>
+
+using namespace Botan;
+
+std::vector<std::string> dir_listing(const std::string&);
+
+void run_one_test(u32bit, Path_Validation_Result::Code,
+ std::string, std::string,
+ std::vector<std::string>,
+ std::vector<std::string>);
+
+std::map<size_t, Path_Validation_Result::Code> expected_results;
+size_t unexp_failure, unexp_success, wrong_error, skipped;
+
+void populate_expected_results();
+
+size_t test_nist_x509()
+ {
+ unexp_failure = unexp_success = wrong_error = skipped = 0;
+
+ try {
+
+ populate_expected_results();
+
+ const std::string root_test_dir = "src/test-data/nist_x509/";
+ std::vector<std::string> test_dirs = dir_listing(root_test_dir);
+ std::sort(test_dirs.begin(), test_dirs.end());
+
+ for(size_t j = 0; j != test_dirs.size(); j++)
+ {
+ const std::string test_dir = root_test_dir + test_dirs[j] + "/";
+ std::vector<std::string> all_files = dir_listing(test_dir);
+
+ std::vector<std::string> certs, crls;
+ std::string root_cert, to_verify;
+
+ for(size_t k = 0; k != all_files.size(); k++)
+ {
+ const std::string current = all_files[k];
+ if(current.find("int") != std::string::npos &&
+ current.find(".crt") != std::string::npos)
+ certs.push_back(test_dir + current);
+ else if(current.find("root.crt") != std::string::npos)
+ root_cert = test_dir + current;
+ else if(current.find("end.crt") != std::string::npos)
+ to_verify = test_dir + current;
+ else if(current.find(".crl") != std::string::npos)
+ crls.push_back(test_dir + current);
+ }
+
+ if(expected_results.find(j+1) == expected_results.end())
+ {
+#if 0
+ std::cout << "Testing disabled for test #" << j+1
+ << " <skipped>" << std::endl;
+#endif
+ skipped++;
+ continue;
+ }
+
+ run_one_test(j+1, expected_results[j+1],
+ root_cert, to_verify, certs, crls);
+ }
+
+ }
+ catch(std::exception& e)
+ {
+ std::cout << e.what() << std::endl;
+ return 1;
+ }
+
+ std::cout << "Total unexpected failures: " << unexp_failure << std::endl;
+ std::cout << "Total unexpected successes: " << unexp_success << std::endl;
+ std::cout << "Total incorrect failures: " << wrong_error << std::endl;
+ std::cout << "Tests skipped: " << skipped << std::endl;
+
+ return unexp_failure + unexp_success + wrong_error;
+ }
+
+void run_one_test(u32bit test_no, Path_Validation_Result::Code expected,
+ std::string root_cert, std::string to_verify,
+ std::vector<std::string> certs,
+ std::vector<std::string> crls)
+ {
+ std::cout << "NIST X.509 test #" << test_no << "... ";
+
+ Certificate_Store_In_Memory store;
+
+ store.add_certificate(X509_Certificate(root_cert));
+
+ X509_Certificate end_user(to_verify);
+
+ for(size_t j = 0; j != certs.size(); j++)
+ store.add_certificate(X509_Certificate(certs[j]));
+
+ for(size_t j = 0; j != crls.size(); j++)
+ {
+ DataSource_Stream in(crls[j]);
+
+ X509_CRL crl(in);
+ /*
+ std::vector<CRL_Entry> crl_entries = crl.get_revoked();
+ for(u32bit k = 0; k != crl_entries.size(); k++)
+ {
+ std::cout << "Revoked: " << std::flush;
+ for(u32bit l = 0; l != crl_entries[k].serial.size(); l++)
+ printf("%02X", crl_entries[k].serial[l]);
+ std::cout << std::endl;
+ }
+ */
+ store.add_crl(crl);
+ }
+
+ Path_Validation_Restrictions restrictions(true);
+
+ Path_Validation_Result validation_result =
+ x509_path_validate(end_user,
+ restrictions,
+ store);
+
+ Path_Validation_Result::Code result = validation_result.result();
+
+ if(result == expected)
+ {
+ std::cout << "passed" << std::endl;
+ return;
+ }
+
+ const std::string result_str = Path_Validation_Result::status_string(result);
+ const std::string exp_str = Path_Validation_Result::status_string(expected);
+
+ if(expected == Certificate_Status_Code::VERIFIED)
+ {
+ std::cout << "unexpected failure: " << result_str << std::endl;
+ unexp_failure++;
+ }
+ else if(result == Certificate_Status_Code::VERIFIED)
+ {
+ std::cout << "unexpected success: " << exp_str << std::endl;
+ unexp_success++;
+ }
+ else
+ {
+ std::cout << "wrong error: " << result_str << "/" << exp_str << std::endl;
+ wrong_error++;
+ }
+ }
+
+std::vector<std::string> dir_listing(const std::string& dir_name)
+ {
+ DIR* dir = opendir(dir_name.c_str());
+ if(!dir)
+ {
+ std::cout << "Error, couldn't open dir " << dir_name << std::endl;
+ std::exit(1);
+ }
+
+ std::vector<std::string> listing;
+
+ while(true)
+ {
+ struct dirent* dir_ent = readdir(dir);
+
+ if(dir_ent == 0)
+ break;
+ const std::string entry = dir_ent->d_name;
+ if(entry == "." || entry == "..")
+ continue;
+
+ listing.push_back(entry);
+ }
+ closedir(dir);
+
+ return listing;
+ }
+
+/*
+ The expected results are essentially the error codes that best coorespond
+ to the problem described in the testing documentation.
+
+ There are a few cases where the tests say there should or should not be an
+ error, and I disagree. A few of the tests have test results different from
+ what they "should" be: these changes are marked as such, and have comments
+ explaining the problem at hand.
+*/
+void populate_expected_results()
+ {
+ /* OK, not a super great way of doing this... */
+ expected_results[1] = Certificate_Status_Code::VERIFIED;
+ expected_results[2] = Certificate_Status_Code::SIGNATURE_ERROR;
+ expected_results[3] = Certificate_Status_Code::SIGNATURE_ERROR;
+ expected_results[4] = Certificate_Status_Code::VERIFIED;
+ expected_results[5] = Certificate_Status_Code::CERT_NOT_YET_VALID;
+ expected_results[6] = Certificate_Status_Code::CERT_NOT_YET_VALID;
+ expected_results[7] = Certificate_Status_Code::VERIFIED;
+ expected_results[8] = Certificate_Status_Code::CERT_NOT_YET_VALID;
+ expected_results[9] = Certificate_Status_Code::CERT_HAS_EXPIRED;
+ expected_results[10] = Certificate_Status_Code::CERT_HAS_EXPIRED;
+ expected_results[11] = Certificate_Status_Code::CERT_HAS_EXPIRED;
+ expected_results[12] = Certificate_Status_Code::VERIFIED;
+ expected_results[13] = Certificate_Status_Code::CERT_ISSUER_NOT_FOUND;
+
+ expected_results[14] = Certificate_Status_Code::CERT_ISSUER_NOT_FOUND;
+ expected_results[15] = Certificate_Status_Code::VERIFIED;
+ expected_results[16] = Certificate_Status_Code::VERIFIED;
+ expected_results[17] = Certificate_Status_Code::VERIFIED;
+ expected_results[18] = Certificate_Status_Code::VERIFIED;
+
+ expected_results[19] = Certificate_Status_Code::CRL_NOT_FOUND;
+ expected_results[20] = Certificate_Status_Code::CERT_IS_REVOKED;
+ expected_results[21] = Certificate_Status_Code::CERT_IS_REVOKED;
+
+ expected_results[22] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[23] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[24] = Certificate_Status_Code::VERIFIED;
+ expected_results[25] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[26] = Certificate_Status_Code::VERIFIED;
+ expected_results[27] = Certificate_Status_Code::VERIFIED;
+ expected_results[28] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[29] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
+ expected_results[30] = Certificate_Status_Code::VERIFIED;
+
+ expected_results[31] = Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER;
+ expected_results[32] = Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER;
+ expected_results[33] = Certificate_Status_Code::VERIFIED;
+
+ /*
+ 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 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
+ 3) With the user policy as test-policy-1 (2.16.840.1.101.3.1.48.1) and
+ an explict policy required
+ 4) With the user policy as either test-policy-1 or test-policy-2 and an
+ explicit policy required
+
+ This provides reasonably good coverage of the possible outcomes.
+ */
+
+ expected_results[34] = Certificate_Status_Code::VERIFIED;
+ expected_results[35] = Certificate_Status_Code::VERIFIED;
+ expected_results[36] = Certificate_Status_Code::VERIFIED;
+ expected_results[37] = Certificate_Status_Code::VERIFIED;
+ expected_results[38] = Certificate_Status_Code::VERIFIED;
+ expected_results[39] = Certificate_Status_Code::VERIFIED;
+ expected_results[40] = Certificate_Status_Code::VERIFIED;
+ expected_results[41] = Certificate_Status_Code::VERIFIED;
+ expected_results[42] = Certificate_Status_Code::VERIFIED;
+ expected_results[43] = Certificate_Status_Code::VERIFIED;
+ expected_results[44] = Certificate_Status_Code::VERIFIED;
+
+ //expected_results[45] = Certificate_Status_Code::EXPLICT_POLICY_REQUIRED;
+ //expected_results[46] = Certificate_Status_Code::ACCEPT;
+ //expected_results[47] = Certificate_Status_Code::EXPLICT_POLICY_REQUIRED;
+
+ expected_results[48] = Certificate_Status_Code::VERIFIED;
+ expected_results[49] = Certificate_Status_Code::VERIFIED;
+ expected_results[50] = Certificate_Status_Code::VERIFIED;
+ expected_results[51] = Certificate_Status_Code::VERIFIED;
+ expected_results[52] = Certificate_Status_Code::VERIFIED;
+ expected_results[53] = Certificate_Status_Code::VERIFIED;
+
+ expected_results[54] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
+ expected_results[55] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
+ expected_results[56] = Certificate_Status_Code::VERIFIED;
+ expected_results[57] = Certificate_Status_Code::VERIFIED;
+ expected_results[58] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
+ expected_results[59] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
+ expected_results[60] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
+ expected_results[61] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
+ expected_results[62] = Certificate_Status_Code::VERIFIED;
+ expected_results[63] = Certificate_Status_Code::VERIFIED;
+
+ expected_results[64] = Certificate_Status_Code::SIGNATURE_ERROR;
+
+ expected_results[65] = Certificate_Status_Code::CRL_NOT_FOUND;
+ expected_results[66] = Certificate_Status_Code::CRL_NOT_FOUND;
+
+ expected_results[67] = Certificate_Status_Code::VERIFIED;
+
+ expected_results[68] = Certificate_Status_Code::CERT_IS_REVOKED;
+ expected_results[69] = Certificate_Status_Code::CERT_IS_REVOKED;
+ expected_results[70] = Certificate_Status_Code::CERT_IS_REVOKED;
+ expected_results[71] = Certificate_Status_Code::CERT_IS_REVOKED;
+ expected_results[72] = Certificate_Status_Code::CRL_HAS_EXPIRED;
+ expected_results[73] = Certificate_Status_Code::CRL_HAS_EXPIRED;
+ expected_results[74] = Certificate_Status_Code::VERIFIED;
+
+ /* These tests use weird CRL extensions which aren't supported yet */
+ //expected_results[75] = ;
+ //expected_results[76] = ;
+ }
diff --git a/src/tests/test_aead.cpp b/src/tests/test_aead.cpp
new file mode 100644
index 000000000..e8643334f
--- /dev/null
+++ b/src/tests/test_aead.cpp
@@ -0,0 +1,88 @@
+#include "tests.h"
+
+#include <botan/hex.h>
+#include <botan/aead.h>
+#include <iostream>
+#include <fstream>
+#include <memory>
+
+using namespace Botan;
+
+namespace {
+
+secure_vector<byte> aead(const std::string& algo,
+ Cipher_Dir dir,
+ const secure_vector<byte>& pt,
+ const secure_vector<byte>& nonce,
+ const secure_vector<byte>& ad,
+ const secure_vector<byte>& key)
+ {
+ std::unique_ptr<AEAD_Mode> aead(get_aead(algo, dir));
+
+ aead->set_key(key);
+ aead->set_associated_data_vec(ad);
+ aead->start_vec(nonce);
+
+ secure_vector<byte> ct = pt;
+ aead->finish(ct);
+
+ return ct;
+ }
+
+bool aead_test(const std::string& algo,
+ const std::string& pt,
+ const std::string& ct,
+ const std::string& nonce_hex,
+ const std::string& ad_hex,
+ const std::string& key_hex)
+ {
+ auto nonce = hex_decode_locked(nonce_hex);
+ auto ad = hex_decode_locked(ad_hex);
+ auto key = hex_decode_locked(key_hex);
+
+ size_t fail = 0;
+
+ //std::cout << algo << " pt=" << pt << " ct=" << ct << " key=" << key_hex << " nonce=" << nonce_hex << " ad=" << ad_hex << "\n";
+
+ const std::string ct2 = hex_encode(aead(algo,
+ ENCRYPTION,
+ hex_decode_locked(pt),
+ nonce,
+ ad,
+ key));
+
+ if(ct != ct2)
+ {
+ std::cout << algo << " got ct " << ct2 << " expected " << ct << "\n";
+ ++fail;
+ }
+
+ const std::string pt2 = hex_encode(aead(algo,
+ DECRYPTION,
+ hex_decode_locked(ct2),
+ nonce,
+ ad,
+ key));
+
+ if(pt != pt2)
+ {
+ std::cout << algo << " got pt " << pt2 << " expected " << pt << "\n";
+ ++fail;
+ }
+
+ return (ct == ct2) && (pt == pt2);
+ }
+
+}
+
+size_t test_aead()
+ {
+ std::ifstream vec(CHECKS_DIR "/aead.vec");
+
+ return run_tests_bb(vec, "AEAD", "Out", true,
+ [](std::map<std::string, std::string> m)
+ {
+ return aead_test(m["AEAD"], m["In"], m["Out"],
+ m["Nonce"], m["AD"], m["Key"]);
+ });
+ }
diff --git a/src/tests/test_bigint.cpp b/src/tests/test_bigint.cpp
new file mode 100644
index 000000000..45a20cef6
--- /dev/null
+++ b/src/tests/test_bigint.cpp
@@ -0,0 +1,357 @@
+/*
+* (C) 2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include "tests.h"
+
+#include <vector>
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <cstdlib>
+
+#include <botan/auto_rng.h>
+#include <botan/bigint.h>
+#include <botan/exceptn.h>
+#include <botan/numthry.h>
+using namespace Botan;
+
+size_t check_add(const std::vector<std::string>&);
+size_t check_sub(const std::vector<std::string>&);
+size_t check_mul(const std::vector<std::string>&);
+size_t check_sqr(const std::vector<std::string>&);
+size_t check_div(const std::vector<std::string>&);
+size_t check_mod(const std::vector<std::string>&,
+ Botan::RandomNumberGenerator& rng);
+size_t check_shr(const std::vector<std::string>&);
+size_t check_shl(const std::vector<std::string>&);
+
+size_t check_powmod(const std::vector<std::string>&);
+size_t check_primetest(const std::vector<std::string>&,
+ Botan::RandomNumberGenerator&);
+
+size_t test_bigint()
+ {
+ const std::string filename = CHECKS_DIR "/mp_valid.dat";
+ std::ifstream test_data(filename.c_str());
+
+ if(!test_data)
+ throw Botan::Stream_IO_Error("Couldn't open test file " + filename);
+
+ size_t total_errors = 0;
+ size_t errors = 0, alg_count = 0;
+ std::string algorithm;
+ bool first = true;
+ size_t counter = 0;
+
+ AutoSeeded_RNG rng;
+
+ while(!test_data.eof())
+ {
+ if(test_data.bad() || test_data.fail())
+ throw Botan::Stream_IO_Error("File I/O error reading from " +
+ filename);
+
+ std::string line;
+ std::getline(test_data, line);
+
+ strip(line);
+ if(line.size() == 0) continue;
+
+ // Do line continuation
+ while(line[line.size()-1] == '\\' && !test_data.eof())
+ {
+ line.replace(line.size()-1, 1, "");
+ std::string nextline;
+ std::getline(test_data, nextline);
+ strip(nextline);
+ if(nextline.size() == 0) continue;
+ line += nextline;
+ }
+
+ if(line[0] == '[' && line[line.size() - 1] == ']')
+ {
+ if(!first)
+ test_report("Bigint " + algorithm, alg_count, errors);
+
+ algorithm = line.substr(1, line.size() - 2);
+
+ total_errors += errors;
+ errors = 0;
+ alg_count = 0;
+ counter = 0;
+
+ first = false;
+ continue;
+ }
+
+ std::vector<std::string> substr = parse(line);
+
+#if DEBUG
+ std::cout << "Testing: " << algorithm << std::endl;
+#endif
+
+ size_t new_errors = 0;
+ if(algorithm.find("Addition") != std::string::npos)
+ new_errors = check_add(substr);
+ else if(algorithm.find("Subtraction") != std::string::npos)
+ new_errors = check_sub(substr);
+ else if(algorithm.find("Multiplication") != std::string::npos)
+ new_errors = check_mul(substr);
+ else if(algorithm.find("Square") != std::string::npos)
+ new_errors = check_sqr(substr);
+ else if(algorithm.find("Division") != std::string::npos)
+ new_errors = check_div(substr);
+ else if(algorithm.find("Modulo") != std::string::npos)
+ new_errors = check_mod(substr, rng);
+ else if(algorithm.find("LeftShift") != std::string::npos)
+ new_errors = check_shl(substr);
+ else if(algorithm.find("RightShift") != std::string::npos)
+ new_errors = check_shr(substr);
+ else if(algorithm.find("ModExp") != std::string::npos)
+ new_errors = check_powmod(substr);
+ else if(algorithm.find("PrimeTest") != std::string::npos)
+ new_errors = check_primetest(substr, rng);
+ else
+ std::cout << "Unknown MPI test " << algorithm << std::endl;
+
+ counter++;
+ alg_count++;
+ errors += new_errors;
+
+ if(new_errors)
+ std::cout << "ERROR: BigInt " << algorithm << " failed test #"
+ << std::dec << alg_count << std::endl;
+ }
+
+ return total_errors;
+ }
+
+namespace {
+
+// c==expected, d==a op b, e==a op= b
+size_t results(std::string op,
+ const BigInt& a, const BigInt& b,
+ const BigInt& c, const BigInt& d, const BigInt& e)
+ {
+ std::string op1 = "operator" + op;
+ std::string op2 = op1 + "=";
+
+ if(c == d && d == e)
+ return 0;
+ else
+ {
+ std::cout << std::endl;
+
+ std::cout << "ERROR: " << op1 << std::endl;
+
+ std::cout << "a = " << std::hex << a << std::endl;
+ std::cout << "b = " << std::hex << b << std::endl;
+
+ std::cout << "c = " << std::hex << c << std::endl;
+ std::cout << "d = " << std::hex << d << std::endl;
+ std::cout << "e = " << std::hex << e << std::endl;
+
+ if(d != e)
+ {
+ std::cout << "ERROR: " << op1 << " | " << op2
+ << " mismatch" << std::endl;
+ }
+ return 1;
+ }
+ }
+
+}
+
+size_t check_add(const std::vector<std::string>& args)
+ {
+ BigInt a(args[0]);
+ BigInt b(args[1]);
+ BigInt c(args[2]);
+
+ BigInt d = a + b;
+ BigInt e = a;
+ e += b;
+
+ if(results("+", a, b, c, d, e))
+ return 1;
+
+ d = b + a;
+ e = b;
+ e += a;
+
+ return results("+", a, b, c, d, e);
+ }
+
+size_t check_sub(const std::vector<std::string>& args)
+ {
+ BigInt a(args[0]);
+ BigInt b(args[1]);
+ BigInt c(args[2]);
+
+ BigInt d = a - b;
+ BigInt e = a;
+ e -= b;
+
+ return results("-", a, b, c, d, e);
+ }
+
+size_t check_mul(const std::vector<std::string>& args)
+ {
+ BigInt a(args[0]);
+ BigInt b(args[1]);
+ BigInt c(args[2]);
+
+ /*
+ std::cout << "a = " << args[0] << "\n"
+ << "b = " << args[1] << std::endl;
+ */
+ /* This makes it more likely the fast multiply algorithms will be usable,
+ which is what we really want to test here (the simple n^2 multiply is
+ pretty well tested at this point).
+ */
+ a.grow_to(64);
+ b.grow_to(64);
+
+ BigInt d = a * b;
+ BigInt e = a;
+ e *= b;
+
+ if(results("*", a, b, c, d, e))
+ return 1;
+
+ d = b * a;
+ e = b;
+ e *= a;
+
+ return results("*", a, b, c, d, e);
+ }
+
+size_t check_sqr(const std::vector<std::string>& args)
+ {
+ BigInt a(args[0]);
+ BigInt b(args[1]);
+
+ a.grow_to(64);
+ b.grow_to(64);
+
+ BigInt c = square(a);
+ BigInt d = a * a;
+
+ return results("sqr", a, a, b, c, d);
+ }
+
+size_t check_div(const std::vector<std::string>& args)
+ {
+ BigInt a(args[0]);
+ BigInt b(args[1]);
+ BigInt c(args[2]);
+
+ BigInt d = a / b;
+ BigInt e = a;
+ e /= b;
+
+ return results("/", a, b, c, d, e);
+ }
+
+size_t check_mod(const std::vector<std::string>& args,
+ Botan::RandomNumberGenerator& rng)
+ {
+ BigInt a(args[0]);
+ BigInt b(args[1]);
+ BigInt c(args[2]);
+
+ BigInt d = a % b;
+ BigInt e = a;
+ e %= b;
+
+ size_t got = results("%", a, b, c, d, e);
+
+ if(got) return got;
+
+ word b_word = b.word_at(0);
+
+ /* Won't work for us, just pick one at random */
+ while(b_word == 0)
+ for(size_t j = 0; j != 2*sizeof(word); j++)
+ b_word = (b_word << 4) ^ rng.next_byte();
+
+ b = b_word;
+
+ c = a % b; /* we declare the BigInt % BigInt version to be correct here */
+
+ word d2 = a % b_word;
+ e = a;
+ e %= b_word;
+
+ return results("%(word)", a, b, c, d2, e);
+ }
+
+size_t check_shl(const std::vector<std::string>& args)
+ {
+ BigInt a(args[0]);
+ size_t b = std::atoi(args[1].c_str());
+ BigInt c(args[2]);
+
+ BigInt d = a << b;
+ BigInt e = a;
+ e <<= b;
+
+ return results("<<", a, b, c, d, e);
+ }
+
+size_t check_shr(const std::vector<std::string>& args)
+ {
+ BigInt a(args[0]);
+ size_t b = std::atoi(args[1].c_str());
+ BigInt c(args[2]);
+
+ BigInt d = a >> b;
+ BigInt e = a;
+ e >>= b;
+
+ return results(">>", a, b, c, d, e);
+ }
+
+/* Make sure that (a^b)%m == r */
+size_t check_powmod(const std::vector<std::string>& args)
+ {
+ BigInt a(args[0]);
+ BigInt b(args[1]);
+ BigInt m(args[2]);
+ BigInt c(args[3]);
+
+ BigInt r = power_mod(a, b, m);
+
+ if(c != r)
+ {
+ std::cout << "ERROR: power_mod" << std::endl;
+ std::cout << "a = " << std::hex << a << std::endl;
+ std::cout << "b = " << std::hex << b << std::endl;
+ std::cout << "m = " << std::hex << m << std::endl;
+ std::cout << "c = " << std::hex << c << std::endl;
+ std::cout << "r = " << std::hex << r << std::endl;
+ return 1;
+ }
+ return 0;
+ }
+
+/* Make sure that n is prime or not prime, according to should_be_prime */
+size_t check_primetest(const std::vector<std::string>& args,
+ Botan::RandomNumberGenerator& rng)
+ {
+ BigInt n(args[0]);
+ bool should_be_prime = (args[1] == "1");
+
+ bool is_prime = Botan::verify_prime(n, rng);
+
+ if(is_prime != should_be_prime)
+ {
+ std::cout << "ERROR: verify_prime" << std::endl;
+ std::cout << "n = " << n << std::endl;
+ std::cout << is_prime << " != " << should_be_prime << std::endl;
+ }
+ return 0;
+ }
diff --git a/src/tests/test_block.cpp b/src/tests/test_block.cpp
new file mode 100644
index 000000000..51241d69b
--- /dev/null
+++ b/src/tests/test_block.cpp
@@ -0,0 +1,75 @@
+#include "tests.h"
+
+#include <botan/libstate.h>
+#include <botan/block_cipher.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+
+using namespace Botan;
+
+namespace {
+
+bool block_test(const std::string& algo,
+ const std::string& key_hex,
+ const std::string& in_hex,
+ const std::string& out_hex)
+ {
+ const secure_vector<byte> key = hex_decode_locked(key_hex);
+ const secure_vector<byte> pt = hex_decode_locked(in_hex);
+ const secure_vector<byte> ct = hex_decode_locked(out_hex);
+
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ const auto providers = af.providers_of(algo);
+ size_t fails = 0;
+
+ for(auto provider: providers)
+ {
+ const BlockCipher* proto = af.prototype_block_cipher(algo, provider);
+
+ if(!proto)
+ {
+ std::cout << "Unable to get " << algo << " from " << provider << "\n";
+ ++fails;
+ continue;
+ }
+
+ std::unique_ptr<BlockCipher> cipher(proto->clone());
+ cipher->set_key(key);
+ secure_vector<byte> buf = pt;
+
+ cipher->encrypt(buf);
+
+ if(buf != ct)
+ {
+ std::cout << algo << " " << provider << " enc " << hex_encode(buf) << " != " << out_hex << "\n";
+ ++fails;
+ }
+
+ buf = ct;
+
+ cipher->decrypt(buf);
+
+ if(buf != pt)
+ {
+ std::cout << algo << " " << provider << " dec " << hex_encode(buf) << " != " << out_hex << "\n";
+ ++fails;
+ }
+ }
+
+ return (fails == 0);
+ }
+
+}
+
+size_t test_block()
+ {
+ std::ifstream vec(CHECKS_DIR "/block.vec");
+
+ return run_tests_bb(vec, "BlockCipher", "Out", true,
+ [](std::map<std::string, std::string> m) -> bool
+ {
+ return block_test(m["BlockCipher"], m["Key"], m["In"], m["Out"]);
+ });
+ }
diff --git a/src/tests/test_cryptobox.cpp b/src/tests/test_cryptobox.cpp
new file mode 100644
index 000000000..9a53da74c
--- /dev/null
+++ b/src/tests/test_cryptobox.cpp
@@ -0,0 +1,45 @@
+#include "tests.h"
+
+#include <botan/auto_rng.h>
+#include <iostream>
+
+#if defined(BOTAN_HAS_CRYPTO_BOX)
+ #include <botan/cryptobox.h>
+#endif
+
+using namespace Botan;
+
+size_t test_cryptobox()
+ {
+ size_t fails = 0;
+
+#if defined(BOTAN_HAS_CRYPTO_BOX)
+ AutoSeeded_RNG rng;
+
+ const byte msg[] = { 0xAA, 0xBB, 0xCC };
+ std::string ciphertext = CryptoBox::encrypt(msg, sizeof(msg),
+ "secret password",
+ rng);
+
+ try
+ {
+ std::string plaintext = CryptoBox::decrypt(ciphertext,
+ "secret password");
+
+ if(plaintext.size() != sizeof(msg) ||
+ !same_mem(reinterpret_cast<const byte*>(&plaintext[0]), msg, sizeof(msg)))
+ ++fails;
+
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Error during Cryptobox test " << e.what() << "\n";
+ ++fails;
+ }
+
+ test_report("Cryptobox", 1, fails);
+#endif
+
+ return fails;
+ }
+
diff --git a/src/tests/test_cvc.cpp b/src/tests/test_cvc.cpp
new file mode 100644
index 000000000..205b74ec8
--- /dev/null
+++ b/src/tests/test_cvc.cpp
@@ -0,0 +1,573 @@
+/*
+* CVC EAC1.1 tests
+*
+* (C) 2008 Falko Strenzke ([email protected])
+* 2008 Jack Lloyd
+*/
+
+#include "tests.h"
+#include <botan/build.h>
+
+#if defined(BOTAN_HAS_CARD_VERIFIABLE_CERTIFICATES)
+
+#include <iosfwd>
+#include <iostream>
+#include <iterator>
+#include <algorithm>
+#include <fstream>
+#include <vector>
+#include <memory>
+
+#include <botan/ecdsa.h>
+#include <botan/rsa.h>
+
+#include <botan/x509cert.h>
+#include <botan/x509self.h>
+#include <botan/oids.h>
+#include <botan/cvc_self.h>
+#include <botan/cvc_cert.h>
+#include <botan/cvc_ado.h>
+
+#define TEST_DATA_DIR CHECKS_DIR "/ecc_testdata"
+
+using namespace Botan;
+
+#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"; }
+
+namespace {
+
+// helper functions
+void helper_write_file(EAC_Signed_Object const& to_write, std::string const& file_path)
+ {
+ std::vector<byte> sv = to_write.BER_encode();
+ std::ofstream cert_file(file_path.c_str(), std::ios::binary);
+ cert_file.write((char*)&sv[0], sv.size());
+ cert_file.close();
+ }
+
+bool helper_files_equal(std::string const& file_path1, std::string const& file_path2)
+ {
+ std::ifstream cert_1_in(file_path1.c_str());
+ std::ifstream cert_2_in(file_path2.c_str());
+ std::vector<byte> sv1;
+ std::vector<byte> sv2;
+ if (!cert_1_in || !cert_2_in)
+ {
+ return false;
+ }
+ while (!cert_1_in.eof())
+ {
+ char now;
+ cert_1_in.read(&now, 1);
+ sv1.push_back(now);
+ }
+ while (!cert_2_in.eof())
+ {
+ char now;
+ cert_2_in.read(&now, 1);
+ sv2.push_back(now);
+ }
+ if (sv1.size() == 0)
+ {
+ return false;
+ }
+ return sv1 == sv2;
+ }
+
+void test_enc_gen_selfsigned(RandomNumberGenerator& rng)
+ {
+ EAC1_1_CVC_Options opts;
+ //opts.cpi = 0;
+ opts.chr = ASN1_Chr("my_opt_chr"); // not used
+ opts.car = ASN1_Car("my_opt_car");
+ opts.cex = ASN1_Cex("2010 08 13");
+ opts.ced = ASN1_Ced("2010 07 27");
+ opts.holder_auth_templ = 0xC1;
+ opts.hash_alg = "SHA-256";
+
+ // creating a non sense selfsigned cert w/o dom pars
+ 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);
+
+ std::vector<byte> der(cert.BER_encode());
+ std::ofstream cert_file;
+ cert_file.open(TEST_DATA_DIR "/my_cv_cert.ber", std::ios::binary);
+ //cert_file << der; // this is bad !!!
+ cert_file.write((char*)&der[0], der.size());
+ cert_file.close();
+
+ EAC1_1_CVC cert_in(TEST_DATA_DIR "/my_cv_cert.ber");
+ CHECK(cert == cert_in);
+ // encoding it again while it has no dp
+ std::vector<byte> der2(cert_in.BER_encode());
+ std::ofstream cert_file2(TEST_DATA_DIR "/my_cv_cert2.ber", std::ios::binary);
+ cert_file2.write((char*)&der2[0], der2.size());
+ cert_file2.close();
+ // read both and compare them
+ std::ifstream cert_1_in(TEST_DATA_DIR "/my_cv_cert.ber");
+ std::ifstream cert_2_in(TEST_DATA_DIR "/my_cv_cert2.ber");
+ std::vector<byte> sv1;
+ std::vector<byte> sv2;
+ if (!cert_1_in || !cert_2_in)
+ {
+ CHECK_MESSAGE(false, "could not read certificate files");
+ }
+ while (!cert_1_in.eof())
+ {
+ char now;
+
+ cert_1_in.read(&now, 1);
+ sv1.push_back(now);
+ }
+ while (!cert_2_in.eof())
+ {
+ char now;
+ cert_2_in.read(&now, 1);
+ sv2.push_back(now);
+ }
+ CHECK(sv1.size() > 10);
+ CHECK_MESSAGE(sv1 == sv2, "reencoded file of cert without domain parameters is different from original");
+
+ //cout << "reading cert again\n";
+ CHECK(cert_in.get_car().value() == "my_opt_car");
+ CHECK(cert_in.get_chr().value() == "my_opt_car");
+ CHECK(cert_in.get_ced().as_string() == "20100727");
+ CHECK(cert_in.get_ced().readable_string() == "2010/07/27 ");
+
+ bool ill_date_exc = false;
+ try
+ {
+ ASN1_Ced("1999 01 01");
+ }
+ catch (...)
+ {
+ ill_date_exc = true;
+ }
+ CHECK(ill_date_exc);
+
+ bool ill_date_exc2 = false;
+ try
+ {
+ ASN1_Ced("2100 01 01");
+ }
+ catch (...)
+ {
+ ill_date_exc2 = true;
+ }
+ CHECK(ill_date_exc2);
+ //cout << "readable = '" << cert_in.get_ced().readable_string() << "'\n";
+ std::unique_ptr<Public_Key> p_pk(cert_in.subject_public_key());
+ ECDSA_PublicKey* p_ecdsa_pk = dynamic_cast<ECDSA_PublicKey*>(p_pk.get());
+
+ // let´s see if encoding is truely implicitca, because this is what the key should have
+ // been set to when decoding (see above)(because it has no domain params):
+
+ CHECK(p_ecdsa_pk->domain_format() == EC_DOMPAR_ENC_IMPLICITCA);
+ bool exc = false;
+ try
+ {
+ std::cout << "order = " << p_ecdsa_pk->domain().get_order() << std::endl;
+ }
+ catch (Invalid_State)
+ {
+ exc = true;
+ }
+ CHECK(exc);
+ // set them and try again
+ //cert_in.set_domain_parameters(dom_pars);
+ std::unique_ptr<Public_Key> p_pk2(cert_in.subject_public_key());
+ ECDSA_PublicKey* p_ecdsa_pk2 = dynamic_cast<ECDSA_PublicKey*>(p_pk2.get());
+ //p_ecdsa_pk2->set_domain_parameters(dom_pars);
+ CHECK(p_ecdsa_pk2->domain().get_order() == dom_pars.get_order());
+ bool ver_ec = cert_in.check_signature(*p_pk2);
+ CHECK_MESSAGE(ver_ec, "could not positively verify correct selfsigned cvc certificate");
+ }
+
+void test_enc_gen_req(RandomNumberGenerator& rng)
+ {
+ EAC1_1_CVC_Options opts;
+
+ //opts.cpi = 0;
+ opts.chr = ASN1_Chr("my_opt_chr");
+ opts.hash_alg = "SHA-160";
+
+ // creating a non sense selfsigned cert w/o dom pars
+ 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);
+ std::vector<byte> der(req.BER_encode());
+ std::ofstream req_file(TEST_DATA_DIR "/my_cv_req.ber", std::ios::binary);
+ req_file.write((char*)&der[0], der.size());
+ req_file.close();
+
+ // read and check signature...
+ EAC1_1_Req req_in(TEST_DATA_DIR "/my_cv_req.ber");
+ //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());
+ //p_ecdsa_pk->set_domain_parameters(dom_pars);
+ CHECK(p_ecdsa_pk->domain().get_order() == dom_pars.get_order());
+ bool ver_ec = req_in.check_signature(*p_pk);
+ CHECK_MESSAGE(ver_ec, "could not positively verify correct selfsigned (created by myself) cvc request");
+ }
+
+void test_cvc_req_ext(RandomNumberGenerator&)
+ {
+ EAC1_1_Req req_in(TEST_DATA_DIR "/DE1_flen_chars_cvcRequest_ECDSA.der");
+ 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());
+ //p_ecdsa_pk->set_domain_parameters(dom_pars);
+ CHECK(p_ecdsa_pk->domain().get_order() == dom_pars.get_order());
+ bool ver_ec = req_in.check_signature(*p_pk);
+ CHECK_MESSAGE(ver_ec, "could not positively verify correct selfsigned (external testdata) cvc request");
+ }
+
+void test_cvc_ado_ext(RandomNumberGenerator&)
+ {
+ EAC1_1_ADO req_in(TEST_DATA_DIR "/ado.cvcreq");
+ 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);
+ }
+
+void test_cvc_ado_creation(RandomNumberGenerator& rng)
+ {
+ EAC1_1_CVC_Options opts;
+ //opts.cpi = 0;
+ opts.chr = ASN1_Chr("my_opt_chr");
+ opts.hash_alg = "SHA-256";
+
+ // creating a non sense selfsigned cert w/o dom pars
+ 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);
+ //EAC1_1_Req req = CVC_EAC::create_cvc_req(req_key, opts);
+ EAC1_1_Req req = CVC_EAC::create_cvc_req(req_key, opts.chr, opts.hash_alg, rng);
+ std::vector<byte> der(req.BER_encode());
+ std::ofstream req_file(TEST_DATA_DIR "/my_cv_req.ber", std::ios::binary);
+ req_file.write((char*)&der[0], der.size());
+ req_file.close();
+
+ // create an ado with that req
+ ECDSA_PrivateKey ado_key(rng, dom_pars);
+ EAC1_1_CVC_Options ado_opts;
+ ado_opts.car = ASN1_Car("my_ado_car");
+ ado_opts.hash_alg = "SHA-256"; // must be equal to req´s hash alg, because ado takes his sig_algo from it´s request
+
+ //EAC1_1_ADO ado = CVC_EAC::create_ado_req(ado_key, req, ado_opts);
+ EAC1_1_ADO ado = CVC_EAC::create_ado_req(ado_key, req, ado_opts.car, rng);
+ CHECK_MESSAGE(ado.check_signature(ado_key), "failure of ado verification after creation");
+
+ std::ofstream ado_file(TEST_DATA_DIR "/ado", std::ios::binary);
+ std::vector<byte> ado_der(ado.BER_encode());
+ ado_file.write((char*)&ado_der[0], ado_der.size());
+ ado_file.close();
+ // read it again and check the signature
+ EAC1_1_ADO ado2(TEST_DATA_DIR "/ado");
+ CHECK(ado == ado2);
+ //ECDSA_PublicKey* p_ado_pk = dynamic_cast<ECDSA_PublicKey*>(&ado_key);
+ //bool ver = ado2.check_signature(*p_ado_pk);
+ bool ver = ado2.check_signature(ado_key);
+ CHECK_MESSAGE(ver, "failure of ado verification after reloading");
+ }
+
+void test_cvc_ado_comparison(RandomNumberGenerator& rng)
+ {
+ EAC1_1_CVC_Options opts;
+ //opts.cpi = 0;
+ opts.chr = ASN1_Chr("my_opt_chr");
+ opts.hash_alg = "SHA-224";
+
+ // creating a non sense selfsigned cert w/o dom pars
+ 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);
+ EAC1_1_Req req = CVC_EAC::create_cvc_req(req_key, opts.chr, opts.hash_alg, rng);
+
+
+ // create an ado with that req
+ ECDSA_PrivateKey ado_key(rng, dom_pars);
+ EAC1_1_CVC_Options ado_opts;
+ ado_opts.car = ASN1_Car("my_ado_car1");
+ ado_opts.hash_alg = "SHA-224"; // must be equal to req's hash alg, because ado takes his sig_algo from it's request
+ //EAC1_1_ADO ado = CVC_EAC::create_ado_req(ado_key, req, ado_opts);
+ EAC1_1_ADO ado = CVC_EAC::create_ado_req(ado_key, req, ado_opts.car, rng);
+ CHECK_MESSAGE(ado.check_signature(ado_key), "failure of ado verification after creation");
+ // make a second one for comparison
+ EAC1_1_CVC_Options opts2;
+ //opts2.cpi = 0;
+ opts2.chr = ASN1_Chr("my_opt_chr");
+ opts2.hash_alg = "SHA-160"; // this is the only difference
+ ECDSA_PrivateKey req_key2(rng, dom_pars);
+ req_key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA);
+ //EAC1_1_Req req2 = CVC_EAC::create_cvc_req(req_key2, opts2, rng);
+ EAC1_1_Req req2 = CVC_EAC::create_cvc_req(req_key2, opts2.chr, opts2.hash_alg, rng);
+ ECDSA_PrivateKey ado_key2(rng, dom_pars);
+ EAC1_1_CVC_Options ado_opts2;
+ ado_opts2.car = ASN1_Car("my_ado_car1");
+ ado_opts2.hash_alg = "SHA-160"; // must be equal to req's hash alg, because ado takes his sig_algo from it's request
+
+ EAC1_1_ADO ado2 = CVC_EAC::create_ado_req(ado_key2, req2, ado_opts2.car, rng);
+ CHECK_MESSAGE(ado2.check_signature(ado_key2), "failure of ado verification after creation");
+
+ CHECK_MESSAGE(ado != ado2, "ado's found to be equal where they are not");
+ // std::ofstream ado_file(TEST_DATA_DIR "/ado");
+ // std::vector<byte> ado_der(ado.BER_encode());
+ // ado_file.write((char*)&ado_der[0], ado_der.size());
+ // ado_file.close();
+ // read it again and check the signature
+
+ // EAC1_1_ADO ado2(TEST_DATA_DIR "/ado");
+ // ECDSA_PublicKey* p_ado_pk = dynamic_cast<ECDSA_PublicKey*>(&ado_key);
+ // //bool ver = ado2.check_signature(*p_ado_pk);
+ // bool ver = ado2.check_signature(ado_key);
+ // CHECK_MESSAGE(ver, "failure of ado verification after reloading");
+ }
+
+void test_eac_time(RandomNumberGenerator&)
+ {
+ EAC_Time time(std::chrono::system_clock::now());
+ // std::cout << "time as std::string = " << time.as_string() << std::endl;
+ EAC_Time sooner("", ASN1_Tag(99));
+ //X509_Time sooner("", ASN1_Tag(99));
+ sooner.set_to("2007 12 12");
+ // std::cout << "sooner as std::string = " << sooner.as_string() << std::endl;
+ EAC_Time later("2007 12 13");
+ //X509_Time later("2007 12 13");
+ // std::cout << "later as std::string = " << later.as_string() << std::endl;
+ CHECK(sooner <= later);
+ CHECK(sooner == sooner);
+
+ ASN1_Cex my_cex("2007 08 01");
+ my_cex.add_months(12);
+ CHECK(my_cex.get_year() == 2008);
+ CHECK_MESSAGE(my_cex.get_month() == 8, "shoult be 8, was " << my_cex.get_month());
+
+ my_cex.add_months(4);
+ CHECK(my_cex.get_year() == 2008);
+ CHECK(my_cex.get_month() == 12);
+
+ my_cex.add_months(4);
+ CHECK(my_cex.get_year() == 2009);
+ CHECK(my_cex.get_month() == 4);
+
+ my_cex.add_months(41);
+ CHECK(my_cex.get_year() == 2012);
+ CHECK(my_cex.get_month() == 9);
+
+
+
+ }
+
+void test_ver_cvca(RandomNumberGenerator&)
+ {
+ EAC1_1_CVC req_in(TEST_DATA_DIR "/cvca01.cv.crt");
+
+ bool exc = false;
+
+ std::unique_ptr<Public_Key> p_pk2(req_in.subject_public_key());
+ ECDSA_PublicKey* p_ecdsa_pk2 = dynamic_cast<ECDSA_PublicKey*>(p_pk2.get());
+ bool ver_ec = req_in.check_signature(*p_pk2);
+ CHECK_MESSAGE(ver_ec, "could not positively verify correct selfsigned cvca certificate");
+
+ try
+ {
+ p_ecdsa_pk2->domain().get_order();
+ }
+ catch (Invalid_State)
+ {
+ exc = true;
+ }
+ CHECK(!exc);
+ }
+
+void test_copy_and_assignment(RandomNumberGenerator&)
+ {
+ EAC1_1_CVC cert_in(TEST_DATA_DIR "/cvca01.cv.crt");
+ EAC1_1_CVC cert_cp(cert_in);
+ EAC1_1_CVC cert_ass = cert_in;
+ CHECK(cert_in == cert_cp);
+ CHECK(cert_in == cert_ass);
+
+ EAC1_1_ADO ado_in(TEST_DATA_DIR "/ado.cvcreq");
+ //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_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);
+ CHECK(req_in == req_ass);
+ }
+
+void test_eac_str_illegal_values(RandomNumberGenerator&)
+ {
+ bool exc = false;
+ try
+ {
+ EAC1_1_CVC(TEST_DATA_DIR "/cvca_illegal_chars.cv.crt");
+
+ }
+ catch (Decoding_Error)
+ {
+ exc = true;
+ }
+ CHECK(exc);
+
+ bool exc2 = false;
+ try
+ {
+ EAC1_1_CVC(TEST_DATA_DIR "/cvca_illegal_chars2.cv.crt");
+
+ }
+ catch (Decoding_Error)
+ {
+ exc2 = true;
+ }
+ CHECK(exc2);
+ }
+
+void test_tmp_eac_str_enc(RandomNumberGenerator&)
+ {
+ bool exc = false;
+ try
+ {
+ ASN1_Car("abc!+-µ\n");
+ }
+ catch (Invalid_Argument)
+ {
+ exc = true;
+ }
+ CHECK(exc);
+ // std::string val = car.iso_8859();
+ // std::cout << "car 8859 = " << val << std::endl;
+ // std::cout << hex <<(unsigned char)val[1] << std::endl;
+
+
+ }
+
+void test_cvc_chain(RandomNumberGenerator& rng)
+ {
+ 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");
+ EAC1_1_CVC cvca_cert = DE_EAC::create_cvca(cvca_privk, hash, car, true, true, 12, rng);
+ std::ofstream cvca_file(TEST_DATA_DIR "/cvc_chain_cvca.cer", std::ios::binary);
+ std::vector<byte> cvca_sv = cvca_cert.BER_encode();
+ cvca_file.write((char*)&cvca_sv[0], cvca_sv.size());
+ cvca_file.close();
+
+ ECDSA_PrivateKey cvca_privk2(rng, dom_pars);
+ ASN1_Car car2("DECVCA00002");
+ EAC1_1_CVC cvca_cert2 = DE_EAC::create_cvca(cvca_privk2, hash, car2, true, true, 12, rng);
+ EAC1_1_CVC link12 = DE_EAC::link_cvca(cvca_cert, cvca_privk, cvca_cert2, rng);
+ std::vector<byte> link12_sv = link12.BER_encode();
+ std::ofstream link12_file(TEST_DATA_DIR "/cvc_chain_link12.cer", std::ios::binary);
+ link12_file.write((char*)&link12_sv[0], link12_sv.size());
+ link12_file.close();
+
+ // verify the link
+ CHECK(link12.check_signature(cvca_privk));
+ EAC1_1_CVC link12_reloaded(TEST_DATA_DIR "/cvc_chain_link12.cer");
+ EAC1_1_CVC cvca1_reloaded(TEST_DATA_DIR "/cvc_chain_cvca.cer");
+ std::unique_ptr<Public_Key> cvca1_rel_pk(cvca1_reloaded.subject_public_key());
+ CHECK(link12_reloaded.check_signature(*cvca1_rel_pk));
+
+ // create first round dvca-req
+ ECDSA_PrivateKey dvca_priv_key(rng, dom_pars);
+ EAC1_1_Req dvca_req = DE_EAC::create_cvc_req(dvca_priv_key, ASN1_Chr("DEDVCAEPASS"), hash, rng);
+ std::ofstream dvca_file(TEST_DATA_DIR "/cvc_chain_dvca_req.cer", std::ios::binary);
+ std::vector<byte> dvca_sv = dvca_req.BER_encode();
+ dvca_file.write((char*)&dvca_sv[0], dvca_sv.size());
+ dvca_file.close();
+
+ // sign the dvca_request
+ EAC1_1_CVC dvca_cert1 = DE_EAC::sign_request(cvca_cert, cvca_privk, dvca_req, 1, 5, true, 3, 1, rng);
+ CHECK(dvca_cert1.get_car().iso_8859() == "DECVCA00001");
+ CHECK(dvca_cert1.get_chr().iso_8859() == "DEDVCAEPASS00001");
+ helper_write_file(dvca_cert1, TEST_DATA_DIR "/cvc_chain_dvca_cert1.cer");
+
+ // make a second round dvca ado request
+ ECDSA_PrivateKey dvca_priv_key2(rng, dom_pars);
+ EAC1_1_Req dvca_req2 = DE_EAC::create_cvc_req(dvca_priv_key2, ASN1_Chr("DEDVCAEPASS"), hash, rng);
+ std::ofstream dvca_file2(TEST_DATA_DIR "/cvc_chain_dvca_req2.cer", std::ios::binary);
+ std::vector<byte> dvca_sv2 = dvca_req2.BER_encode();
+ dvca_file2.write((char*)&dvca_sv2[0], dvca_sv2.size());
+ dvca_file2.close();
+ EAC1_1_ADO dvca_ado2 = CVC_EAC::create_ado_req(dvca_priv_key, dvca_req2,
+ ASN1_Car(dvca_cert1.get_chr().iso_8859()), rng);
+ helper_write_file(dvca_ado2, TEST_DATA_DIR "/cvc_chain_dvca_ado2.cer");
+
+ // verify the ado and sign the request too
+
+ std::unique_ptr<Public_Key> ap_pk(dvca_cert1.subject_public_key());
+ ECDSA_PublicKey* cert_pk = dynamic_cast<ECDSA_PublicKey*>(ap_pk.get());
+
+ //cert_pk->set_domain_parameters(dom_pars);
+ //std::cout << "dvca_cert.public_point.size() = " << ec::EC2OSP(cert_pk->get_public_point(), ec::PointGFp::COMPRESSED).size() << std::endl;
+ EAC1_1_CVC dvca_cert1_reread(TEST_DATA_DIR "/cvc_chain_cvca.cer");
+ CHECK(dvca_ado2.check_signature(*cert_pk));
+
+ CHECK(dvca_ado2.check_signature(dvca_priv_key)); // must also work
+
+ EAC1_1_Req dvca_req2b = dvca_ado2.get_request();
+ helper_write_file(dvca_req2b, TEST_DATA_DIR "/cvc_chain_dvca_req2b.cer");
+ CHECK(helper_files_equal(TEST_DATA_DIR "/cvc_chain_dvca_req2b.cer", TEST_DATA_DIR "/cvc_chain_dvca_req2.cer"));
+ EAC1_1_CVC dvca_cert2 = DE_EAC::sign_request(cvca_cert, cvca_privk, dvca_req2b, 2, 5, true, 3, 1, rng);
+ CHECK(dvca_cert2.get_car().iso_8859() == "DECVCA00001");
+ CHECK_MESSAGE(dvca_cert2.get_chr().iso_8859() == "DEDVCAEPASS00002",
+ "chr = " << dvca_cert2.get_chr().iso_8859());
+
+ // make a first round IS request
+ ECDSA_PrivateKey is_priv_key(rng, dom_pars);
+ EAC1_1_Req is_req = DE_EAC::create_cvc_req(is_priv_key, ASN1_Chr("DEIS"), hash, rng);
+ helper_write_file(is_req, TEST_DATA_DIR "/cvc_chain_is_req.cer");
+
+ // sign the IS request
+ //dvca_cert1.set_domain_parameters(dom_pars);
+ EAC1_1_CVC is_cert1 = DE_EAC::sign_request(dvca_cert1, dvca_priv_key, is_req, 1, 5, true, 3, 1, rng);
+ CHECK_MESSAGE(is_cert1.get_car().iso_8859() == "DEDVCAEPASS00001", "car = " << is_cert1.get_car().iso_8859());
+ CHECK(is_cert1.get_chr().iso_8859() == "DEIS00001");
+ helper_write_file(is_cert1, TEST_DATA_DIR "/cvc_chain_is_cert.cer");
+
+ // verify the signature of the certificate
+ CHECK(is_cert1.check_signature(dvca_priv_key));
+ }
+
+}
+
+size_t test_cvc()
+ {
+ AutoSeeded_RNG rng;
+
+ test_enc_gen_selfsigned(rng);
+ test_enc_gen_req(rng);
+ test_cvc_req_ext(rng);
+ test_cvc_ado_ext(rng);
+ test_cvc_ado_creation(rng);
+ test_cvc_ado_comparison(rng);
+ test_eac_time(rng);
+ test_ver_cvca(rng);
+ test_copy_and_assignment(rng);
+ test_eac_str_illegal_values(rng);
+ test_tmp_eac_str_enc(rng);
+ test_cvc_chain(rng);
+
+ return 0;
+ }
+#else
+size_t test_cvc() { return 0; }
+#endif
diff --git a/src/tests/test_eax.cpp b/src/tests/test_eax.cpp
new file mode 100644
index 000000000..45b583139
--- /dev/null
+++ b/src/tests/test_eax.cpp
@@ -0,0 +1,229 @@
+/*
+* (C) 2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include "tests.h"
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <boost/regex.hpp>
+
+#include <botan/eax.h>
+#include <botan/hex.h>
+#include <botan/lookup.h>
+
+using namespace Botan;
+
+namespace {
+
+unsigned from_string(const std::string& s)
+ {
+ std::istringstream stream(s);
+ unsigned n;
+ stream >> n;
+ return n;
+ }
+
+std::string seq(unsigned n)
+ {
+ std::string s;
+
+ for(unsigned i = 0; i != n; ++i)
+ {
+ unsigned char b = (i & 0xFF);
+
+ const char bin2hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ s += bin2hex[(b >> 4)];
+ s += bin2hex[(b & 0x0f)];
+ }
+
+ return s;
+ }
+
+size_t eax_test(const std::string& algo,
+ const std::string& key_str,
+ const std::string& nonce_str,
+ const std::string& header_str,
+ const std::string& tag_str,
+ const std::string& plaintext_str,
+ const std::string& ciphertext)
+ {
+ size_t fail = 0;
+
+ try
+ {
+ EAX_Encryption enc(get_block_cipher(algo));
+ EAX_Decryption dec(get_block_cipher(algo));
+
+ enc.set_key(hex_decode(key_str));
+ dec.set_key(hex_decode(key_str));
+
+ enc.set_associated_data_vec(hex_decode(header_str));
+ dec.set_associated_data_vec(hex_decode(header_str));
+
+ secure_vector<byte> text = hex_decode_locked(plaintext_str);
+ enc.start_vec(hex_decode(nonce_str));
+ enc.finish(text);
+
+ const std::string produced = hex_encode(text);
+
+ if(produced != ciphertext + tag_str)
+ {
+ std::cout << "EAX " << algo << " " << produced << " != expected " << ciphertext << tag_str << "\n";
+ ++fail;
+ }
+
+ text.clear();
+ text = hex_decode_locked(ciphertext);
+ text += hex_decode_locked(tag_str);
+
+ dec.start_vec(hex_decode(nonce_str));
+ dec.finish(text);
+
+ const std::string decrypted = hex_encode(text);
+
+ if(decrypted != plaintext_str)
+ {
+ std::cout << "EAX " << algo << " " << decrypted << " != expected " << plaintext_str << "\n";
+ ++fail;
+ }
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Exception during EAX test " << e.what() << "\n";
+ ++fail;
+ }
+
+ return fail;
+ }
+
+std::pair<std::string, int> translate_algo(const std::string& in)
+ {
+ if(in == "aes (16 byte key)")
+ return std::make_pair("AES-128", 16);
+
+ if(in == "blowfish (8 byte key)")
+ return std::make_pair("Blowfish", 8);
+
+ if(in == "rc2 (8 byte key)")
+ return std::make_pair("RC2", 8);
+
+ if(in == "rc5 (8 byte key)")
+ return std::make_pair("RC5", 8);
+
+ if(in == "rc6 (16 byte key)")
+ return std::make_pair("RC6", 16);
+
+ if(in == "safer-sk128 (16 byte key)")
+ return std::make_pair("SAFER-SK(10)", 16);
+
+ if(in == "twofish (16 byte key)")
+ return std::make_pair("Twofish", 16);
+
+ if(in == "des (8 byte key)")
+ return std::make_pair("DES", 8);
+
+ if(in == "3des (24 byte key)")
+ return std::make_pair("TripleDES", 24);
+
+ // These 3 are disabled due to differences in base algorithm.
+
+#if 0
+ // XTEA: LTC uses little endian, Botan (and Crypto++) use big-endian
+ // I swapped to LE in XTEA and the vectors did match
+ if(in == "xtea (16 byte key)")
+ return std::make_pair("XTEA", 16);
+
+ // Skipjack: LTC uses big-endian, Botan (and Crypto++) use
+ // little-endian I am not sure if that was the full difference
+ // though, was unable to replicate LTC's EAX vectors with Skipjack
+ if(in == "skipjack (10 byte key)")
+ return std::make_pair("Skipjack", 10);
+
+ // Noekeon: uses direct keying instead of indirect
+ if(in == "noekeon (16 byte key)")
+ return std::make_pair("Noekeon", 16);
+
+#endif
+
+ return std::make_pair("", 0);
+ }
+
+std::string rep(const std::string& s_in, unsigned n)
+ {
+ std::string s_out;
+
+ for(unsigned i = 0; i != n; ++i)
+ s_out += s_in[i % s_in.size()];
+
+ return s_out;
+ }
+
+size_t eax_tests(std::istream& in)
+ {
+ std::string algo;
+ std::string key;
+
+ size_t fails = 0;
+ size_t tests = 0;
+
+ while(in.good())
+ {
+ std::string line;
+
+ std::getline(in, line);
+
+ if(line == "")
+ continue;
+
+ if(line.size() > 5 && line.substr(0, 4) == "EAX-")
+ {
+ std::pair<std::string, int> name_and_keylen =
+ translate_algo(line.substr(4));
+
+ algo = name_and_keylen.first;
+ key = seq(name_and_keylen.second);
+ }
+ else if(algo != "")
+ {
+ boost::regex vec_regex("^([ 0-9]{3}): (.*), (.*)$");
+
+ boost::smatch what;
+
+ if(boost::regex_match(line, what, vec_regex, boost::match_extra))
+ {
+ unsigned n = from_string(what[1]);
+ std::string ciphertext = what[2];
+ std::string tag = what[3];
+
+ std::string plaintext = seq(n);
+ std::string header = seq(n);
+ std::string nonce = seq(n);
+
+ tests += 1;
+
+ fails += eax_test(algo, key, nonce, header, tag,
+ plaintext, ciphertext);
+
+ key = rep(tag, key.size()); // repeat as needed
+ }
+ }
+ }
+
+ test_report("EAX", tests, fails);
+
+ return fails;
+ }
+
+}
+
+size_t test_eax()
+ {
+ // Uses a set of tests created for libtomcrypt
+ std::ifstream in(CHECKS_DIR "/eax.vec");
+ return eax_tests(in);
+ }
diff --git a/src/tests/test_ecc.cpp b/src/tests/test_ecc.cpp
new file mode 100644
index 000000000..929e44528
--- /dev/null
+++ b/src/tests/test_ecc.cpp
@@ -0,0 +1,842 @@
+/*
+* (C) 2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include "tests.h"
+
+#include <botan/hex.h>
+#include <botan/auto_rng.h>
+#include <botan/bigint.h>
+#include <botan/numthry.h>
+#include <botan/curve_gfp.h>
+#include <botan/point_gfp.h>
+#include <botan/ec_group.h>
+#include <botan/reducer.h>
+#include <botan/oids.h>
+#include <iostream>
+#include <memory>
+
+using namespace Botan;
+
+#define CHECK_MESSAGE(expr, print) try { if(!(expr)) { ++fails; std::cout << print << "\n"; }} catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; }
+#define CHECK(expr) try { if(!(expr)) { ++fails; std::cout << #expr << "\n"; } } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; }
+
+namespace {
+
+std::ostream& operator<<(std::ostream& out, const PointGFp& point)
+ {
+ out << "(" << point.get_affine_x() << " " << point.get_affine_y() << ")";
+ return out;
+ }
+
+PointGFp create_random_point(RandomNumberGenerator& rng,
+ const CurveGFp& curve)
+ {
+ const BigInt& p = curve.get_p();
+
+ Modular_Reducer mod_p(p);
+
+ while(true)
+ {
+ BigInt x(rng, p.bits());
+
+ BigInt x3 = mod_p.multiply(x, mod_p.square(x));
+
+ BigInt ax = mod_p.multiply(curve.get_a(), x);
+
+ BigInt bx3 = mod_p.multiply(curve.get_b(), x3);
+
+ BigInt y = mod_p.reduce(ax + bx3);
+
+ if(ressol(y, p) > 0)
+ return PointGFp(curve, x, y);
+ }
+ }
+
+size_t test_point_turn_on_sp_red_mul()
+ {
+ size_t fails = 0;
+
+ // setting up expected values
+ BigInt exp_Qx(std::string("466448783855397898016055842232266600516272889280"));
+ BigInt exp_Qy(std::string("1110706324081757720403272427311003102474457754220"));
+ BigInt exp_Qz(1);
+
+ // performing calculation to test
+ std::string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
+ std::string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
+ std::string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_p_secp = hex_decode(p_secp);
+ std::vector<byte> sv_a_secp = hex_decode(a_secp);
+ std::vector<byte> sv_b_secp = hex_decode(b_secp);
+ std::vector<byte> sv_G_secp_comp = hex_decode(G_secp_comp);
+ BigInt bi_p_secp = BigInt::decode(&sv_p_secp[0], sv_p_secp.size());
+ BigInt bi_a_secp = BigInt::decode(&sv_a_secp[0], sv_a_secp.size());
+ BigInt bi_b_secp = BigInt::decode(&sv_b_secp[0], sv_b_secp.size());
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+ PointGFp p_G = OS2ECP(sv_G_secp_comp, secp160r1);
+
+ BigInt d("459183204582304");
+
+ PointGFp r1 = d * p_G;
+ CHECK(r1.get_affine_x() != 0);
+
+ PointGFp p_G2(p_G);
+
+ PointGFp r2 = d * p_G2;
+ CHECK_MESSAGE(r1 == r2, "error with point mul after extra turn on sp red mul");
+ CHECK(r1.get_affine_x() != 0);
+
+ PointGFp p_r1 = r1;
+ PointGFp p_r2 = r2;
+
+ p_r1 *= 2;
+ p_r2 *= 2;
+ CHECK_MESSAGE(p_r1.get_affine_x() == p_r2.get_affine_x(), "error with mult2 after extra turn on sp red mul");
+ CHECK(p_r1.get_affine_x() != 0);
+ CHECK(p_r2.get_affine_x() != 0);
+ r1 *= 2;
+
+ r2 *= 2;
+
+ CHECK_MESSAGE(r1 == r2, "error with mult2 after extra turn on sp red mul");
+ CHECK_MESSAGE(r1.get_affine_x() == r2.get_affine_x(), "error with mult2 after extra turn on sp red mul");
+ CHECK(r1.get_affine_x() != 0);
+ r1 += p_G;
+ r2 += p_G2;
+
+ CHECK_MESSAGE(r1 == r2, "error with op+= after extra turn on sp red mul");
+
+ r1 += p_G;
+ r2 += p_G2;
+
+ CHECK_MESSAGE(r1 == r2, "error with op+= after extra turn on sp red mul for both operands");
+ r1 += p_G;
+ r2 += p_G2;
+
+ CHECK_MESSAGE(r1 == r2, "error with op+= after extra turn on sp red mul for both operands");
+ return fails;
+ }
+
+size_t test_coordinates()
+ {
+ size_t fails = 0;
+
+ BigInt exp_affine_x(std::string("16984103820118642236896513183038186009872590470"));
+ BigInt exp_affine_y(std::string("1373093393927139016463695321221277758035357890939"));
+
+ // precalculation
+ std::string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
+ std::string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
+ std::string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+ CurveGFp secp160r1 (bi_p_secp, bi_a_secp, bi_b_secp);
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, secp160r1 );
+ PointGFp p0 = p_G;
+ PointGFp p1 = p_G * 2;
+ PointGFp point_exp(secp160r1, exp_affine_x, exp_affine_y);
+ if(!point_exp.on_the_curve())
+ throw Internal_Error("Point not on the curve");
+
+ CHECK_MESSAGE( p1.get_affine_x() == exp_affine_x, " p1_x = " << p1.get_affine_x() << "\n" << "exp_x = " << exp_affine_x << "\n");
+ CHECK_MESSAGE( p1.get_affine_y() == exp_affine_y, " p1_y = " << p1.get_affine_y() << "\n" << "exp_y = " << exp_affine_y << "\n");
+ return fails;
+ }
+
+
+/**
+Test point multiplication according to
+--------
+SEC 2: Test Vectors for SEC 1
+Certicom Research
+Working Draft
+September, 1999
+Version 0.3;
+Section 2.1.2
+--------
+*/
+
+size_t test_point_transformation ()
+ {
+ size_t fails = 0;
+
+ // get a vailid point
+ EC_Group dom_pars(OID("1.3.132.0.8"));
+ PointGFp p = dom_pars.get_base_point();
+
+ // get a copy
+ PointGFp q = p;
+
+ CHECK_MESSAGE( p.get_affine_x() == q.get_affine_x(), "affine_x changed during copy");
+ CHECK_MESSAGE( p.get_affine_y() == q.get_affine_y(), "affine_y changed during copy");
+ return fails;
+ }
+
+size_t test_point_mult ()
+ {
+ size_t fails = 0;
+
+ EC_Group secp160r1(OIDS::lookup("secp160r1"));
+
+ const CurveGFp& curve = secp160r1.get_curve();
+
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_G_secp_comp = hex_decode(G_secp_comp);
+ PointGFp p_G = OS2ECP(sv_G_secp_comp, curve);
+
+ BigInt d_U("0xaa374ffc3ce144e6b073307972cb6d57b2a4e982");
+ PointGFp Q_U = d_U * p_G;
+
+ CHECK(Q_U.get_affine_x() == BigInt("466448783855397898016055842232266600516272889280"));
+ CHECK(Q_U.get_affine_y() == BigInt("1110706324081757720403272427311003102474457754220"));
+ return fails;
+ }
+
+size_t test_point_negative()
+ {
+ size_t fails = 0;
+
+ // performing calculation to test
+ std::string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
+ std::string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
+ std::string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, secp160r1 );
+
+ PointGFp p1 = p_G *= 2;
+
+ CHECK(p1.get_affine_x() == BigInt("16984103820118642236896513183038186009872590470"));
+ CHECK(p1.get_affine_y() == BigInt("1373093393927139016463695321221277758035357890939"));
+
+ PointGFp p1_neg = p1.negate();
+
+ CHECK(p1_neg.get_affine_x() == BigInt("16984103820118642236896513183038186009872590470"));
+ CHECK(p1_neg.get_affine_y() == BigInt("88408243403763901739989511495005261618427168388"));
+ return fails;
+ }
+
+size_t test_zeropoint()
+ {
+ size_t fails = 0;
+
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+ BigInt bi_p_secp("0xffffffffffffffffffffffffffffffff7fffffff");
+ BigInt bi_a_secp("0xffffffffffffffffffffffffffffffff7ffffffc");
+ BigInt bi_b_secp("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45");
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+
+ PointGFp p1(secp160r1,
+ BigInt("16984103820118642236896513183038186009872590470"),
+ BigInt("1373093393927139016463695321221277758035357890939"));
+
+ if(!p1.on_the_curve())
+ throw Internal_Error("Point not on the curve");
+ p1 -= p1;
+
+ CHECK_MESSAGE( p1.is_zero(), "p - q with q = p is not zero!");
+ return fails;
+ }
+
+size_t test_zeropoint_enc_dec()
+ {
+ size_t fails = 0;
+
+ BigInt bi_p_secp("0xffffffffffffffffffffffffffffffff7fffffff");
+ BigInt bi_a_secp("0xffffffffffffffffffffffffffffffff7ffffffc");
+ BigInt bi_b_secp("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45");
+ CurveGFp curve(bi_p_secp, bi_a_secp, bi_b_secp);
+
+ PointGFp p(curve);
+ CHECK_MESSAGE( p.is_zero(), "by constructor created zeropoint is no zeropoint!");
+
+
+ std::vector<byte> sv_p = unlock(EC2OSP(p, PointGFp::UNCOMPRESSED));
+ PointGFp p_encdec = OS2ECP(sv_p, curve);
+ CHECK_MESSAGE( p == p_encdec, "encoded-decoded (uncompressed) point is not equal the original!");
+
+ sv_p = unlock(EC2OSP(p, PointGFp::UNCOMPRESSED));
+ p_encdec = OS2ECP(sv_p, curve);
+ CHECK_MESSAGE( p == p_encdec, "encoded-decoded (compressed) point is not equal the original!");
+
+ sv_p = unlock(EC2OSP(p, PointGFp::HYBRID));
+ p_encdec = OS2ECP(sv_p, curve);
+ CHECK_MESSAGE( p == p_encdec, "encoded-decoded (hybrid) point is not equal the original!");
+ return fails;
+ }
+
+size_t test_calc_with_zeropoint()
+ {
+ size_t fails = 0;
+
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+ BigInt bi_p_secp("0xffffffffffffffffffffffffffffffff7fffffff");
+ BigInt bi_a_secp("0xffffffffffffffffffffffffffffffff7ffffffc");
+ BigInt bi_b_secp("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45");
+ CurveGFp curve(bi_p_secp, bi_a_secp, bi_b_secp);
+
+ PointGFp p(curve,
+ BigInt("16984103820118642236896513183038186009872590470"),
+ BigInt("1373093393927139016463695321221277758035357890939"));
+
+ if(!p.on_the_curve())
+ throw Internal_Error("Point not on the curve");
+ CHECK_MESSAGE( !p.is_zero(), "created is zeropoint, shouldn't be!");
+
+ PointGFp zero(curve);
+ CHECK_MESSAGE( zero.is_zero(), "by constructor created zeropoint is no zeropoint!");
+
+ PointGFp res = p + zero;
+ CHECK_MESSAGE( res == p, "point + zeropoint is not equal the point");
+
+ res = p - zero;
+ CHECK_MESSAGE( res == p, "point - zeropoint is not equal the point");
+
+ res = zero * 32432243;
+ CHECK_MESSAGE( res.is_zero(), "zeropoint * skalar is not a zero-point!");
+ return fails;
+ }
+
+size_t test_add_point()
+ {
+ size_t fails = 0;
+
+ // precalculation
+ std::string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
+ std::string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
+ std::string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, secp160r1 );
+
+ PointGFp p0 = p_G;
+ PointGFp p1 = p_G *= 2;
+
+ p1 += p0;
+
+ PointGFp expected(secp160r1,
+ BigInt("704859595002530890444080436569091156047721708633"),
+ BigInt("1147993098458695153857594941635310323215433166682"));
+
+ CHECK(p1 == expected);
+ return fails;
+ }
+
+size_t test_sub_point()
+ {
+ size_t fails = 0;
+
+ //Setting up expected values
+ BigInt exp_sub_x(std::string("112913490230515010376958384252467223283065196552"));
+ BigInt exp_sub_y(std::string("143464803917389475471159193867377888720776527730"));
+ BigInt exp_sub_z(std::string("562006223742588575209908669014372619804457947208"));
+
+ // precalculation
+ std::string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
+ std::string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
+ std::string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, secp160r1 );
+
+ PointGFp p0 = p_G;
+ PointGFp p1 = p_G *= 2;
+
+ p1 -= p0;
+
+ PointGFp expected(secp160r1,
+ BigInt("425826231723888350446541592701409065913635568770"),
+ BigInt("203520114162904107873991457957346892027982641970"));
+
+ CHECK(p1 == expected);
+ return fails;
+ }
+
+size_t test_mult_point()
+ {
+ size_t fails = 0;
+
+ //Setting up expected values
+ BigInt exp_mult_x(std::string("967697346845926834906555988570157345422864716250"));
+ BigInt exp_mult_y(std::string("512319768365374654866290830075237814703869061656"));
+
+ // precalculation
+ std::string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
+ std::string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
+ std::string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, secp160r1 );
+
+ PointGFp p0 = p_G;
+ PointGFp p1 = p_G *= 2;
+
+ p1 *= p0.get_affine_x();
+
+ PointGFp expected(secp160r1, exp_mult_x, exp_mult_y);
+
+ CHECK(p1 == expected);
+ return fails;
+ }
+
+size_t test_basic_operations()
+ {
+ size_t fails = 0;
+
+ // precalculation
+ std::string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
+ std::string a_secp = "ffffffffffffffffffffffffffffffff7ffffffc";
+ std::string b_secp = "1c97befc54bd7a8b65acf89f81d4d4adc565fa45";
+ std::string G_secp_comp = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, secp160r1 );
+
+ PointGFp p0 = p_G;
+
+ PointGFp expected(secp160r1,
+ BigInt("425826231723888350446541592701409065913635568770"),
+ BigInt("203520114162904107873991457957346892027982641970"));
+
+ CHECK(p0 == expected);
+
+ PointGFp p1 = p_G *= 2;
+
+ CHECK(p1.get_affine_x() == BigInt("16984103820118642236896513183038186009872590470"));
+ CHECK(p1.get_affine_y() == BigInt("1373093393927139016463695321221277758035357890939"));
+
+ PointGFp simplePlus= p1 + p0;
+ PointGFp exp_simplePlus(secp160r1,
+ BigInt("704859595002530890444080436569091156047721708633"),
+ BigInt("1147993098458695153857594941635310323215433166682"));
+ if(simplePlus != exp_simplePlus)
+ std::cout << simplePlus << " != " << exp_simplePlus << "\n";
+
+ PointGFp simpleMinus= p1 - p0;
+ PointGFp exp_simpleMinus(secp160r1,
+ BigInt("425826231723888350446541592701409065913635568770"),
+ BigInt("203520114162904107873991457957346892027982641970"));
+
+ CHECK(simpleMinus == exp_simpleMinus);
+
+ PointGFp simpleMult= p1 * 123456789;
+
+ CHECK(simpleMult.get_affine_x() == BigInt("43638877777452195295055270548491599621118743290"));
+ CHECK(simpleMult.get_affine_y() == BigInt("56841378500012376527163928510402662349220202981"));
+
+ // check that all initial points hasn't changed
+ CHECK(p1.get_affine_x() == BigInt("16984103820118642236896513183038186009872590470"));
+ CHECK(p1.get_affine_y() == BigInt("1373093393927139016463695321221277758035357890939"));
+
+ CHECK(p0.get_affine_x() == BigInt("425826231723888350446541592701409065913635568770"));
+ CHECK(p0.get_affine_y() == BigInt("203520114162904107873991457957346892027982641970"));
+ return fails;
+ }
+
+size_t test_enc_dec_compressed_160()
+ {
+ size_t fails = 0;
+
+ // Test for compressed conversion (02/03) 160bit
+ std::string p_secp = "ffffffffffffffffffffffffffffffff7fffffff";
+ std::string a_secp = "ffffffffffffffffffffffffffffffff7ffffffC";
+ std::string b_secp = "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45";
+ std::string G_secp_comp = "024A96B5688EF573284664698968C38BB913CBFC82";
+ std::string G_order_secp_comp = "0100000000000000000001F4C8F927AED3CA752257";
+
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, secp160r1 );
+ std::vector<byte> sv_result = unlock(EC2OSP(p_G, PointGFp::COMPRESSED));
+
+ CHECK( sv_result == sv_G_secp_comp);
+ return fails;
+ }
+
+size_t test_enc_dec_compressed_256()
+ {
+ size_t fails = 0;
+
+ // Test for compressed conversion (02/03) 256bit
+ std::string p_secp = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
+ std::string a_secp = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffFC";
+ std::string b_secp = "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B";
+ std::string G_secp_comp = "036B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296";
+ std::string G_order_secp_comp = "ffffffff00000000ffffffffffffffffBCE6FAADA7179E84F3B9CAC2FC632551";
+
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G_secp_comp );
+
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, secp160r1 );
+ std::vector<byte> sv_result = unlock(EC2OSP(p_G, PointGFp::COMPRESSED));
+
+ CHECK( sv_result == sv_G_secp_comp);
+ return fails;
+ }
+
+
+size_t test_enc_dec_uncompressed_112()
+ {
+ size_t fails = 0;
+
+ // Test for uncompressed conversion (04) 112bit
+
+ std::string p_secp = "db7c2abf62e35e668076bead208b";
+ std::string a_secp = "6127C24C05F38A0AAAF65C0EF02C";
+ std::string b_secp = "51DEF1815DB5ED74FCC34C85D709";
+ std::string G_secp_uncomp = "044BA30AB5E892B4E1649DD0928643ADCD46F5882E3747DEF36E956E97";
+ std::string G_order_secp_uncomp = "36DF0AAFD8B8D7597CA10520D04B";
+
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_uncomp = hex_decode ( G_secp_uncomp );
+
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+
+ PointGFp p_G = OS2ECP ( sv_G_secp_uncomp, secp160r1 );
+ std::vector<byte> sv_result = unlock(EC2OSP(p_G, PointGFp::UNCOMPRESSED));
+
+ CHECK( sv_result == sv_G_secp_uncomp);
+ return fails;
+ }
+
+size_t test_enc_dec_uncompressed_521()
+ {
+ size_t fails = 0;
+
+ // Test for uncompressed conversion(04) with big values(521 bit)
+ std::string p_secp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
+ std::string a_secp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFC";
+ std::string b_secp = "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00";
+ std::string G_secp_uncomp = "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2ffA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650";
+ std::string G_order_secp_uncomp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409";
+
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_uncomp = hex_decode ( G_secp_uncomp );
+
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+
+ CurveGFp secp160r1(bi_p_secp, bi_a_secp, bi_b_secp);
+
+ PointGFp p_G = OS2ECP ( sv_G_secp_uncomp, secp160r1 );
+
+ std::vector<byte> sv_result = unlock(EC2OSP(p_G, PointGFp::UNCOMPRESSED));
+ std::string result = hex_encode(&sv_result[0], sv_result.size());
+ std::string exp_result = hex_encode(&sv_G_secp_uncomp[0], sv_G_secp_uncomp.size());
+
+ CHECK_MESSAGE( sv_result == sv_G_secp_uncomp, "\ncalc. result = " << result << "\nexp. result = " << exp_result << "\n");
+ return fails;
+ }
+
+size_t test_enc_dec_uncompressed_521_prime_too_large()
+ {
+ size_t fails = 0;
+
+ // Test for uncompressed conversion(04) with big values(521 bit)
+ std::string p_secp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; // length increased by "ff"
+ std::string a_secp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFC";
+ std::string b_secp = "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00";
+ std::string G_secp_uncomp = "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2ffA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650";
+ std::string G_order_secp_uncomp = "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409";
+
+ std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ std::vector<byte> sv_a_secp = hex_decode ( a_secp );
+ std::vector<byte> sv_b_secp = hex_decode ( b_secp );
+ std::vector<byte> sv_G_secp_uncomp = hex_decode ( G_secp_uncomp );
+
+ BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+
+ CurveGFp secp521r1 (bi_p_secp, bi_a_secp, bi_b_secp);
+ std::unique_ptr<PointGFp> p_G;
+ bool exc = false;
+ try
+ {
+ p_G = std::unique_ptr<PointGFp>(new PointGFp(OS2ECP ( sv_G_secp_uncomp, secp521r1)));
+ if(!p_G->on_the_curve())
+ throw Internal_Error("Point not on the curve");
+ }
+ catch (std::exception e)
+ {
+ exc = true;
+ }
+
+ CHECK_MESSAGE(exc, "attempt of creation of point on curve with too high prime did not throw an exception");
+ return fails;
+ }
+
+size_t test_gfp_store_restore()
+ {
+ size_t fails = 0;
+
+ // generate point
+ //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)
+ std::vector<byte> sv_mes = unlock(EC2OSP(p, PointGFp::COMPRESSED));
+ PointGFp new_p = OS2ECP(sv_mes, dom_pars.get_curve());
+
+ CHECK_MESSAGE( p == new_p, "original and restored point are different!");
+ return fails;
+ }
+
+
+// maybe move this test
+size_t test_cdc_curve_33()
+ {
+ size_t fails = 0;
+
+ std::string G_secp_uncomp = "04081523d03d4f12cd02879dea4bf6a4f3a7df26ed888f10c5b2235a1274c386a2f218300dee6ed217841164533bcdc903f07a096f9fbf4ee95bac098a111f296f5830fe5c35b3e344d5df3a2256985f64fbe6d0edcc4c61d18bef681dd399df3d0194c5a4315e012e0245ecea56365baa9e8be1f7";
+
+ std::vector<byte> sv_G_uncomp = hex_decode ( G_secp_uncomp );
+
+ BigInt bi_p_secp = BigInt("2117607112719756483104013348936480976596328609518055062007450442679169492999007105354629105748524349829824407773719892437896937279095106809");
+ BigInt bi_a_secp("0xa377dede6b523333d36c78e9b0eaa3bf48ce93041f6d4fc34014d08f6833807498deedd4290101c5866e8dfb589485d13357b9e78c2d7fbe9fe");
+ BigInt bi_b_secp("0xa9acf8c8ba617777e248509bcb4717d4db346202bf9e352cd5633731dd92a51b72a4dc3b3d17c823fcc8fbda4da08f25dea89046087342595a7");
+
+ CurveGFp curve(bi_p_secp, bi_a_secp, bi_b_secp);
+ PointGFp p_G = OS2ECP ( sv_G_uncomp, curve);
+ bool exc = false;
+ try
+ {
+ if(!p_G.on_the_curve())
+ throw Internal_Error("Point not on the curve");
+ }
+ catch (std::exception)
+ {
+ exc = true;
+ }
+ CHECK(!exc);
+ return fails;
+ }
+
+size_t test_more_zeropoint()
+ {
+ size_t fails = 0;
+
+ // by Falko
+
+ std::string G = "024a96b5688ef573284664698968c38bb913cbfc82";
+ std::vector<byte> sv_G_secp_comp = hex_decode ( G );
+ BigInt bi_p("0xffffffffffffffffffffffffffffffff7fffffff");
+ BigInt bi_a("0xffffffffffffffffffffffffffffffff7ffffffc");
+ BigInt bi_b("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45");
+ CurveGFp curve(bi_p, bi_a, bi_b);
+
+ PointGFp p1(curve,
+ BigInt("16984103820118642236896513183038186009872590470"),
+ BigInt("1373093393927139016463695321221277758035357890939"));
+
+ if(!p1.on_the_curve())
+ throw Internal_Error("Point not on the curve");
+ PointGFp minus_p1 = -p1;
+ if(!minus_p1.on_the_curve())
+ throw Internal_Error("Point not on the curve");
+ PointGFp shouldBeZero = p1 + minus_p1;
+ if(!shouldBeZero.on_the_curve())
+ throw Internal_Error("Point not on the curve");
+
+ BigInt y1 = p1.get_affine_y();
+ y1 = curve.get_p() - y1;
+
+ CHECK_MESSAGE(p1.get_affine_x() == minus_p1.get_affine_x(),
+ "problem with minus_p1 : x");
+ CHECK_MESSAGE(minus_p1.get_affine_y() == y1,
+ "problem with minus_p1 : y");
+
+ PointGFp zero(curve);
+ if(!zero.on_the_curve())
+ throw Internal_Error("Point not on the curve");
+ CHECK_MESSAGE(p1 + zero == p1, "addition of zero modified point");
+
+ CHECK_MESSAGE( shouldBeZero.is_zero(), "p - q with q = p is not zero!");
+ return fails;
+ }
+
+size_t test_mult_by_order()
+ {
+ size_t fails = 0;
+
+ // generate point
+ EC_Group dom_pars(OID("1.3.132.0.8"));
+ PointGFp p = dom_pars.get_base_point();
+ PointGFp shouldBeZero = p * dom_pars.get_order();
+
+ CHECK_MESSAGE(shouldBeZero.is_zero(), "G * order != O");
+ return fails;
+ }
+
+size_t test_point_swap(RandomNumberGenerator& rng)
+ {
+ size_t fails = 0;
+
+
+ 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()));
+ b *= BigInt(20);
+
+ PointGFp c(a);
+ PointGFp d(b);
+
+ d.swap(c);
+ CHECK(a == d);
+ CHECK(b == c);
+ return fails;
+ }
+
+/**
+* This test verifies that the side channel attack resistant multiplication function
+* yields the same result as the normal (insecure) multiplication via operator*=
+*/
+size_t test_mult_sec_mass(RandomNumberGenerator& rng)
+ {
+ size_t fails = 0;
+
+
+ EC_Group dom_pars(OID("1.3.132.0.8"));
+ for(int i = 0; i<50; i++)
+ {
+ PointGFp a(create_random_point(rng, dom_pars.get_curve()));
+ BigInt scal(BigInt(rng, 40));
+ PointGFp b = a * scal;
+ PointGFp c(a);
+
+ c *= scal;
+ CHECK(b == c);
+ }
+ return fails;
+ }
+
+size_t test_curve_cp_ctor()
+ {
+ try
+ {
+ EC_Group dom_pars(OID("1.3.132.0.8"));
+ CurveGFp curve(dom_pars.get_curve());
+ }
+ catch(...)
+ {
+ return 1;
+
+ }
+
+ return 0;
+ }
+
+}
+
+size_t test_ecc()
+ {
+ AutoSeeded_RNG rng;
+
+ size_t fails = 0;
+
+ fails += test_point_turn_on_sp_red_mul();
+ fails += test_coordinates();
+ fails += test_point_transformation ();
+ fails += test_point_mult ();
+ fails += test_point_negative();
+ fails += test_zeropoint();
+ fails += test_zeropoint_enc_dec();
+ fails += test_calc_with_zeropoint();
+ fails += test_add_point();
+ fails += test_sub_point();
+ fails += test_mult_point();
+ fails += test_basic_operations();
+ fails += test_enc_dec_compressed_160();
+ fails += test_enc_dec_compressed_256();
+ fails += test_enc_dec_uncompressed_112();
+ fails += test_enc_dec_uncompressed_521();
+ fails += test_enc_dec_uncompressed_521_prime_too_large();
+ fails += test_gfp_store_restore();
+ fails += test_cdc_curve_33();
+ fails += test_more_zeropoint();
+ fails += test_mult_by_order();
+ fails += test_point_swap(rng);
+ fails += test_mult_sec_mass(rng);
+ fails += test_curve_cp_ctor();
+
+ test_report("ECC", 0, fails);
+
+ return fails;
+ }
diff --git a/src/tests/test_ecdh.cpp b/src/tests/test_ecdh.cpp
new file mode 100644
index 000000000..5eb5da586
--- /dev/null
+++ b/src/tests/test_ecdh.cpp
@@ -0,0 +1,132 @@
+/*
+* ECDH tests
+*
+* (C) 2007 Manuel Hartl ([email protected])
+* 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include "tests.h"
+
+#include <iostream>
+#include <fstream>
+
+#include <botan/auto_rng.h>
+#include <botan/pubkey.h>
+#include <botan/ecdh.h>
+#include <botan/x509self.h>
+#include <botan/der_enc.h>
+
+using namespace Botan;
+
+#define CHECK_MESSAGE(expr, print) try { if(!(expr)) { ++fails; std::cout << print << "\n"; } } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; }
+#define CHECK(expr) try { if(!(expr)) { ++fails; std::cout << #expr << "\n"; } } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; }
+
+namespace {
+
+size_t test_ecdh_normal_derivation(RandomNumberGenerator& rng)
+ {
+ size_t fails = 0;
+
+ EC_Group dom_pars(OID("1.3.132.0.8"));
+
+ ECDH_PrivateKey private_a(rng, dom_pars);
+
+ ECDH_PrivateKey private_b(rng, dom_pars); //public_a.getCurve()
+
+ PK_Key_Agreement ka(private_a, "KDF2(SHA-1)");
+ PK_Key_Agreement kb(private_b, "KDF2(SHA-1)");
+
+ SymmetricKey alice_key = ka.derive_key(32, private_b.public_value());
+ SymmetricKey bob_key = kb.derive_key(32, private_a.public_value());
+
+ if(alice_key != bob_key)
+ {
+ std::cout << "The two keys didn't match!\n";
+ std::cout << "Alice's key was: " << alice_key.as_string() << "\n";
+ std::cout << "Bob's key was: " << bob_key.as_string() << "\n";
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t test_ecdh_some_dp(RandomNumberGenerator& rng)
+ {
+ size_t fails = 0;
+
+ std::vector<std::string> oids;
+ oids.push_back("1.2.840.10045.3.1.7");
+ oids.push_back("1.3.132.0.8");
+ oids.push_back("1.2.840.10045.3.1.1");
+
+ for(u32bit i = 0; i< oids.size(); i++)
+ {
+ OID oid(oids[i]);
+ EC_Group dom_pars(oid);
+
+ ECDH_PrivateKey private_a(rng, dom_pars);
+ ECDH_PrivateKey private_b(rng, dom_pars);
+
+ PK_Key_Agreement ka(private_a, "KDF2(SHA-1)");
+ PK_Key_Agreement kb(private_b, "KDF2(SHA-1)");
+
+ SymmetricKey alice_key = ka.derive_key(32, private_b.public_value());
+ SymmetricKey bob_key = kb.derive_key(32, private_a.public_value());
+
+ CHECK_MESSAGE(alice_key == bob_key, "different keys - " << "Alice's key was: " << alice_key.as_string() << ", Bob's key was: " << bob_key.as_string());
+ }
+
+ return fails;
+ }
+
+size_t test_ecdh_der_derivation(RandomNumberGenerator& rng)
+ {
+ size_t fails = 0;
+
+ std::vector<std::string> oids;
+ oids.push_back("1.2.840.10045.3.1.7");
+ oids.push_back("1.3.132.0.8");
+ oids.push_back("1.2.840.10045.3.1.1");
+
+ for(u32bit i = 0; i< oids.size(); i++)
+ {
+ OID oid(oids[i]);
+ EC_Group dom_pars(oid);
+
+ ECDH_PrivateKey private_a(rng, dom_pars);
+ ECDH_PrivateKey private_b(rng, dom_pars);
+
+ std::vector<byte> key_a = private_a.public_value();
+ std::vector<byte> key_b = private_b.public_value();
+
+ PK_Key_Agreement ka(private_a, "KDF2(SHA-1)");
+ PK_Key_Agreement kb(private_b, "KDF2(SHA-1)");
+
+ SymmetricKey alice_key = ka.derive_key(32, key_b);
+ SymmetricKey bob_key = kb.derive_key(32, key_a);
+
+ CHECK_MESSAGE(alice_key == bob_key, "different keys - " << "Alice's key was: " << alice_key.as_string() << ", Bob's key was: " << bob_key.as_string());
+
+ }
+
+ return fails;
+ }
+
+}
+
+size_t test_ecdh()
+ {
+ size_t fails = 0;
+
+ AutoSeeded_RNG rng;
+
+ fails += test_ecdh_normal_derivation(rng);
+ fails += test_ecdh_some_dp(rng);
+ fails += test_ecdh_der_derivation(rng);
+
+ test_report("ECDH", 3, fails);
+
+ return fails;
+ }
diff --git a/src/tests/test_ecdsa.cpp b/src/tests/test_ecdsa.cpp
new file mode 100644
index 000000000..b557f0193
--- /dev/null
+++ b/src/tests/test_ecdsa.cpp
@@ -0,0 +1,490 @@
+/******************************************************
+* ECDSA tests *
+* *
+* (C) 2007 Falko Strenzke *
+* Manuel Hartl *
+* 2008 Jack Lloyd *
+******************************************************/
+
+#include "tests.h"
+
+#include <botan/hex.h>
+#include <botan/auto_rng.h>
+#include <botan/pubkey.h>
+#include <botan/ecdsa.h>
+#include <botan/rsa.h>
+#include <botan/x509cert.h>
+#include <botan/oids.h>
+
+#include <iostream>
+#include <fstream>
+#include <memory>
+
+using namespace Botan;
+
+#define TEST_DATA_DIR CHECKS_DIR "/ecc_testdata"
+
+#define CHECK_MESSAGE(expr, print) try { if(!(expr)) { ++fails; std::cout << print << "\n"; } } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; }
+#define CHECK(expr) try { if(!(expr)) { ++fails; std::cout << #expr << "\n"; } } catch(std::exception& e) { std::cout << __FUNCTION__ << ": " << e.what() << "\n"; }
+
+namespace {
+
+std::string to_hex(const std::vector<byte>& bin)
+ {
+ return hex_encode(&bin[0], bin.size());
+ }
+
+/**
+
+* Tests whether the the signing routine will work correctly in case
+* the integer e that is constructed from the message (thus the hash
+* value) is larger than n, the order of the base point. Tests the
+* signing function of the pk signer object */
+
+size_t test_hash_larger_than_n(RandomNumberGenerator& rng)
+ {
+ EC_Group dom_pars(OID("1.3.132.0.8")); // secp160r1
+ // n = 0x0100000000000000000001f4c8f927aed3ca752257 (21 bytes)
+ // -> shouldn't work with SHA224 which outputs 28 bytes
+
+ size_t fails = 0;
+ ECDSA_PrivateKey priv_key(rng, dom_pars);
+
+ std::vector<byte> message(20);
+ for(size_t i = 0; i != message.size(); ++i)
+ message[i] = i;
+
+ PK_Signer pk_signer_160(priv_key, "EMSA1_BSI(SHA-1)");
+ PK_Verifier pk_verifier_160(priv_key, "EMSA1_BSI(SHA-1)");
+
+ PK_Signer pk_signer_224(priv_key, "EMSA1_BSI(SHA-224)");
+
+ // Verify we can sign and verify with SHA-160
+ std::vector<byte> signature_160 = pk_signer_160.sign_message(message, rng);
+
+ CHECK(pk_verifier_160.verify_message(message, signature_160));
+
+ bool signature_failed = false;
+ try
+ {
+ std::vector<byte> signature_224 = pk_signer_224.sign_message(message, rng);
+ }
+ catch(Encoding_Error)
+ {
+ signature_failed = true;
+ }
+
+ CHECK(signature_failed);
+
+ // now check that verification alone fails
+
+ // sign it with the normal EMSA1
+ PK_Signer pk_signer(priv_key, "EMSA1(SHA-224)");
+ std::vector<byte> signature = pk_signer.sign_message(message, rng);
+
+ PK_Verifier pk_verifier(priv_key, "EMSA1_BSI(SHA-224)");
+
+ // verify against EMSA1_BSI
+ if(pk_verifier.verify_message(message, signature))
+ {
+ std::cout << "Corrupt ECDSA signature verified, should not have\n";
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t test_decode_ecdsa_X509()
+ {
+ X509_Certificate cert(TEST_DATA_DIR "/CSCA.CSCA.csca-germany.1.crt");
+ size_t fails = 0;
+
+ CHECK_MESSAGE(OIDS::lookup(cert.signature_algorithm().oid) == "ECDSA/EMSA1(SHA-224)", "error reading signature algorithm from x509 ecdsa certificate");
+
+ CHECK_MESSAGE(to_hex(cert.serial_number()) == "01", "error reading serial from x509 ecdsa certificate");
+ CHECK_MESSAGE(to_hex(cert.authority_key_id()) == "0096452DE588F966C4CCDF161DD1F3F5341B71E7", "error reading authority key id from x509 ecdsa certificate");
+ CHECK_MESSAGE(to_hex(cert.subject_key_id()) == "0096452DE588F966C4CCDF161DD1F3F5341B71E7", "error reading Subject key id from x509 ecdsa certificate");
+
+ std::unique_ptr<X509_PublicKey> pubkey(cert.subject_public_key());
+ bool ver_ec = cert.check_signature(*pubkey);
+ CHECK_MESSAGE(ver_ec, "could not positively verify correct selfsigned x509-ecdsa certificate");
+
+ return fails;
+ }
+
+size_t test_decode_ver_link_SHA256()
+ {
+ X509_Certificate root_cert(TEST_DATA_DIR "/root2_SHA256.cer");
+ X509_Certificate link_cert(TEST_DATA_DIR "/link_SHA256.cer");
+
+ size_t fails = 0;
+ std::unique_ptr<X509_PublicKey> pubkey(root_cert.subject_public_key());
+ bool ver_ec = link_cert.check_signature(*pubkey);
+ CHECK_MESSAGE(ver_ec, "could not positively verify correct SHA256 link x509-ecdsa certificate");
+ return fails;
+ }
+
+size_t test_decode_ver_link_SHA1()
+ {
+ X509_Certificate root_cert(TEST_DATA_DIR "/root_SHA1.163.crt");
+ X509_Certificate link_cert(TEST_DATA_DIR "/link_SHA1.166.crt");
+
+ size_t fails = 0;
+ std::unique_ptr<X509_PublicKey> pubkey(root_cert.subject_public_key());
+ bool ver_ec = link_cert.check_signature(*pubkey);
+ CHECK_MESSAGE(ver_ec, "could not positively verify correct SHA1 link x509-ecdsa certificate");
+ return fails;
+ }
+
+size_t test_sign_then_ver(RandomNumberGenerator& rng)
+ {
+ EC_Group dom_pars(OID("1.3.132.0.8"));
+ ECDSA_PrivateKey ecdsa(rng, dom_pars);
+
+ size_t fails = 0;
+ PK_Signer signer(ecdsa, "EMSA1(SHA-1)");
+
+ auto msg = hex_decode("12345678901234567890abcdef12");
+ std::vector<byte> sig = signer.sign_message(msg, rng);
+
+ PK_Verifier verifier(ecdsa, "EMSA1(SHA-1)");
+
+ bool ok = verifier.verify_message(msg, sig);
+
+ if(!ok)
+ {
+ std::cout << "ERROR: Could not verify ECDSA signature\n";
+ fails++;
+ }
+
+ sig[0]++;
+ ok = verifier.verify_message(msg, sig);
+
+ if(ok)
+ {
+ std::cout << "ERROR: Bogus ECDSA signature verified anyway\n";
+ fails++;
+ }
+
+ return fails;
+ }
+
+size_t test_ec_sign(RandomNumberGenerator& rng)
+ {
+ size_t fails = 0;
+
+ try
+ {
+ 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(size_t i = 0; i != 256; ++i)
+ signer.update(static_cast<byte>(i));
+ std::vector<byte> sig = signer.signature(rng);
+
+ for(u32bit i = 0; i != 256; ++i)
+ verifier.update(static_cast<byte>(i));
+ if(!verifier.check_signature(sig))
+ {
+ std::cout << "ECDSA self-test failed!";
+ ++fails;
+ }
+
+ // now check valid signature, different input
+ for(u32bit i = 1; i != 256; ++i) //starting from 1
+ verifier.update(static_cast<byte>(i));
+
+ if(verifier.check_signature(sig))
+ {
+ std::cout << "ECDSA with bad input passed validation";
+ ++fails;
+ }
+
+ // now check with original input, modified signature
+
+ sig[sig.size()/2]++;
+ for(u32bit i = 0; i != 256; ++i)
+ verifier.update(static_cast<byte>(i));
+
+ if(verifier.check_signature(sig))
+ {
+ std::cout << "ECDSA with bad signature passed validation";
+ ++fails;
+ }
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "Exception in test_ec_sign - " << e.what() << "\n";
+ ++fails;
+ }
+
+ return fails;
+ }
+
+
+size_t test_create_pkcs8(RandomNumberGenerator& rng)
+ {
+ size_t fails = 0;
+
+ try
+ {
+ RSA_PrivateKey rsa_key(rng, 1024);
+ //RSA_PrivateKey rsa_key2(1024);
+ //cout << "\nequal: " << (rsa_key == rsa_key2) << "\n";
+ //DSA_PrivateKey key(DL_Group("dsa/jce/1024"));
+
+ std::ofstream rsa_priv_key(TEST_DATA_DIR "/rsa_private.pkcs8.pem");
+ rsa_priv_key << PKCS8::PEM_encode(rsa_key);
+
+ EC_Group dom_pars(OID("1.3.132.0.8"));
+ ECDSA_PrivateKey key(rng, dom_pars);
+
+ // later used by other tests :(
+ std::ofstream priv_key(TEST_DATA_DIR "/wo_dompar_private.pkcs8.pem");
+ priv_key << PKCS8::PEM_encode(key);
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "Exception: " << e.what() << std::endl;
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t test_create_and_verify(RandomNumberGenerator& rng)
+ {
+ size_t fails = 0;
+
+ 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);
+
+ std::unique_ptr<PKCS8_PrivateKey> loaded_key(PKCS8::load_key(TEST_DATA_DIR "/wo_dompar_private.pkcs8.pem", rng));
+ ECDSA_PrivateKey* loaded_ec_key = dynamic_cast<ECDSA_PrivateKey*>(loaded_key.get());
+ CHECK_MESSAGE(loaded_ec_key, "the loaded key could not be converted into an ECDSA_PrivateKey");
+
+ std::unique_ptr<PKCS8_PrivateKey> loaded_key_1(PKCS8::load_key(TEST_DATA_DIR "/rsa_private.pkcs8.pem", rng));
+ ECDSA_PrivateKey* loaded_rsa_key = dynamic_cast<ECDSA_PrivateKey*>(loaded_key_1.get());
+ CHECK_MESSAGE(!loaded_rsa_key, "the loaded key is ECDSA_PrivateKey -> shouldn't be, is a RSA-Key");
+
+ //calc a curve which is not in the registry
+
+ // string p_secp = "2117607112719756483104013348936480976596328609518055062007450442679169492999007105354629105748524349829824407773719892437896937279095106809";
+ std::string a_secp = "0a377dede6b523333d36c78e9b0eaa3bf48ce93041f6d4fc34014d08f6833807498deedd4290101c5866e8dfb589485d13357b9e78c2d7fbe9fe";
+ std::string b_secp = "0a9acf8c8ba617777e248509bcb4717d4db346202bf9e352cd5633731dd92a51b72a4dc3b3d17c823fcc8fbda4da08f25dea89046087342595a7";
+ std::string G_secp_comp = "04081523d03d4f12cd02879dea4bf6a4f3a7df26ed888f10c5b2235a1274c386a2f218300dee6ed217841164533bcdc903f07a096f9fbf4ee95bac098a111f296f5830fe5c35b3e344d5df3a2256985f64fbe6d0edcc4c61d18bef681dd399df3d0194c5a4315e012e0245ecea56365baa9e8be1f7";
+ std::string order_g = "0e1a16196e6000000000bc7f1618d867b15bb86474418f";
+
+ // ::std::vector<byte> sv_p_secp = hex_decode ( p_secp );
+ auto sv_a_secp = hex_decode ( a_secp );
+ auto sv_b_secp = hex_decode ( b_secp );
+ auto sv_G_secp_comp = hex_decode ( G_secp_comp );
+ auto sv_order_g = hex_decode ( order_g );
+
+ // BigInt bi_p_secp = BigInt::decode ( &sv_p_secp[0], sv_p_secp.size() );
+ BigInt bi_p_secp("2117607112719756483104013348936480976596328609518055062007450442679169492999007105354629105748524349829824407773719892437896937279095106809");
+ BigInt bi_a_secp = BigInt::decode ( &sv_a_secp[0], sv_a_secp.size() );
+ BigInt bi_b_secp = BigInt::decode ( &sv_b_secp[0], sv_b_secp.size() );
+ BigInt bi_order_g = BigInt::decode ( &sv_order_g[0], sv_order_g.size() );
+ CurveGFp curve(bi_p_secp, bi_a_secp, bi_b_secp);
+ PointGFp p_G = OS2ECP ( sv_G_secp_comp, curve );
+
+ 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");
+
+ ECDSA_PrivateKey key_odd_oid(rng, dom_params);
+ std::string key_odd_oid_str = PKCS8::PEM_encode(key_odd_oid);
+
+ DataSource_Memory key_data_src(key_odd_oid_str);
+ std::unique_ptr<PKCS8_PrivateKey> loaded_key2(PKCS8::load_key(key_data_src, rng));
+
+ if(!dynamic_cast<ECDSA_PrivateKey*>(loaded_key.get()))
+ {
+ std::cout << "Failed to reload an ECDSA key with unusual parameter set\n";
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t test_curve_registry(RandomNumberGenerator& rng)
+ {
+ std::vector<std::string> oids;
+ oids.push_back("1.3.132.0.8");
+ oids.push_back("1.2.840.10045.3.1.1");
+ oids.push_back("1.2.840.10045.3.1.2");
+ oids.push_back("1.2.840.10045.3.1.3");
+ oids.push_back("1.2.840.10045.3.1.4");
+ oids.push_back("1.2.840.10045.3.1.5");
+ oids.push_back("1.2.840.10045.3.1.6");
+ oids.push_back("1.2.840.10045.3.1.7");
+ oids.push_back("1.3.132.0.6");
+ oids.push_back("1.3.132.0.7");
+ oids.push_back("1.3.132.0.28");
+ oids.push_back("1.3.132.0.29");
+ oids.push_back("1.3.132.0.9");
+ oids.push_back("1.3.132.0.30");
+ oids.push_back("1.3.132.0.31");
+ oids.push_back("1.3.132.0.32");
+ oids.push_back("1.3.132.0.33");
+ oids.push_back("1.3.132.0.10");
+ oids.push_back("1.3.132.0.34");
+ oids.push_back("1.3.132.0.35");
+ //oids.push_back("1.3.6.1.4.1.8301.3.1.2.9.0.38");
+ oids.push_back("1.3.36.3.3.2.8.1.1.1");
+ oids.push_back("1.3.36.3.3.2.8.1.1.3");
+ oids.push_back("1.3.36.3.3.2.8.1.1.5");
+ oids.push_back("1.3.36.3.3.2.8.1.1.7");
+ oids.push_back("1.3.36.3.3.2.8.1.1.9");
+ oids.push_back("1.3.36.3.3.2.8.1.1.11");
+ oids.push_back("1.3.36.3.3.2.8.1.1.13");
+
+ size_t fails = 0;
+
+ unsigned int i;
+ for (i = 0; i < oids.size(); i++)
+ {
+ try
+ {
+ OID oid(oids[i]);
+ EC_Group dom_pars(oid);
+ ECDSA_PrivateKey ecdsa(rng, dom_pars);
+
+ PK_Signer signer(ecdsa, "EMSA1(SHA-1)");
+ PK_Verifier verifier(ecdsa, "EMSA1(SHA-1)");
+
+ auto msg = hex_decode("12345678901234567890abcdef12");
+ std::vector<byte> sig = signer.sign_message(msg, rng);
+
+ if(!verifier.verify_message(msg, sig))
+ {
+ std::cout << "Failed testing ECDSA sig for curve " << oids[i] << "\n";
+ ++fails;
+ }
+ }
+ catch(Invalid_Argument& e)
+ {
+ std::cout << "Error testing curve " << oids[i] << " - " << e.what() << "\n";
+ ++fails;
+ }
+ }
+ return fails;
+ }
+
+size_t test_read_pkcs8(RandomNumberGenerator& rng)
+ {
+ auto msg = hex_decode("12345678901234567890abcdef12");
+ size_t fails = 0;
+
+ try
+ {
+ std::unique_ptr<PKCS8_PrivateKey> loaded_key(PKCS8::load_key(TEST_DATA_DIR "/wo_dompar_private.pkcs8.pem", rng));
+ ECDSA_PrivateKey* ecdsa = dynamic_cast<ECDSA_PrivateKey*>(loaded_key.get());
+ CHECK_MESSAGE(ecdsa, "the loaded key could not be converted into an ECDSA_PrivateKey");
+
+ PK_Signer signer(*ecdsa, "EMSA1(SHA-1)");
+
+ std::vector<byte> sig = signer.sign_message(msg, rng);
+
+ PK_Verifier verifier(*ecdsa, "EMSA1(SHA-1)");
+
+ CHECK_MESSAGE(verifier.verify_message(msg, sig),
+ "generated sig could not be verified positively");
+ }
+ catch (std::exception& e)
+ {
+ ++fails;
+ std::cout << "Exception in test_read_pkcs8 - " << e.what() << "\n";
+ }
+
+ try
+ {
+ std::unique_ptr<PKCS8_PrivateKey> loaded_key_nodp(PKCS8::load_key(TEST_DATA_DIR "/nodompar_private.pkcs8.pem", rng));
+ // anew in each test with unregistered domain-parameters
+ ECDSA_PrivateKey* ecdsa_nodp = dynamic_cast<ECDSA_PrivateKey*>(loaded_key_nodp.get());
+ CHECK_MESSAGE(ecdsa_nodp, "the loaded key could not be converted into an ECDSA_PrivateKey");
+
+ PK_Signer signer(*ecdsa_nodp, "EMSA1(SHA-1)");
+ PK_Verifier verifier(*ecdsa_nodp, "EMSA1(SHA-1)");
+
+ std::vector<byte> signature_nodp = signer.sign_message(msg, rng);
+
+ CHECK_MESSAGE(verifier.verify_message(msg, signature_nodp),
+ "generated signature could not be verified positively (no_dom)");
+
+ try
+ {
+ std::unique_ptr<PKCS8_PrivateKey> loaded_key_withdp(
+ PKCS8::load_key(TEST_DATA_DIR "/withdompar_private.pkcs8.pem", rng));
+
+ std::cout << "Unexpected success: loaded key with unknown OID\n";
+ ++fails;
+ }
+ catch (std::exception) { /* OK */ }
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "Exception in test_read_pkcs8 - " << e.what() << "\n";
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t test_ecc_key_with_rfc5915_extensions(RandomNumberGenerator& rng)
+ {
+ const std::string pw = "G3bz1L1gmB5ULietOZdoLPu63D7uwTLMEk";
+
+ size_t fails = 0;
+
+ try
+ {
+ std::unique_ptr<PKCS8_PrivateKey> pkcs8(
+ PKCS8::load_key(TEST_DATA_DIR "/ecc_private_with_rfc5915_ext.pem", rng, pw));
+
+ if(!dynamic_cast<ECDSA_PrivateKey*>(pkcs8.get()))
+ {
+ std::cout << "Loaded RFC 5915 key, but got something other than an ECDSA key\n";
+ ++fails;
+ }
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Exception in " << __func__ << " - " << e.what() << "\n";
+ ++fails;
+ }
+
+ return fails;
+ }
+
+}
+
+size_t test_ecdsa()
+ {
+ size_t fails = 0;
+
+ AutoSeeded_RNG rng;
+
+ fails += test_hash_larger_than_n(rng);
+ fails += test_decode_ecdsa_X509();
+ fails += test_decode_ver_link_SHA256();
+ fails += test_decode_ver_link_SHA1();
+ fails += test_sign_then_ver(rng);
+ fails += test_ec_sign(rng);
+ fails += test_create_pkcs8(rng);
+ fails += test_create_and_verify(rng);
+ fails += test_curve_registry(rng);
+ fails += test_read_pkcs8(rng);
+ fails += test_ecc_key_with_rfc5915_extensions(rng);
+
+ test_report("ECDSA", 11, fails);
+
+ return fails;
+ }
diff --git a/src/tests/test_hash.cpp b/src/tests/test_hash.cpp
new file mode 100644
index 000000000..bb5788565
--- /dev/null
+++ b/src/tests/test_hash.cpp
@@ -0,0 +1,60 @@
+#include "tests.h"
+
+#include <botan/libstate.h>
+#include <botan/hash.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+
+using namespace Botan;
+
+namespace {
+
+bool hash_test(const std::string& algo,
+ const std::string& in_hex,
+ const std::string& out_hex)
+ {
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ const auto providers = af.providers_of(algo);
+ size_t fails = 0;
+
+ for(auto provider: providers)
+ {
+ auto proto = af.prototype_hash_function(algo, provider);
+
+ if(!proto)
+ {
+ std::cout << "Unable to get " << algo << " from " << provider << "\n";
+ ++fails;
+ continue;
+ }
+
+ std::unique_ptr<HashFunction> hash(proto->clone());
+
+ hash->update(hex_decode(in_hex));
+
+ auto h = hash->final();
+
+ if(h != hex_decode_locked(out_hex))
+ {
+ std::cout << algo << " " << provider << " got " << hex_encode(h) << " != " << out_hex << "\n";
+ ++fails;
+ }
+ }
+
+ return (fails == 0);
+ }
+
+}
+
+size_t test_hash()
+ {
+ std::ifstream vec(CHECKS_DIR "/hash.vec");
+
+ return run_tests_bb(vec, "Hash", "Out", true,
+ [](std::map<std::string, std::string> m) -> bool
+ {
+ return hash_test(m["Hash"], m["In"], m["Out"]);
+ });
+ }
diff --git a/src/tests/test_hkdf.cpp b/src/tests/test_hkdf.cpp
new file mode 100644
index 000000000..1c8532c33
--- /dev/null
+++ b/src/tests/test_hkdf.cpp
@@ -0,0 +1,70 @@
+#include "tests.h"
+
+#include <botan/libstate.h>
+#include <botan/hkdf.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+
+using namespace Botan;
+
+namespace {
+
+secure_vector<byte> hkdf(const std::string& algo,
+ const secure_vector<byte>& ikm,
+ const secure_vector<byte>& salt,
+ const secure_vector<byte>& info,
+ size_t L)
+ {
+ Algorithm_Factory& af = global_state().algorithm_factory();
+ const MessageAuthenticationCode* mac_proto = af.prototype_mac("HMAC(" + algo + ")");
+
+ if(!mac_proto)
+ throw std::invalid_argument("Bad HKDF hash " + algo);
+
+ HKDF hkdf(mac_proto->clone(), mac_proto->clone());
+
+ hkdf.start_extract(&salt[0], salt.size());
+ hkdf.extract(&ikm[0], ikm.size());
+ hkdf.finish_extract();
+
+ secure_vector<byte> key(L);
+ hkdf.expand(&key[0], key.size(), &info[0], info.size());
+ return key;
+ }
+
+bool hkdf_test(const std::string& algo,
+ const std::string& ikm,
+ const std::string& salt,
+ const std::string& info,
+ const std::string& okm,
+ size_t L)
+ {
+ const std::string got = hex_encode(
+ hkdf(algo,
+ hex_decode_locked(ikm),
+ hex_decode_locked(salt),
+ hex_decode_locked(info),
+ L)
+ );
+
+ if(got != okm)
+ std::cout << "HKDF got " << got << " expected " << okm << std::endl;
+
+ return (got == okm);
+ }
+
+}
+
+size_t test_hkdf()
+ {
+ // From RFC 5869
+ std::ifstream vec(CHECKS_DIR "/hkdf.vec");
+
+ return run_tests_bb(vec, "HKDF", "OKM", true,
+ [](std::map<std::string, std::string> m) -> bool
+ {
+ return hkdf_test(m["Hash"], m["IKM"], m["salt"], m["info"],
+ m["OKM"], to_u32bit(m["L"]));
+ });
+ }
diff --git a/src/tests/test_kdf.cpp b/src/tests/test_kdf.cpp
new file mode 100644
index 000000000..9debe7966
--- /dev/null
+++ b/src/tests/test_kdf.cpp
@@ -0,0 +1,43 @@
+#include "tests.h"
+
+#include <botan/lookup.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+
+using namespace Botan;
+
+namespace {
+
+secure_vector<byte> kdf(const std::string& algo,
+ size_t outlen,
+ const secure_vector<byte>& secret,
+ const secure_vector<byte>& salt)
+ {
+ std::unique_ptr<KDF> kdf(get_kdf(algo));
+ return kdf->derive_key(outlen, secret, salt);
+ }
+
+std::string kdf_test(const std::string& algo,
+ size_t outlen,
+ const std::string& secret,
+ const std::string& salt)
+ {
+ return hex_encode(kdf(algo, outlen,
+ hex_decode_locked(secret),
+ hex_decode_locked(salt)));
+ }
+
+}
+
+size_t test_kdf()
+ {
+ std::ifstream vec(CHECKS_DIR "/kdf.vec");
+
+ return run_tests(vec, "KDF", "Output", true,
+ [](std::map<std::string, std::string> m)
+ {
+ return kdf_test(m["KDF"], to_u32bit(m["OutputLen"]),
+ m["Secret"], m["Salt"]);
+ });
+ }
diff --git a/src/tests/test_keywrap.cpp b/src/tests/test_keywrap.cpp
new file mode 100644
index 000000000..a7dcbfe75
--- /dev/null
+++ b/src/tests/test_keywrap.cpp
@@ -0,0 +1,90 @@
+#include "tests.h"
+
+#include <botan/libstate.h>
+#include <botan/hex.h>
+
+#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
+ #include <botan/rfc3394.h>
+#endif
+
+#include <iostream>
+
+using namespace Botan;
+
+namespace {
+
+size_t keywrap_test(const char* key_str,
+ const char* expected_str,
+ const char* kek_str)
+ {
+ size_t fail = 0;
+
+#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
+ try
+ {
+ SymmetricKey key(key_str);
+ SymmetricKey expected(expected_str);
+ SymmetricKey kek(kek_str);
+
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ secure_vector<byte> enc = rfc3394_keywrap(key.bits_of(), kek, af);
+
+ if(enc != expected.bits_of())
+ {
+ std::cout << "NIST key wrap encryption failure: "
+ << hex_encode(enc) << " != " << hex_encode(expected.bits_of()) << "\n";
+ fail++;
+ }
+
+ secure_vector<byte> dec = rfc3394_keyunwrap(expected.bits_of(), kek, af);
+
+ if(dec != key.bits_of())
+ {
+ std::cout << "NIST key wrap decryption failure: "
+ << hex_encode(dec) << " != " << hex_encode(key.bits_of()) << "\n";
+ fail++;
+ }
+ }
+ catch(std::exception& e)
+ {
+ std::cout << e.what() << "\n";
+ fail++;
+ }
+#endif
+
+ return fail;
+ }
+
+}
+
+size_t test_keywrap()
+ {
+ size_t fails = 0;
+
+ fails += keywrap_test("00112233445566778899AABBCCDDEEFF",
+ "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5",
+ "000102030405060708090A0B0C0D0E0F");
+
+ fails += keywrap_test("00112233445566778899AABBCCDDEEFF",
+ "96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D",
+ "000102030405060708090A0B0C0D0E0F1011121314151617");
+
+ fails += keywrap_test("00112233445566778899AABBCCDDEEFF",
+ "64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ fails += keywrap_test("00112233445566778899AABBCCDDEEFF0001020304050607",
+ "031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2",
+ "000102030405060708090A0B0C0D0E0F1011121314151617");
+
+ fails += keywrap_test("00112233445566778899AABBCCDDEEFF0001020304050607",
+ "A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ fails += keywrap_test("00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F",
+ "28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ return fails;
+ }
diff --git a/src/tests/test_mac.cpp b/src/tests/test_mac.cpp
new file mode 100644
index 000000000..31f159663
--- /dev/null
+++ b/src/tests/test_mac.cpp
@@ -0,0 +1,62 @@
+#include "tests.h"
+
+#include <botan/libstate.h>
+#include <botan/mac.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+
+using namespace Botan;
+
+namespace {
+
+bool mac_test(const std::string& algo,
+ const std::string& key_hex,
+ const std::string& in_hex,
+ const std::string& out_hex)
+ {
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ const auto providers = af.providers_of(algo);
+ size_t fails = 0;
+
+ for(auto provider: providers)
+ {
+ auto proto = af.prototype_mac(algo, provider);
+
+ if(!proto)
+ {
+ std::cout << "Unable to get " << algo << " from " << provider << "\n";
+ ++fails;
+ continue;
+ }
+
+ std::unique_ptr<MessageAuthenticationCode> mac(proto->clone());
+
+ mac->set_key(hex_decode(key_hex));
+ mac->update(hex_decode(in_hex));
+
+ auto h = mac->final();
+
+ if(h != hex_decode_locked(out_hex))
+ {
+ std::cout << algo << " " << provider << " got " << hex_encode(h) << " != " << out_hex << "\n";
+ ++fails;
+ }
+ }
+
+ return (fails == 0);
+ }
+
+}
+
+size_t test_mac()
+ {
+ std::ifstream vec(CHECKS_DIR "/mac.vec");
+
+ return run_tests_bb(vec, "Mac", "Out", true,
+ [](std::map<std::string, std::string> m) -> bool
+ {
+ return mac_test(m["Mac"], m["Key"], m["In"], m["Out"]);
+ });
+ }
diff --git a/src/tests/test_modes.cpp b/src/tests/test_modes.cpp
new file mode 100644
index 000000000..1b546cea3
--- /dev/null
+++ b/src/tests/test_modes.cpp
@@ -0,0 +1,79 @@
+#include "tests.h"
+
+#include <botan/hex.h>
+#include <botan/lookup.h>
+#include <botan/cipher_mode.h>
+#include <botan/filters.h>
+#include <iostream>
+#include <fstream>
+#include <memory>
+
+using namespace Botan;
+
+namespace {
+
+secure_vector<byte> run_mode(const std::string& algo,
+ Cipher_Dir dir,
+ const secure_vector<byte>& pt,
+ const secure_vector<byte>& nonce,
+ const secure_vector<byte>& key)
+ {
+#if 0
+ std::unique_ptr<Cipher_Mode> cipher(get_cipher(algo, dir));
+
+ cipher->set_key(key);
+ cipher->start_vec(nonce);
+
+ secure_vector<byte> ct = pt;
+ cipher->finish(ct);
+#endif
+
+ Pipe pipe(get_cipher(algo, SymmetricKey(key), InitializationVector(nonce), dir));
+
+ pipe.process_msg(pt);
+
+ return pipe.read_all();
+ }
+
+bool mode_test(const std::string& algo,
+ const std::string& pt,
+ const std::string& ct,
+ const std::string& key_hex,
+ const std::string& nonce_hex)
+ {
+ auto nonce = hex_decode_locked(nonce_hex);
+ auto key = hex_decode_locked(key_hex);
+
+ const std::string ct2 = hex_encode(run_mode(algo,
+ ENCRYPTION,
+ hex_decode_locked(pt),
+ nonce,
+ key));
+
+ if(ct != ct2)
+ std::cout << algo << " got ct " << ct2 << " expected " << ct << "\n";
+
+ const std::string pt2 = hex_encode(run_mode(algo,
+ DECRYPTION,
+ hex_decode_locked(ct),
+ nonce,
+ key));
+
+ if(pt != pt2)
+ std::cout << algo << " got pt " << pt2 << " expected " << pt << "\n";
+
+ return (ct == ct2) && (pt == pt2);
+ }
+
+}
+
+size_t test_modes()
+ {
+ std::ifstream vec(CHECKS_DIR "/modes.vec");
+
+ return run_tests_bb(vec, "Mode", "Out", true,
+ [](std::map<std::string, std::string> m)
+ {
+ return mode_test(m["Mode"], m["In"], m["Out"], m["Key"], m["Nonce"]);
+ });
+ }
diff --git a/src/tests/test_ocb.cpp b/src/tests/test_ocb.cpp
new file mode 100644
index 000000000..b2bd296e0
--- /dev/null
+++ b/src/tests/test_ocb.cpp
@@ -0,0 +1,142 @@
+
+#include "tests.h"
+
+#include <botan/ocb.h>
+#include <botan/hex.h>
+#include <botan/sha2_32.h>
+#include <botan/aes.h>
+#include <iostream>
+//#include <botan/selftest.h>
+
+using namespace Botan;
+
+// something like this should be in the library
+namespace {
+
+std::vector<byte> ocb_decrypt(const SymmetricKey& key,
+ const std::vector<byte>& nonce,
+ const byte ct[], size_t ct_len,
+ const byte ad[], size_t ad_len)
+ {
+ OCB_Decryption ocb(new AES_128);
+
+ ocb.set_key(key);
+ ocb.set_associated_data(ad, ad_len);
+
+ ocb.start(&nonce[0], nonce.size());
+
+ secure_vector<byte> buf(ct, ct+ct_len);
+ ocb.finish(buf, 0);
+
+ return unlock(buf);
+ }
+
+std::vector<byte> ocb_encrypt(const SymmetricKey& key,
+ const std::vector<byte>& nonce,
+ const byte pt[], size_t pt_len,
+ const byte ad[], size_t ad_len)
+ {
+ OCB_Encryption ocb(new AES_128);
+
+ ocb.set_key(key);
+ ocb.set_associated_data(ad, ad_len);
+
+ ocb.start(&nonce[0], nonce.size());
+
+ secure_vector<byte> buf(pt, pt+pt_len);
+ ocb.finish(buf, 0);
+
+ try
+ {
+ std::vector<byte> pt2 = ocb_decrypt(key, nonce, &buf[0], buf.size(), ad, ad_len);
+ if(pt_len != pt2.size() || !same_mem(pt, &pt2[0], pt_len))
+ std::cout << "OCB failed to decrypt correctly\n";
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "OCB round trip error - " << e.what() << "\n";
+ }
+
+ return unlock(buf);
+ }
+
+template<typename Alloc, typename Alloc2>
+std::vector<byte> ocb_encrypt(const SymmetricKey& key,
+ const std::vector<byte>& nonce,
+ const std::vector<byte, Alloc>& pt,
+ const std::vector<byte, Alloc2>& ad)
+ {
+ return ocb_encrypt(key, nonce, &pt[0], pt.size(), &ad[0], ad.size());
+ }
+
+template<typename Alloc, typename Alloc2>
+std::vector<byte> ocb_decrypt(const SymmetricKey& key,
+ const std::vector<byte>& nonce,
+ const std::vector<byte, Alloc>& pt,
+ const std::vector<byte, Alloc2>& ad)
+ {
+ return ocb_decrypt(key, nonce, &pt[0], pt.size(), &ad[0], ad.size());
+ }
+
+std::vector<byte> ocb_encrypt(OCB_Encryption& ocb,
+ const std::vector<byte>& nonce,
+ const std::vector<byte>& pt,
+ const std::vector<byte>& ad)
+ {
+ ocb.set_associated_data(&ad[0], ad.size());
+
+ ocb.start(&nonce[0], nonce.size());
+
+ secure_vector<byte> buf(pt.begin(), pt.end());
+ ocb.finish(buf, 0);
+
+ return unlock(buf);
+ }
+
+size_t test_ocb_long(size_t taglen, const std::string &expected)
+ {
+ OCB_Encryption ocb(new AES_128, taglen/8);
+
+ ocb.set_key(SymmetricKey("00000000000000000000000000000000"));
+
+ const std::vector<byte> empty;
+ std::vector<byte> N(12);
+ std::vector<byte> C;
+
+ for(size_t i = 0; i != 128; ++i)
+ {
+ const std::vector<byte> S(i);
+ N[11] = i;
+
+ C += ocb_encrypt(ocb, N, S, S);
+ C += ocb_encrypt(ocb, N, S, empty);
+ C += ocb_encrypt(ocb, N, empty, S);
+ }
+
+ N[11] = 0;
+ const std::vector<byte> cipher = ocb_encrypt(ocb, N, empty, C);
+
+ const std::string cipher_hex = hex_encode(cipher);
+
+ if(cipher_hex != expected)
+ {
+ std::cout << "OCB AES-128 long test mistmatch " << cipher_hex << " != " << expected << "\n";
+ return 1;
+ }
+
+ return 0;
+ }
+
+}
+
+size_t test_ocb()
+ {
+ size_t fails = 0;
+ fails += test_ocb_long(128, "B2B41CBF9B05037DA7F16C24A35C1C94");
+ fails += test_ocb_long(96, "1A4F0654277709A5BDA0D380");
+ fails += test_ocb_long(64, "B7ECE9D381FE437F");
+ test_report("OCB long", 3, fails);
+ return fails;
+ }
+
+
diff --git a/src/tests/test_passhash.cpp b/src/tests/test_passhash.cpp
new file mode 100644
index 000000000..6f66743c5
--- /dev/null
+++ b/src/tests/test_passhash.cpp
@@ -0,0 +1,94 @@
+#include "tests.h"
+
+#include <botan/auto_rng.h>
+#include <iostream>
+
+#if defined(BOTAN_HAS_PASSHASH9)
+ #include <botan/passhash9.h>
+#endif
+
+#if defined(BOTAN_HAS_BCRYPT)
+ #include <botan/bcrypt.h>
+#endif
+
+using namespace Botan;
+
+size_t test_bcrypt()
+ {
+ size_t fails = 0;
+
+#if defined(BOTAN_HAS_BCRYPT)
+
+ // Generated by jBCrypt 0.3
+ if(!check_bcrypt("abc", "$2a$05$DfPyLs.G6.To9fXEFgUL1O6HpYw3jIXgPcl/L3Qt3jESuWmhxtmpS"))
+ {
+ std::cout << "Bcrypt test 1 failed\n";
+ fails++;
+ }
+
+ // http://www.openwall.com/lists/john-dev/2011/06/19/2
+ if(!check_bcrypt("\xA3",
+ "$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq"))
+ {
+ std::cout << "Bcrypt test 2 failed\n";
+ fails++;
+ }
+
+ AutoSeeded_RNG rng;
+
+ for(u16bit level = 1; level != 5; ++level)
+ {
+ const std::string input = "some test passphrase 123";
+ const std::string gen_hash = generate_bcrypt(input, rng, level);
+
+ if(!check_bcrypt(input, gen_hash))
+ {
+ std::cout << "Gen and check for bcrypt failed: " << gen_hash << " not valid\n";
+ ++fails;
+ }
+ }
+
+ test_report("Bcrypt", 6, fails);
+
+#endif
+
+ return fails;
+ }
+
+size_t test_passhash9()
+ {
+ size_t fails = 0;
+
+#if defined(BOTAN_HAS_PASSHASH9)
+ const std::string input = "secret";
+ const std::string fixed_hash =
+ "$9$AAAKhiHXTIUhNhbegwBXJvk03XXJdzFMy+i3GFMIBYKtthTTmXZA";
+
+ size_t ran = 0;
+
+ ++ran;
+ if(!check_passhash9(input, fixed_hash))
+ {
+ std::cout << "Passhash9 fixed input test failed\n";
+ fails++;
+ }
+
+ AutoSeeded_RNG rng;
+
+ for(byte alg_id = 0; alg_id <= 4; ++alg_id)
+ {
+ std::string gen_hash = generate_passhash9(input, rng, 2, alg_id);
+
+ ++ran;
+ if(!check_passhash9(input, gen_hash))
+ {
+ std::cout << "Passhash9 gen and check " << static_cast<int>(alg_id) << " failed\n";
+ ++fails;
+ }
+ }
+
+ test_report("Passhash9", ran, fails);
+#endif
+
+ return fails;
+ }
diff --git a/src/tests/test_pbkdf.cpp b/src/tests/test_pbkdf.cpp
new file mode 100644
index 000000000..140190b13
--- /dev/null
+++ b/src/tests/test_pbkdf.cpp
@@ -0,0 +1,48 @@
+#include "tests.h"
+
+#include <botan/lookup.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+
+using namespace Botan;
+
+namespace {
+
+secure_vector<byte> pbkdf(const std::string& algo,
+ const std::string& pass,
+ const secure_vector<byte>& salt,
+ size_t iterations, size_t outlen)
+ {
+ std::unique_ptr<PBKDF> pbkdf(get_pbkdf(algo));
+ return pbkdf->derive_key(outlen, pass,
+ &salt[0], salt.size(),
+ iterations).bits_of();
+ }
+
+std::string pbkdf_test(const std::string& algo,
+ const std::string& pass,
+ const std::string& salt,
+ size_t iterations,
+ size_t outlen)
+ {
+ return hex_encode(pbkdf(algo,
+ pass,
+ hex_decode_locked(salt),
+ iterations,
+ outlen));
+ }
+
+}
+
+size_t test_pbkdf()
+ {
+ std::ifstream vec(CHECKS_DIR "/pbkdf.vec");
+
+ return run_tests(vec, "PBKDF", "Output", true,
+ [](std::map<std::string, std::string> m)
+ {
+ return pbkdf_test(m["PBKDF"], m["Passphrase"], m["Salt"],
+ to_u32bit(m["Iterations"]), to_u32bit(m["OutputLen"]));
+ });
+ }
diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp
new file mode 100644
index 000000000..209021f7f
--- /dev/null
+++ b/src/tests/test_pubkey.cpp
@@ -0,0 +1,935 @@
+/*
+* (C) 2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include "tests.h"
+#include "test_rng.h"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <cstdlib>
+#include <memory>
+
+#include <botan/botan.h>
+#include <botan/oids.h>
+
+#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
+ #include <botan/x509_key.h>
+ #include <botan/pkcs8.h>
+ #include <botan/pubkey.h>
+#endif
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ #include <botan/dsa.h>
+#endif
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ #include <botan/dh.h>
+#endif
+
+#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
+ #include <botan/nr.h>
+#endif
+
+#if defined(BOTAN_HAS_RW)
+ #include <botan/rw.h>
+#endif
+
+#if defined(BOTAN_HAS_ELGAMAL)
+ #include <botan/elgamal.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDH)
+ #include <botan/ecdh.h>
+#endif
+
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+ #include <botan/gost_3410.h>
+#endif
+
+#if defined(BOTAN_HAS_DLIES)
+ #include <botan/dlies.h>
+ #include <botan/kdf.h>
+#endif
+
+#include <botan/filters.h>
+#include <botan/numthry.h>
+using namespace Botan;
+
+namespace {
+
+BigInt to_bigint(std::string input)
+ {
+ while(input.find(' ') != std::string::npos)
+ input = input.erase(input.find(' '), 1);
+
+ while(input.find('\t') != std::string::npos)
+ input = input.erase(input.find('\t'), 1);
+
+ while(input.find('\n') != std::string::npos)
+ input = input.erase(input.find('\n'), 1);
+
+ return BigInt::decode(reinterpret_cast<const byte*>(input.data()),
+ input.length(), BigInt::Hexadecimal);
+ }
+
+void dump_data(const std::vector<byte>& out,
+ const std::vector<byte>& expected)
+ {
+ Pipe pipe(new Hex_Encoder);
+
+ pipe.process_msg(out);
+ pipe.process_msg(expected);
+ std::cout << "Got: " << pipe.read_all_as_string(0) << std::endl;
+ std::cout << "Exp: " << pipe.read_all_as_string(1) << std::endl;
+ }
+
+size_t validate_save_and_load(const Private_Key* priv_key,
+ RandomNumberGenerator& rng)
+ {
+ std::string name = priv_key->algo_name();
+
+ size_t fails = 0;
+ std::string pub_pem = X509::PEM_encode(*priv_key);
+
+ try
+ {
+ DataSource_Memory input_pub(pub_pem);
+ std::auto_ptr<Public_Key> restored_pub(X509::load_key(input_pub));
+
+ if(!restored_pub.get())
+ {
+ std::cout << "Could not recover " << name << " public key\n";
+ ++fails;
+ }
+ else if(restored_pub->check_key(rng, true) == false)
+ {
+ std::cout << "Restored pubkey failed self tests " << name << "\n";
+ ++fails;
+ }
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Exception during load of " << name
+ << " key: " << e.what() << "\n";
+ std::cout << "PEM for pubkey was:\n" << pub_pem << "\n";
+ ++fails;
+ }
+
+ std::string priv_pem = PKCS8::PEM_encode(*priv_key);
+
+ try
+ {
+ DataSource_Memory input_priv(priv_pem);
+ std::auto_ptr<Private_Key> restored_priv(
+ PKCS8::load_key(input_priv, rng));
+
+ if(!restored_priv.get())
+ {
+ std::cout << "Could not recover " << name << " privlic key\n";
+ ++fails;
+ }
+ else if(restored_priv->check_key(rng, true) == false)
+ {
+ std::cout << "Restored privkey failed self tests " << name << "\n";
+ ++fails;
+ }
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Exception during load of " << name
+ << " key: " << e.what() << "\n";
+ std::cout << "PEM for privkey was:\n" << priv_pem << "\n";
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t validate_decryption(PK_Decryptor& d, const std::string& algo,
+ const std::vector<byte> ctext,
+ const std::vector<byte> ptext)
+ {
+ size_t fails = 0;
+
+ std::vector<byte> decrypted = unlock(d.decrypt(ctext));
+
+ if(decrypted != ptext)
+ {
+ std::cout << "FAILED (decrypt): " << algo << std::endl;
+ dump_data(decrypted, ptext);
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t validate_encryption(PK_Encryptor& e, PK_Decryptor& d,
+ const std::string& algo, const std::string& input,
+ const std::string& random, const std::string& exp)
+ {
+ std::vector<byte> message = hex_decode(input);
+ std::vector<byte> expected = hex_decode(exp);
+ Fixed_Output_RNG rng(hex_decode(random));
+
+ size_t fails = 0;
+
+ std::vector<byte> out = e.encrypt(message, rng);
+ if(out != expected)
+ {
+ std::cout << "FAILED (encrypt): " << algo << std::endl;
+ dump_data(out, expected);
+ ++fails;
+ }
+
+ fails += validate_decryption(d, algo, out, message);
+
+ return fails;
+ }
+
+size_t validate_signature(PK_Verifier& v, PK_Signer& s, const std::string& algo,
+ const std::string& input,
+ RandomNumberGenerator& rng,
+ const std::string& exp)
+ {
+ std::vector<byte> message = hex_decode(input);
+ std::vector<byte> expected = hex_decode(exp);
+ std::vector<byte> sig = s.sign_message(message, rng);
+
+ size_t fails = 0;
+
+ if(sig != expected)
+ {
+ std::cout << "FAILED (sign): " << algo << std::endl;
+ dump_data(sig, expected);
+ ++fails;
+ }
+
+ if(!v.verify_message(message, sig))
+ {
+ std::cout << "FAILED (verify): " << algo << std::endl;
+ ++fails;
+ }
+
+ /* This isn't a very thorough testing method, but it will hopefully
+ catch any really horrible errors */
+ sig[0]++;
+ if(v.verify_message(message, sig))
+ {
+ std::cout << "FAILED (accepted bad sig): " << algo << std::endl;
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t validate_signature(PK_Verifier& v, PK_Signer& s, const std::string& algo,
+ const std::string& input,
+ const std::string& random,
+ const std::string& exp)
+ {
+ Fixed_Output_RNG rng(hex_decode(random));
+
+ return validate_signature(v, s, algo, input, rng, exp);
+ }
+
+size_t validate_kas(PK_Key_Agreement& kas, const std::string& algo,
+ const std::vector<byte>& pubkey, const std::string& output,
+ u32bit keylen)
+ {
+ std::vector<byte> expected = hex_decode(output);
+
+ std::vector<byte> got = unlock(kas.derive_key(keylen, pubkey).bits_of());
+
+ size_t fails = 0;
+
+ if(got != expected)
+ {
+ std::cout << "FAILED: " << algo << std::endl;
+ dump_data(got, expected);
+ ++fails;
+ }
+
+ return fails;
+ }
+
+size_t validate_rsa_enc_pkcs8(const std::string& algo,
+ const std::vector<std::string>& str,
+ RandomNumberGenerator& rng)
+ {
+ if(str.size() != 4 && str.size() != 5)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_RSA)
+ std::string pass;
+ if(str.size() == 5) pass = str[4];
+ strip_newlines(pass); /* it will have a newline thanks to the messy
+ decoding method we use */
+
+ DataSource_Memory keysource(reinterpret_cast<const byte*>(str[0].c_str()),
+ str[0].length());
+
+ std::unique_ptr<Private_Key> privkey(PKCS8::load_key(keysource, rng, pass));
+
+ RSA_PrivateKey* rsapriv = dynamic_cast<RSA_PrivateKey*>(privkey.get());
+ if(!rsapriv)
+ throw Invalid_Argument("Bad key load for RSA key");
+
+ RSA_PublicKey* rsapub = dynamic_cast<RSA_PublicKey*>(rsapriv);
+
+ std::string eme = algo.substr(12, std::string::npos);
+
+ PK_Encryptor_EME e(*rsapub, eme);
+ PK_Decryptor_EME d(*rsapriv, eme);
+
+ return validate_encryption(e, d, algo, str[1], str[2], str[3]);
+#endif
+
+ return 0;
+ }
+
+size_t validate_rsa_enc(const std::string& algo,
+ const std::vector<std::string>& str,
+ RandomNumberGenerator& rng)
+ {
+ if(str.size() != 6)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_RSA)
+ RSA_PrivateKey privkey(rng,
+ to_bigint(str[1]), to_bigint(str[2]),
+ to_bigint(str[0]));
+
+ RSA_PublicKey pubkey = privkey;
+
+ std::string eme = algo.substr(6, std::string::npos);
+
+ PK_Encryptor_EME e(pubkey, eme);
+ PK_Decryptor_EME d(privkey, eme);
+
+ return validate_encryption(e, d, algo, str[3], str[4], str[5]);
+#endif
+
+ return 0;
+ }
+
+size_t validate_elg_enc(const std::string& algo,
+ const std::vector<std::string>& str,
+ RandomNumberGenerator& rng)
+ {
+ if(str.size() != 6 && str.size() != 7)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_ELGAMAL)
+ DL_Group domain(to_bigint(str[0]), to_bigint(str[1]));
+ ElGamal_PrivateKey privkey(rng, domain, to_bigint(str[2]));
+ ElGamal_PublicKey pubkey = privkey;
+
+ std::string eme = algo.substr(8, std::string::npos);
+
+ PK_Decryptor_EME d(privkey, eme);
+
+ if(str.size() == 7)
+ {
+ PK_Encryptor_EME e(pubkey, eme);
+ return validate_encryption(e, d, algo, str[4], str[5], str[6]);
+ }
+ else
+ return validate_decryption(d, algo, hex_decode(str[5]),
+ hex_decode(str[4]));
+#endif
+
+ return 0;
+ }
+
+size_t validate_rsa_sig(const std::string& algo,
+ const std::vector<std::string>& str,
+ RandomNumberGenerator& rng)
+ {
+ if(str.size() != 6)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_RSA)
+ RSA_PrivateKey privkey(rng,
+ to_bigint(str[1]), to_bigint(str[2]),
+ to_bigint(str[0]));
+
+ RSA_PublicKey pubkey = privkey;
+
+ std::string emsa = algo.substr(7, std::string::npos);
+
+ PK_Verifier v(pubkey, emsa);
+ PK_Signer s(privkey, emsa);
+
+ return validate_signature(v, s, algo, str[3], str[4], str[5]);
+#endif
+
+ return 0;
+ }
+
+u32bit validate_rsa_ver(const std::string& algo,
+ const std::vector<std::string>& str)
+ {
+ if(str.size() != 5) /* is actually 4, parse() adds an extra empty one */
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+ size_t fails = 0;
+
+#if defined(BOTAN_HAS_RSA)
+ RSA_PublicKey key(to_bigint(str[1]), to_bigint(str[0]));
+
+ std::string emsa = algo.substr(6, std::string::npos);
+
+ PK_Verifier v(key, emsa);
+
+ std::vector<byte> msg = hex_decode(str[2]);
+ std::vector<byte> sig = hex_decode(str[3]);
+
+ if(!v.verify_message(msg, sig))
+ {
+ std::cout << "RSA verification failed\n";
+ ++fails;
+ }
+
+#endif
+
+ return fails;
+ }
+
+size_t validate_rsa_ver_x509(const std::string& algo,
+ const std::vector<std::string>& str)
+ {
+ if(str.size() != 5) /* is actually 3, parse() adds extra empty ones */
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+ size_t fails = 0;
+
+#if defined(BOTAN_HAS_RSA)
+ DataSource_Memory keysource(reinterpret_cast<const byte*>(str[0].c_str()),
+ str[0].length());
+
+ std::unique_ptr<Public_Key> key(X509::load_key(keysource));
+
+ RSA_PublicKey* rsakey = dynamic_cast<RSA_PublicKey*>(key.get());
+
+ if(!rsakey)
+ throw Invalid_Argument("Bad key load for RSA public key");
+
+ std::string emsa = algo.substr(11, std::string::npos);
+
+ PK_Verifier v(*rsakey, emsa);
+
+ std::vector<byte> msg = hex_decode(str[1]);
+ std::vector<byte> sig = hex_decode(str[2]);
+
+ if(!v.verify_message(msg, sig))
+ {
+ std::cout << "RSA verification failed\n";
+ ++fails;
+ }
+#endif
+
+ return fails;
+ }
+
+u32bit validate_rw_ver(const std::string& algo,
+ const std::vector<std::string>& str)
+ {
+ if(str.size() != 5)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_RW)
+ RW_PublicKey key(to_bigint(str[1]), to_bigint(str[0]));
+
+ std::string emsa = algo.substr(5, std::string::npos);
+
+ PK_Verifier v(key, emsa);
+
+ std::vector<byte> msg = hex_decode(str[2]);
+ std::vector<byte> sig = hex_decode(str[3]);
+
+ bool passed = true;
+ passed = v.verify_message(msg, sig);
+ return (passed ? 0 : 1);
+#endif
+
+ return 2;
+ }
+
+u32bit validate_rw_sig(const std::string& algo,
+ 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_RW)
+ RW_PrivateKey privkey(rng, to_bigint(str[1]), to_bigint(str[2]),
+ to_bigint(str[0]));
+ RW_PublicKey pubkey = privkey;
+
+ std::string emsa = algo.substr(3, std::string::npos);
+
+ PK_Verifier v(pubkey, emsa);
+ PK_Signer s(privkey, emsa);
+
+
+ validate_signature(v, s, algo, str[3], rng, str[4]);
+#endif
+
+ return 0;
+ }
+
+u32bit validate_dsa_sig(const std::string& algo,
+ const std::vector<std::string>& str,
+ RandomNumberGenerator& rng)
+ {
+ if(str.size() != 4 && str.size() != 5)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+ std::string pass;
+ if(str.size() == 5) pass = str[4];
+ strip_newlines(pass); /* it will have a newline thanks to the messy
+ decoding method we use */
+
+#if defined(BOTAN_HAS_DSA)
+
+ DataSource_Memory keysource(reinterpret_cast<const byte*>(str[0].c_str()),
+ str[0].length());
+
+ std::unique_ptr<Private_Key> privkey(PKCS8::load_key(keysource, rng, pass));
+
+ DSA_PrivateKey* dsapriv = dynamic_cast<DSA_PrivateKey*>(privkey.get());
+ if(!dsapriv)
+ throw Invalid_Argument("Bad key load for DSA private key");
+
+ DSA_PublicKey* dsapub = dynamic_cast<DSA_PublicKey*>(dsapriv);
+
+ std::string emsa = algo.substr(4, std::string::npos);
+
+ PK_Verifier v(*dsapub, emsa);
+ PK_Signer s(*dsapriv, emsa);
+
+
+ validate_signature(v, s, algo, str[1], str[2], str[3]);
+#endif
+
+ return 0;
+ }
+
+u32bit validate_ecdsa_sig(const std::string& algo,
+ 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_Group group(OIDS::lookup(str[0]));
+ ECDSA_PrivateKey ecdsa(rng, group, to_bigint(str[1]));
+
+ std::string emsa = algo.substr(6, std::string::npos);
+
+ PK_Verifier v(ecdsa, emsa);
+ PK_Signer s(ecdsa, emsa);
+
+ validate_signature(v, s, algo, str[2], str[3], str[4]);
+#endif
+
+ return 0;
+ }
+
+u32bit validate_gost_ver(const std::string& algo,
+ const std::vector<std::string>& str)
+ {
+ if(str.size() != 5)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+
+ EC_Group group(OIDS::lookup(str[0]));
+
+ PointGFp public_point = OS2ECP(hex_decode(str[1]), group.get_curve());
+
+ GOST_3410_PublicKey gost(group, public_point);
+
+ std::string emsa = algo.substr(13, std::string::npos);
+
+ PK_Verifier v(gost, emsa);
+
+ std::vector<byte> msg = hex_decode(str[2]);
+ std::vector<byte> sig = hex_decode(str[3]);
+
+ bool passed = v.verify_message(msg, sig);
+ return (passed ? 0 : 1);
+#endif
+
+ return 0;
+ }
+
+u32bit validate_dsa_ver(const std::string& algo,
+ const std::vector<std::string>& str)
+ {
+ if(str.size() != 5) /* is actually 3, parse() adds extra empty ones */
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+ DataSource_Memory keysource(reinterpret_cast<const byte*>(str[0].c_str()),
+ str[0].length());
+
+ size_t fails = 0;
+
+#if defined(BOTAN_HAS_DSA)
+ std::unique_ptr<Public_Key> key(X509::load_key(keysource));
+
+ DSA_PublicKey* dsakey = dynamic_cast<DSA_PublicKey*>(key.get());
+
+ if(!dsakey)
+ {
+ ++fails;
+ std::cout << "Unable to load DSA private key during test\n";
+ }
+
+ std::string emsa = algo.substr(7, std::string::npos);
+
+ PK_Verifier v(*dsakey, emsa);
+
+ std::vector<byte> msg = hex_decode(str[1]);
+ std::vector<byte> sig = hex_decode(str[2]);
+
+ v.set_input_format(DER_SEQUENCE);
+
+ bool verified = v.verify_message(msg, sig);
+ if(!verified)
+ {
+ std::cout << "Failed to verify\n";
+ ++fails;
+ }
+#endif
+
+ return fails;
+ }
+
+u32bit validate_nr_sig(const std::string& algo,
+ const std::vector<std::string>& str,
+ RandomNumberGenerator& rng)
+ {
+ if(str.size() != 8)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
+
+ DL_Group domain(to_bigint(str[0]), to_bigint(str[1]), to_bigint(str[2]));
+ NR_PrivateKey privkey(rng, domain, to_bigint(str[4]));
+ NR_PublicKey pubkey = privkey;
+
+ std::string emsa = algo.substr(3, std::string::npos);
+
+ PK_Verifier v(pubkey, emsa);
+ PK_Signer s(privkey, emsa);
+
+ return validate_signature(v, s, algo, str[5], str[6], str[7]);
+#endif
+
+ return 0;
+ }
+
+u32bit validate_dh(const std::string& algo,
+ const std::vector<std::string>& str,
+ RandomNumberGenerator& rng)
+ {
+ if(str.size() != 5 && str.size() != 6)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ DL_Group domain(to_bigint(str[0]), to_bigint(str[1]));
+
+ DH_PrivateKey mykey(rng, domain, to_bigint(str[2]));
+ DH_PublicKey otherkey(domain, to_bigint(str[3]));
+
+ std::string kdf = algo.substr(3, std::string::npos);
+
+ u32bit keylen = 0;
+ if(str.size() == 6)
+ keylen = to_u32bit(str[5]);
+
+ PK_Key_Agreement kas(mykey, kdf);
+
+ return validate_kas(kas, algo, otherkey.public_value(), str[4], keylen);
+#endif
+
+ return 0;
+ }
+
+u32bit validate_dlies(const std::string& algo,
+ const std::vector<std::string>& str,
+ RandomNumberGenerator& rng)
+ {
+ if(str.size() != 6)
+ throw std::runtime_error("Invalid input from pk_valid.dat");
+
+#if defined(BOTAN_HAS_DLIES)
+ DL_Group domain(to_bigint(str[0]), to_bigint(str[1]));
+
+ DH_PrivateKey from(rng, domain, to_bigint(str[2]));
+ DH_PrivateKey to(rng, domain, to_bigint(str[3]));
+
+ const std::string opt_str = algo.substr(6, std::string::npos);
+
+ std::vector<std::string> options = split_on(opt_str, '/');
+
+ if(options.size() != 3)
+ throw std::runtime_error("DLIES needs three options: " + opt_str);
+
+ MessageAuthenticationCode* mac = get_mac(options[1]);
+ u32bit mac_key_len = to_u32bit(options[2]);
+
+ DLIES_Encryptor e(from,
+ get_kdf(options[0]),
+ mac, mac_key_len);
+
+ DLIES_Decryptor d(to,
+ get_kdf(options[0]),
+ mac->clone(), mac_key_len);
+
+ e.set_other_key(to.public_value());
+
+ std::string empty = "";
+ return validate_encryption(e, d, algo, str[4], empty, str[5]);
+#endif
+
+ return 0;
+ }
+
+}
+
+size_t test_pk_keygen()
+ {
+ AutoSeeded_RNG rng;
+
+ size_t fails = 0;
+
+#define DL_KEY(TYPE, GROUP) \
+ { \
+ TYPE key(rng, DL_Group(GROUP)); \
+ key.check_key(rng, true); \
+ fails += validate_save_and_load(&key, rng); \
+ }
+
+#define EC_KEY(TYPE, GROUP) \
+ { \
+ TYPE key(rng, EC_Group(OIDS::lookup(GROUP))); \
+ key.check_key(rng, true); \
+ fails += validate_save_and_load(&key, rng); \
+ }
+
+#if defined(BOTAN_HAS_RSA)
+ {
+ RSA_PrivateKey rsa1024(rng, 1024);
+ rsa1024.check_key(rng, true);
+ fails += validate_save_and_load(&rsa1024, rng);
+
+ RSA_PrivateKey rsa2048(rng, 2048);
+ rsa2048.check_key(rng, true);
+ fails += validate_save_and_load(&rsa2048, rng);
+ }
+#endif
+
+#if defined(BOTAN_HAS_RW)
+ {
+ RW_PrivateKey rw1024(rng, 1024);
+ rw1024.check_key(rng, true);
+ fails += validate_save_and_load(&rw1024, rng);
+ }
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ DL_KEY(DSA_PrivateKey, "dsa/jce/1024");
+ DL_KEY(DSA_PrivateKey, "dsa/botan/2048");
+ DL_KEY(DSA_PrivateKey, "dsa/botan/3072");
+#endif
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ DL_KEY(DH_PrivateKey, "modp/ietf/1024");
+ DL_KEY(DH_PrivateKey, "modp/ietf/2048");
+ DL_KEY(DH_PrivateKey, "modp/ietf/4096");
+ DL_KEY(DH_PrivateKey, "dsa/jce/1024");
+#endif
+
+#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
+ DL_KEY(NR_PrivateKey, "dsa/jce/1024");
+ DL_KEY(NR_PrivateKey, "dsa/botan/2048");
+ DL_KEY(NR_PrivateKey, "dsa/botan/3072");
+#endif
+
+#if defined(BOTAN_HAS_ELGAMAL)
+ DL_KEY(ElGamal_PrivateKey, "modp/ietf/1024");
+ DL_KEY(ElGamal_PrivateKey, "dsa/jce/1024");
+ DL_KEY(ElGamal_PrivateKey, "dsa/botan/2048");
+ DL_KEY(ElGamal_PrivateKey, "dsa/botan/3072");
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ EC_KEY(ECDSA_PrivateKey, "secp112r1");
+ EC_KEY(ECDSA_PrivateKey, "secp128r1");
+ EC_KEY(ECDSA_PrivateKey, "secp160r1");
+ EC_KEY(ECDSA_PrivateKey, "secp192r1");
+ EC_KEY(ECDSA_PrivateKey, "secp224r1");
+ EC_KEY(ECDSA_PrivateKey, "secp256r1");
+ EC_KEY(ECDSA_PrivateKey, "secp384r1");
+ EC_KEY(ECDSA_PrivateKey, "secp521r1");
+#endif
+
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+ EC_KEY(GOST_3410_PrivateKey, "gost_256A");
+ EC_KEY(GOST_3410_PrivateKey, "secp112r1");
+ EC_KEY(GOST_3410_PrivateKey, "secp128r1");
+ EC_KEY(GOST_3410_PrivateKey, "secp160r1");
+ EC_KEY(GOST_3410_PrivateKey, "secp192r1");
+ EC_KEY(GOST_3410_PrivateKey, "secp224r1");
+ EC_KEY(GOST_3410_PrivateKey, "secp256r1");
+ EC_KEY(GOST_3410_PrivateKey, "secp384r1");
+ EC_KEY(GOST_3410_PrivateKey, "secp521r1");
+#endif
+
+ return fails;
+ }
+
+size_t test_pubkey()
+ {
+ AutoSeeded_RNG rng;
+ const std::string filename = CHECKS_DIR "/pk_valid.dat";
+ std::ifstream test_data(filename.c_str());
+
+ if(!test_data)
+ throw Botan::Stream_IO_Error("Couldn't open test file " + filename);
+
+ size_t total_errors = 0;
+ size_t errors = 0, alg_count = 0, total_tests = 0;
+ std::string algorithm, print_algorithm;
+
+ while(!test_data.eof())
+ {
+ if(test_data.bad() || test_data.fail())
+ throw std::runtime_error("File I/O error reading from " + filename);
+
+ std::string line;
+ std::getline(test_data, line);
+
+ strip_comments(line);
+ if(line.size() == 0) continue;
+
+ // Do line continuation
+ while(line[line.size()-1] == '\\' && !test_data.eof())
+ {
+ line.replace(line.size()-1, 1, "");
+ std::string nextline;
+ std::getline(test_data, nextline);
+ strip_comments(nextline);
+ if(nextline.size() == 0) continue;
+ line.push_back('\n');
+ line += nextline;
+ }
+
+ if(line[0] == '[' && line[line.size() - 1] == ']')
+ {
+ const std::string old_algo = print_algorithm;
+ algorithm = line.substr(1, line.size() - 2);
+ print_algorithm = algorithm;
+ if(print_algorithm.find("_PKCS8") != std::string::npos)
+ print_algorithm.replace(print_algorithm.find("_PKCS8"), 6, "");
+ if(print_algorithm.find("_X509") != std::string::npos)
+ print_algorithm.replace(print_algorithm.find("_X509"), 5, "");
+ if(print_algorithm.find("_VA") != std::string::npos)
+ print_algorithm.replace(print_algorithm.find("_VA"), 3, "");
+
+ if(old_algo != print_algorithm && old_algo != "")
+ {
+ test_report(old_algo, alg_count, errors);
+ alg_count = 0;
+ total_errors += errors;
+ errors = 0;
+ }
+
+ continue;
+ }
+
+ std::vector<std::string> substr = parse(line);
+
+ size_t new_errors = 0;
+
+ try
+ {
+
+ if(algorithm.find("DSA/") == 0)
+ new_errors = validate_dsa_sig(algorithm, substr, rng);
+ else if(algorithm.find("DSA_VA/") == 0)
+ new_errors = validate_dsa_ver(algorithm, substr);
+
+ else if(algorithm.find("ECDSA/") == 0)
+ new_errors = validate_ecdsa_sig(algorithm, substr, rng);
+
+ else if(algorithm.find("GOST_3410_VA/") == 0)
+ new_errors = validate_gost_ver(algorithm, substr);
+
+ else if(algorithm.find("RSAES_PKCS8/") == 0)
+ new_errors = validate_rsa_enc_pkcs8(algorithm, substr, rng);
+ else if(algorithm.find("RSAVA_X509/") == 0)
+ new_errors = validate_rsa_ver_x509(algorithm, substr);
+
+ else if(algorithm.find("RSAES/") == 0)
+ new_errors = validate_rsa_enc(algorithm, substr, rng);
+ else if(algorithm.find("RSASSA/") == 0)
+ new_errors = validate_rsa_sig(algorithm, substr, rng);
+ else if(algorithm.find("RSAVA/") == 0)
+ new_errors = validate_rsa_ver(algorithm, substr);
+ else if(algorithm.find("RWVA/") == 0)
+ new_errors = validate_rw_ver(algorithm, substr);
+ else if(algorithm.find("RW/") == 0)
+ new_errors = validate_rw_sig(algorithm, substr, rng);
+ else if(algorithm.find("NR/") == 0)
+ new_errors = validate_nr_sig(algorithm, substr, rng);
+ else if(algorithm.find("ElGamal/") == 0)
+ new_errors = validate_elg_enc(algorithm, substr, rng);
+ else if(algorithm.find("DH/") == 0)
+ new_errors = validate_dh(algorithm, substr, rng);
+ else if(algorithm.find("DLIES/") == 0)
+ new_errors = validate_dlies(algorithm, substr, rng);
+ else
+ {
+ std::cout << "WARNING: Unknown PK algorithm "
+ << algorithm << std::endl;
+ ++new_errors;
+ }
+
+ alg_count++;
+ total_tests++;
+ errors += new_errors;
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Exception: " << e.what() << "\n";
+ new_errors++;
+ }
+
+ if(new_errors)
+ std::cout << "ERROR: \"" << algorithm << "\" failed test #"
+ << std::dec << alg_count << std::endl;
+ }
+
+ test_report("Pubkey", total_tests, total_errors);
+
+ return total_errors;
+ }
diff --git a/src/tests/test_rng.cpp b/src/tests/test_rng.cpp
new file mode 100644
index 000000000..99b2fbf8f
--- /dev/null
+++ b/src/tests/test_rng.cpp
@@ -0,0 +1,63 @@
+#include "tests.h"
+#include "test_rng.h"
+
+#include <botan/libstate.h>
+#include <botan/x931_rng.h>
+#include <botan/aes.h>
+#include <botan/des.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+#include <deque>
+
+using namespace Botan;
+
+namespace {
+
+RandomNumberGenerator* get_x931(const std::string& algo, const std::string& ikm_hex)
+ {
+ const auto ikm = hex_decode(ikm_hex);
+
+ if(algo == "X9.31-RNG(TripleDES)")
+ return new ANSI_X931_RNG(new TripleDES, new Fixed_Output_RNG(ikm));
+ else if(algo == "X9.31-RNG(AES-128)")
+ return new ANSI_X931_RNG(new AES_128, new Fixed_Output_RNG(ikm));
+ else if(algo == "X9.31-RNG(AES-192)")
+ return new ANSI_X931_RNG(new AES_192, new Fixed_Output_RNG(ikm));
+ else if(algo == "X9.31-RNG(AES-256)")
+ return new ANSI_X931_RNG(new AES_256, new Fixed_Output_RNG(ikm));
+
+ return nullptr;
+ }
+
+bool x931_test(const std::string& algo,
+ const std::string& ikm,
+ const std::string& out,
+ size_t L)
+ {
+ std::unique_ptr<RandomNumberGenerator> x931(get_x931(algo, ikm));
+ x931->reseed(0);
+
+ const std::string got = hex_encode(x931->random_vec(L));
+
+ if(got != out)
+ {
+ std::cout << "X9.31 " << got << " != " << out << "\n";
+ return false;
+ }
+
+ return true;
+ }
+
+}
+
+size_t test_rngs()
+ {
+ std::ifstream vec(CHECKS_DIR "/x931.vec");
+
+ return run_tests_bb(vec, "RNG", "Out", true,
+ [](std::map<std::string, std::string> m) -> bool
+ {
+ return x931_test(m["RNG"], m["IKM"], m["Out"], to_u32bit(m["L"]));
+ });
+ }
diff --git a/src/tests/test_rng.h b/src/tests/test_rng.h
new file mode 100644
index 000000000..b3da5f08a
--- /dev/null
+++ b/src/tests/test_rng.h
@@ -0,0 +1,61 @@
+
+#ifndef BOTAN_TESTS_FIXED_RNG_H__
+#define BOTAN_TESTS_FIXED_RNG_H__
+
+#include <deque>
+#include <string>
+#include <stdexcept>
+#include <botan/rng.h>
+#include <botan/hex.h>
+
+using Botan::byte;
+
+class Fixed_Output_RNG : public Botan::RandomNumberGenerator
+ {
+ public:
+ bool is_seeded() const { return !buf.empty(); }
+
+ byte random()
+ {
+ if(!is_seeded())
+ throw std::runtime_error("Out of bytes");
+
+ byte out = buf.front();
+ buf.pop_front();
+ return out;
+ }
+
+ void reseed(size_t) {}
+
+ void randomize(byte out[], size_t len)
+ {
+ for(size_t j = 0; j != len; j++)
+ out[j] = random();
+ }
+
+ void add_entropy(const byte b[], size_t s)
+ {
+ buf.insert(buf.end(), b, b + s);
+ }
+
+ std::string name() const { return "Fixed_Output_RNG"; }
+
+ void clear() throw() {}
+
+ Fixed_Output_RNG(const std::vector<byte>& in)
+ {
+ buf.insert(buf.end(), in.begin(), in.end());
+ }
+
+ Fixed_Output_RNG(const std::string& in_str)
+ {
+ std::vector<byte> in = Botan::hex_decode(in_str);
+ buf.insert(buf.end(), in.begin(), in.end());
+ }
+
+ Fixed_Output_RNG() {}
+ private:
+ std::deque<byte> buf;
+ };
+
+#endif
diff --git a/src/tests/test_stream.cpp b/src/tests/test_stream.cpp
new file mode 100644
index 000000000..9846fb521
--- /dev/null
+++ b/src/tests/test_stream.cpp
@@ -0,0 +1,71 @@
+#include "tests.h"
+
+#include <botan/libstate.h>
+#include <botan/stream_cipher.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+
+using namespace Botan;
+
+namespace {
+
+bool stream_test(const std::string& algo,
+ const std::string& key_hex,
+ const std::string& in_hex,
+ const std::string& out_hex,
+ const std::string& nonce_hex)
+ {
+ const secure_vector<byte> key = hex_decode_locked(key_hex);
+ const secure_vector<byte> pt = hex_decode_locked(in_hex);
+ const secure_vector<byte> ct = hex_decode_locked(out_hex);
+ const secure_vector<byte> nonce = hex_decode_locked(nonce_hex);
+
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ const auto providers = af.providers_of(algo);
+ size_t fails = 0;
+
+ for(auto provider: providers)
+ {
+ const StreamCipher* proto = af.prototype_stream_cipher(algo, provider);
+
+ if(!proto)
+ {
+ std::cout << "Unable to get " << algo << " from " << provider << "\n";
+ ++fails;
+ continue;
+ }
+
+ std::unique_ptr<StreamCipher> cipher(proto->clone());
+ cipher->set_key(key);
+
+ if(nonce.size())
+ cipher->set_iv(&nonce[0], nonce.size());
+
+ secure_vector<byte> buf = pt;
+
+ cipher->encrypt(buf);
+
+ if(buf != ct)
+ {
+ std::cout << algo << " " << provider << " enc " << hex_encode(buf) << " != " << out_hex << "\n";
+ ++fails;
+ }
+ }
+
+ return (fails == 0);
+ }
+
+}
+
+size_t test_stream()
+ {
+ std::ifstream vec(CHECKS_DIR "/stream.vec");
+
+ return run_tests_bb(vec, "StreamCipher", "Out", true,
+ [](std::map<std::string, std::string> m) -> bool
+ {
+ return stream_test(m["StreamCipher"], m["Key"], m["In"], m["Out"], m["Nonce"]);
+ });
+ }
diff --git a/src/tests/test_tls.cpp b/src/tests/test_tls.cpp
new file mode 100644
index 000000000..af3627217
--- /dev/null
+++ b/src/tests/test_tls.cpp
@@ -0,0 +1,281 @@
+
+#include "tests.h"
+
+#if defined(BOTAN_HAS_TLS)
+
+#include <botan/auto_rng.h>
+#include <botan/tls_server.h>
+#include <botan/tls_client.h>
+#include <botan/pkcs10.h>
+#include <botan/x509self.h>
+#include <botan/rsa.h>
+#include <botan/x509_ca.h>
+#include <botan/hex.h>
+
+#include <iostream>
+#include <vector>
+#include <memory>
+
+using namespace Botan;
+
+namespace {
+
+class Credentials_Manager_Test : public Botan::Credentials_Manager
+ {
+ public:
+ Credentials_Manager_Test(const X509_Certificate& server_cert,
+ const X509_Certificate& ca_cert,
+ Private_Key* server_key) :
+ m_server_cert(server_cert),
+ m_ca_cert(ca_cert),
+ m_key(server_key)
+ {
+ auto store = new Certificate_Store_In_Memory;
+ store->add_certificate(m_ca_cert);
+ m_stores.push_back(store);
+ }
+
+ std::vector<Certificate_Store*>
+ trusted_certificate_authorities(const std::string&,
+ const std::string&) override
+ {
+ return m_stores;
+ }
+
+ std::vector<X509_Certificate> cert_chain(
+ const std::vector<std::string>& cert_key_types,
+ const std::string& type,
+ const std::string&) override
+ {
+ std::vector<X509_Certificate> chain;
+
+ if(type == "tls-server")
+ {
+ bool have_match = false;
+ for(size_t i = 0; i != cert_key_types.size(); ++i)
+ if(cert_key_types[i] == m_key->algo_name())
+ have_match = true;
+
+ if(have_match)
+ {
+ chain.push_back(m_server_cert);
+ chain.push_back(m_ca_cert);
+ }
+ }
+
+ return chain;
+ }
+
+ void verify_certificate_chain(
+ const std::string& type,
+ const std::string& purported_hostname,
+ const std::vector<Botan::X509_Certificate>& cert_chain) override
+ {
+ try
+ {
+ Credentials_Manager::verify_certificate_chain(type,
+ purported_hostname,
+ cert_chain);
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Certificate verification failed - " << e.what() << " - but will ignore\n";
+ }
+ }
+
+ Private_Key* private_key_for(const X509_Certificate&,
+ const std::string&,
+ const std::string&) override
+ {
+ return m_key;
+ }
+ public:
+ X509_Certificate m_server_cert, m_ca_cert;
+ Private_Key* m_key;
+ std::vector<Certificate_Store*> m_stores;
+ };
+
+Credentials_Manager* create_creds(RandomNumberGenerator& rng)
+ {
+ std::auto_ptr<Private_Key> ca_key(new RSA_PrivateKey(rng, 1024));
+
+ X509_Cert_Options ca_opts;
+ ca_opts.common_name = "Test CA";
+ ca_opts.country = "US";
+ ca_opts.CA_key(1);
+
+ X509_Certificate ca_cert =
+ X509::create_self_signed_cert(ca_opts,
+ *ca_key,
+ "SHA-256",
+ rng);
+
+ Private_Key* server_key = new RSA_PrivateKey(rng, 1024);
+
+ X509_Cert_Options server_opts;
+ server_opts.common_name = "localhost";
+ server_opts.country = "US";
+
+ PKCS10_Request req = X509::create_cert_req(server_opts,
+ *server_key,
+ "SHA-256",
+ rng);
+
+ X509_CA ca(ca_cert, *ca_key, "SHA-256");
+
+ auto now = std::chrono::system_clock::now();
+ X509_Time start_time(now);
+ typedef std::chrono::duration<int, std::ratio<31556926>> years;
+ X509_Time end_time(now + years(1));
+
+ X509_Certificate server_cert = ca.sign_request(req,
+ rng,
+ start_time,
+ end_time);
+
+ return new Credentials_Manager_Test(server_cert, ca_cert, server_key);
+ }
+
+
+size_t test_handshake()
+ {
+ AutoSeeded_RNG rng;
+ TLS::Policy default_policy;
+
+ std::auto_ptr<Credentials_Manager> creds(create_creds(rng));
+
+ TLS::Session_Manager_In_Memory server_sessions(rng);
+ TLS::Session_Manager_In_Memory client_sessions(rng);
+
+ std::vector<byte> c2s_q, s2c_q, c2s_data, s2c_data;
+
+ auto handshake_complete = [](const TLS::Session& session) -> bool
+ {
+ if(false)
+ {
+ std::cout << "Handshake complete, " << session.version().to_string()
+ << " using " << session.ciphersuite().to_string() << "\n";
+
+ if(!session.session_id().empty())
+ std::cout << "Session ID " << hex_encode(session.session_id()) << "\n";
+
+ if(!session.session_ticket().empty())
+ std::cout << "Session ticket " << hex_encode(session.session_ticket()) << "\n";
+ }
+
+ return true;
+ };
+
+ auto print_alert = [&](TLS::Alert alert, const byte[], size_t)
+ {
+ if(alert.is_valid())
+ std::cout << "Server recvd alert " << alert.type_string() << "\n";
+ };
+
+ auto save_server_data = [&](const byte buf[], size_t sz)
+ {
+ c2s_data.insert(c2s_data.end(), buf, buf+sz);
+ };
+
+ auto save_client_data = [&](const byte buf[], size_t sz)
+ {
+ s2c_data.insert(s2c_data.end(), buf, buf+sz);
+ };
+
+ TLS::Server server([&](const byte buf[], size_t sz)
+ { s2c_q.insert(s2c_q.end(), buf, buf+sz); },
+ save_server_data,
+ print_alert,
+ handshake_complete,
+ server_sessions,
+ *creds,
+ default_policy,
+ rng);
+
+ TLS::Client client([&](const byte buf[], size_t sz)
+ { c2s_q.insert(c2s_q.end(), buf, buf+sz); },
+ save_client_data,
+ print_alert,
+ handshake_complete,
+ client_sessions,
+ *creds,
+ default_policy,
+ rng);
+
+ while(true)
+ {
+ if(client.is_active())
+ client.send("1");
+ if(server.is_active())
+ server.send("2");
+
+ /*
+ * Use this as a temp value to hold the queues as otherwise they
+ * might end up appending more in response to messages during the
+ * handshake.
+ */
+ std::vector<byte> input;
+ std::swap(c2s_q, input);
+
+ try
+ {
+ server.received_data(&input[0], input.size());
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Server error - " << e.what() << "\n";
+ break;
+ }
+
+ input.clear();
+ std::swap(s2c_q, input);
+
+ try
+ {
+ client.received_data(&input[0], input.size());
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Client error - " << e.what() << "\n";
+ break;
+ }
+
+ if(c2s_data.size())
+ {
+ if(c2s_data[0] != '1')
+ {
+ std::cout << "Error\n";
+ return 1;
+ }
+ }
+
+ if(s2c_data.size())
+ {
+ if(s2c_data[0] != '2')
+ {
+ std::cout << "Error\n";
+ return 1;
+ }
+ }
+
+ if(s2c_data.size() && c2s_data.size())
+ break;
+ }
+
+ return 0;
+ }
+
+}
+
+size_t test_tls()
+ {
+ size_t errors = 0;
+
+ errors += test_handshake();
+
+ return errors;
+ }
+
+#else
+size_t test_tls() { return 0; }
+#endif
diff --git a/src/tests/test_transform.cpp b/src/tests/test_transform.cpp
new file mode 100644
index 000000000..dc54d1761
--- /dev/null
+++ b/src/tests/test_transform.cpp
@@ -0,0 +1,50 @@
+#include "tests.h"
+
+#include <botan/botan.h>
+#include <botan/transform.h>
+#include <botan/threefish.h>
+#include <botan/benchmark.h>
+#include <botan/hex.h>
+#include <iostream>
+#include <fstream>
+
+using namespace Botan;
+
+namespace {
+
+Transformation* get_transform(const std::string& algo)
+ {
+ throw std::runtime_error("Unknown transform " + algo);
+ }
+
+secure_vector<byte> transform_test(const std::string& algo,
+ const secure_vector<byte>& nonce,
+ const secure_vector<byte>& key,
+ const secure_vector<byte>& in)
+ {
+ std::unique_ptr<Transformation> transform(get_transform(algo));
+
+ transform->set_key(key);
+ transform->start_vec(nonce);
+
+ secure_vector<byte> out = in;
+ transform->update(out, 0);
+
+ return out;
+ }
+
+}
+
+size_t test_transform()
+ {
+ std::ifstream vec(CHECKS_DIR "/transform.vec");
+
+ return run_tests(vec, "Transform", "Output", true,
+ [](std::map<std::string, std::string> m)
+ {
+ return hex_encode(transform_test(m["Transform"],
+ hex_decode_locked(m["Nonce"]),
+ hex_decode_locked(m["Key"]),
+ hex_decode_locked(m["Input"])));
+ });
+ }
diff --git a/src/tests/test_x509.cpp b/src/tests/test_x509.cpp
new file mode 100644
index 000000000..cd0beec5b
--- /dev/null
+++ b/src/tests/test_x509.cpp
@@ -0,0 +1,255 @@
+/*
+* (C) 2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include "tests.h"
+
+#include <botan/filters.h>
+#include <botan/auto_rng.h>
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ #include <botan/dsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_X509_CERTIFICATES)
+ #include <botan/x509self.h>
+ #include <botan/x509path.h>
+ #include <botan/x509_ca.h>
+ #include <botan/pkcs10.h>
+#endif
+
+using namespace Botan;
+
+#include <iostream>
+#include <memory>
+
+
+#if defined(BOTAN_HAS_X509_CERTIFICATES) && \
+ defined(BOTAN_HAS_RSA) && \
+ defined(BOTAN_HAS_DSA)
+
+namespace {
+
+u64bit key_id(const Public_Key* key)
+ {
+ Pipe pipe(new Hash_Filter("SHA-1", 8));
+ pipe.start_msg();
+ pipe.write(key->algo_name());
+ pipe.write(key->algorithm_identifier().parameters);
+ pipe.write(key->x509_subject_public_key());
+ pipe.end_msg();
+
+ secure_vector<byte> output = pipe.read_all();
+
+ if(output.size() != 8)
+ throw Internal_Error("Public_Key::key_id: Incorrect output size");
+
+ u64bit id = 0;
+ for(u32bit j = 0; j != 8; ++j)
+ id = (id << 8) | output[j];
+ return id;
+ }
+
+
+/* Return some option sets */
+X509_Cert_Options ca_opts()
+ {
+ X509_Cert_Options opts("Test CA/US/Botan Project/Testing");
+
+ opts.uri = "http://botan.randombit.net";
+ opts.dns = "botan.randombit.net";
+ opts.email = "[email protected]";
+
+ opts.CA_key(1);
+
+ return opts;
+ }
+
+X509_Cert_Options req_opts1()
+ {
+ X509_Cert_Options opts("Test User 1/US/Botan Project/Testing");
+
+ opts.uri = "http://botan.randombit.net";
+ opts.dns = "botan.randombit.net";
+ opts.email = "[email protected]";
+
+ return opts;
+ }
+
+X509_Cert_Options req_opts2()
+ {
+ X509_Cert_Options opts("Test User 2/US/Botan Project/Testing");
+
+ opts.uri = "http://botan.randombit.net";
+ opts.dns = "botan.randombit.net";
+ opts.email = "[email protected]";
+
+ opts.add_ex_constraint("PKIX.EmailProtection");
+
+ return opts;
+ }
+
+u32bit check_against_copy(const Private_Key& orig,
+ RandomNumberGenerator& rng)
+ {
+ Private_Key* copy_priv = PKCS8::copy_key(orig, rng);
+ Public_Key* copy_pub = X509::copy_key(orig);
+
+ const std::string passphrase= "I need work! -Mr. T";
+ DataSource_Memory enc_source(PKCS8::PEM_encode(orig, rng, passphrase));
+ Private_Key* copy_priv_enc = PKCS8::load_key(enc_source, rng,
+ passphrase);
+
+ u64bit orig_id = key_id(&orig);
+ u64bit pub_id = key_id(copy_pub);
+ u64bit priv_id = key_id(copy_priv);
+ u64bit priv_enc_id = key_id(copy_priv_enc);
+
+ delete copy_pub;
+ delete copy_priv;
+ delete copy_priv_enc;
+
+ if(orig_id != pub_id || orig_id != priv_id || orig_id != priv_enc_id)
+ {
+ std::cout << "Failed copy check for " << orig.algo_name() << "\n";
+ return 1;
+ }
+ return 0;
+ }
+
+}
+
+size_t test_x509()
+ {
+ AutoSeeded_RNG rng;
+ const std::string hash_fn = "SHA-256";
+
+ size_t fails = 0;
+
+ /* Create the CA's key and self-signed cert */
+ RSA_PrivateKey ca_key(rng, 2048);
+
+ X509_Certificate ca_cert = X509::create_self_signed_cert(ca_opts(),
+ ca_key,
+ hash_fn,
+ rng);
+ /* Create user #1's key and cert request */
+ DSA_PrivateKey user1_key(rng, DL_Group("dsa/botan/2048"));
+
+ PKCS10_Request user1_req = X509::create_cert_req(req_opts1(),
+ user1_key,
+ "SHA-1",
+ rng);
+
+ /* Create user #2's key and cert request */
+#if defined(BOTAN_HAS_ECDSA)
+ 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, 1536);
+#endif
+
+ PKCS10_Request user2_req = X509::create_cert_req(req_opts2(),
+ user2_key,
+ hash_fn,
+ rng);
+
+ /* Create the CA object */
+ X509_CA ca(ca_cert, ca_key, hash_fn);
+
+ /* Sign the requests to create the certs */
+ X509_Certificate user1_cert =
+ ca.sign_request(user1_req, rng,
+ X509_Time("2008-01-01"), X509_Time("2100-01-01"));
+
+ X509_Certificate user2_cert = ca.sign_request(user2_req, rng,
+ X509_Time("2008-01-01"),
+ X509_Time("2100-01-01"));
+ X509_CRL crl1 = ca.new_crl(rng);
+
+ /* Verify the certs */
+ Certificate_Store_In_Memory store;
+
+ store.add_certificate(ca_cert);
+
+ Path_Validation_Restrictions restrictions;
+
+ Path_Validation_Result result_u1 = x509_path_validate(user1_cert, restrictions, store);
+ if(!result_u1.successful_validation())
+ {
+ std::cout << "FAILED: User cert #1 did not validate - "
+ << result_u1.result_string() << std::endl;
+ ++fails;
+ }
+
+ Path_Validation_Result result_u2 = x509_path_validate(user2_cert, restrictions, store);
+ if(!result_u2.successful_validation())
+ {
+ std::cout << "FAILED: User cert #2 did not validate - "
+ << result_u2.result_string() << std::endl;
+ ++fails;
+ }
+
+ store.add_crl(crl1);
+
+ std::vector<CRL_Entry> revoked;
+ revoked.push_back(CRL_Entry(user1_cert, CESSATION_OF_OPERATION));
+ revoked.push_back(user2_cert);
+
+ X509_CRL crl2 = ca.update_crl(crl1, revoked, rng);
+
+ store.add_crl(crl2);
+
+ result_u1 = x509_path_validate(user1_cert, restrictions, store);
+ if(result_u1.result() != Certificate_Status_Code::CERT_IS_REVOKED)
+ {
+ std::cout << "FAILED: User cert #1 was not revoked - "
+ << result_u1.result_string() << std::endl;
+ ++fails;
+ }
+
+ result_u2 = x509_path_validate(user2_cert, restrictions, store);
+ if(result_u2.result() != Certificate_Status_Code::CERT_IS_REVOKED)
+ {
+ std::cout << "FAILED: User cert #2 was not revoked - "
+ << result_u2.result_string() << std::endl;
+ ++fails;
+ }
+
+ revoked.clear();
+ revoked.push_back(CRL_Entry(user1_cert, REMOVE_FROM_CRL));
+ X509_CRL crl3 = ca.update_crl(crl2, revoked, rng);
+
+ store.add_crl(crl3);
+
+ result_u1 = x509_path_validate(user1_cert, restrictions, store);
+ if(!result_u1.successful_validation())
+ {
+ std::cout << "FAILED: User cert #1 was not un-revoked - "
+ << result_u1.result_string() << std::endl;
+ ++fails;
+ }
+
+ check_against_copy(ca_key, rng);
+ check_against_copy(user1_key, rng);
+ check_against_copy(user2_key, rng);
+
+ return fails;
+ }
+
+#else
+
+size_t test_x590() { return 0; }
+
+#endif
+
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
new file mode 100644
index 000000000..49f55c165
--- /dev/null
+++ b/src/tests/tests.cpp
@@ -0,0 +1,190 @@
+#include "tests.h"
+#include <iostream>
+
+size_t run_tests(const std::vector<test_fn>& tests)
+ {
+ size_t fails = 0;
+
+ for(auto& test : tests)
+ {
+ try
+ {
+ fails += test();
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Exception escaped test: " << e.what() << "\n";
+ ++fails;
+ }
+ catch(...)
+ {
+ std::cout << "Exception escaped test\n";
+ ++fails;
+ }
+ }
+
+ test_report("Tests", 0, fails);
+
+ return fails;
+ }
+
+void test_report(const std::string& name, size_t ran, size_t failed)
+ {
+ std::cout << name;
+
+ if(ran > 0)
+ std::cout << " " << ran << " tests";
+
+ if(failed)
+ std::cout << " " << failed << " FAILs\n";
+ else
+ std::cout << " all ok\n";
+ }
+
+size_t run_tests_bb(std::istream& src,
+ const std::string& name_key,
+ const std::string& output_key,
+ bool clear_between_cb,
+ std::function<bool (std::map<std::string, std::string>)> cb)
+ {
+ if(!src.good())
+ {
+ std::cout << "Could not open input file for " << name_key << "\n";
+ return 1;
+ }
+
+ std::map<std::string, std::string> vars;
+ size_t test_fails = 0, algo_fail = 0;
+ size_t test_count = 0, algo_count = 0;
+
+ std::string fixed_name;
+
+ while(src.good())
+ {
+ std::string line;
+ std::getline(src, line);
+
+ if(line == "")
+ continue;
+
+ if(line[0] == '#')
+ continue;
+
+ if(line[0] == '[' && line[line.size()-1] == ']')
+ {
+ if(fixed_name != "")
+ test_report(fixed_name, algo_count, algo_fail);
+
+ test_count += algo_count;
+ test_fails += algo_fail;
+ algo_count = 0;
+ algo_fail = 0;
+ fixed_name = line.substr(1, line.size() - 2);
+ vars[name_key] = fixed_name;
+ continue;
+ }
+
+ const std::string key = line.substr(0, line.find_first_of(' '));
+ const std::string val = line.substr(line.find_last_of(' ') + 1, std::string::npos);
+
+ vars[key] = val;
+
+ if(key == name_key)
+ fixed_name.clear();
+
+ if(key == output_key)
+ {
+ //std::cout << vars[name_key] << " " << test_cnt << "\n";
+ ++algo_count;
+ try
+ {
+ if(!cb(vars))
+ {
+ std::cout << vars[name_key] << " test " << algo_count << " failed\n";
+ ++algo_fail;
+ }
+ }
+ catch(std::exception& e)
+ {
+ std::cout << vars[name_key] << " test " << algo_count << " failed: " << e.what() << "\n";
+ ++algo_fail;
+ }
+
+ if(clear_between_cb)
+ {
+ vars.clear();
+ vars[name_key] = fixed_name;
+ }
+ }
+ }
+
+ if(fixed_name != "" && (algo_count > 0 || algo_fail > 0))
+ test_report(fixed_name, algo_count, algo_fail);
+
+ test_count += algo_count;
+ test_fails += algo_fail;
+
+ test_report(name_key, test_count, test_fails);
+
+ return test_fails;
+ }
+
+size_t run_tests(std::istream& src,
+ const std::string& name_key,
+ const std::string& output_key,
+ bool clear_between_cb,
+ std::function<std::string (std::map<std::string, std::string>)> cb)
+ {
+ return run_tests_bb(src, name_key, output_key, clear_between_cb,
+ [name_key,output_key,cb](std::map<std::string, std::string> vars)
+ {
+ const std::string got = cb(vars);
+ if(got != vars[output_key])
+ {
+ std::cout << name_key << ' ' << vars[name_key] << " got " << got
+ << " expected " << vars[output_key] << std::endl;
+ return false;
+ }
+ return true;
+ });
+ }
+
+size_t run_all_tests()
+ {
+ std::vector<test_fn> all_tests;
+
+ all_tests.push_back(test_block);
+ all_tests.push_back(test_stream);
+ all_tests.push_back(test_hash);
+ all_tests.push_back(test_mac);
+
+ all_tests.push_back(test_modes);
+
+ all_tests.push_back(test_aead);
+ all_tests.push_back(test_ocb);
+ all_tests.push_back(test_eax);
+
+ all_tests.push_back(test_pbkdf);
+ all_tests.push_back(test_kdf);
+ all_tests.push_back(test_hkdf);
+ all_tests.push_back(test_keywrap);
+ all_tests.push_back(test_transform);
+
+ all_tests.push_back(test_rngs);
+ all_tests.push_back(test_passhash9);
+ all_tests.push_back(test_bcrypt);
+ all_tests.push_back(test_cryptobox);
+
+ all_tests.push_back(test_bigint);
+ all_tests.push_back(test_pubkey);
+
+ all_tests.push_back(test_ecc);
+ all_tests.push_back(test_ecdsa);
+ all_tests.push_back(test_ecdh);
+ all_tests.push_back(test_pk_keygen);
+ all_tests.push_back(test_cvc);
+ all_tests.push_back(test_x509);
+ all_tests.push_back(test_tls);
+
+ return run_tests(all_tests);
+ }
diff --git a/src/tests/tests.h b/src/tests/tests.h
new file mode 100644
index 000000000..cb1e0f585
--- /dev/null
+++ b/src/tests/tests.h
@@ -0,0 +1,77 @@
+
+#ifndef BOTAN_TESTS_H__
+#define BOTAN_TESTS_H__
+
+#include <functional>
+#include <istream>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "../common.h"
+
+size_t run_tests_bb(std::istream& src,
+ const std::string& name_key,
+ const std::string& output_key,
+ bool clear_between_cb,
+ std::function<bool (std::map<std::string, std::string>)> cb);
+
+size_t run_tests(std::istream& src,
+ const std::string& name_key,
+ const std::string& output_key,
+ bool clear_between_cb,
+ std::function<std::string (std::map<std::string, std::string>)> cb);
+
+// Run a list of tests
+typedef std::function<size_t ()> test_fn;
+
+size_t run_tests(const std::vector<test_fn>& tests);
+void test_report(const std::string& name, size_t ran, size_t failed);
+
+#define TEST(expr, msg) do { if(!(expr)) { ++fails; std::cout << msg; } while(0)
+
+#define CHECKS_DIR "src/test-data/"
+
+size_t run_all_tests();
+
+// Tests using reader framework above
+size_t test_block();
+size_t test_stream();
+size_t test_hash();
+size_t test_mac();
+
+size_t test_modes();
+
+size_t test_rngs();
+
+size_t test_hkdf();
+size_t test_pbkdf();
+size_t test_kdf();
+size_t test_aead();
+size_t test_transform();
+
+// One off tests
+size_t test_ocb();
+size_t test_eax();
+size_t test_keywrap();
+size_t test_bcrypt();
+size_t test_passhash9();
+size_t test_cryptobox();
+
+size_t test_bigint();
+
+size_t test_pubkey();
+size_t test_pk_keygen();
+
+size_t test_ecc();
+
+size_t test_ecdsa();
+size_t test_ecdh();
+
+size_t test_x509();
+size_t test_cvc();
+
+size_t test_tls();
+size_t test_nist_x509();
+
+#endif