aboutsummaryrefslogtreecommitdiffstats
path: root/src/tests/test_pubkey.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/test_pubkey.cpp')
-rw-r--r--src/tests/test_pubkey.cpp396
1 files changed, 396 insertions, 0 deletions
diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp
new file mode 100644
index 000000000..85e2924be
--- /dev/null
+++ b/src/tests/test_pubkey.cpp
@@ -0,0 +1,396 @@
+/*
+* (C) 2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include "tests.h"
+#include "test_rng.h"
+#include "test_pubkey.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 {
+
+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;
+ }
+
+byte nonzero_byte(RandomNumberGenerator& rng)
+ {
+ byte b = 0;
+ while(b == 0)
+ b = rng.next_byte();
+ return b;
+ }
+
+}
+
+#define PK_TEST(expr, msg) \
+ do { \
+ const bool test_result = expr; \
+ if(!test_result) \
+ { \
+ std::cout << "Test " << #expr << " failed: " << msg << "\n"; \
+ ++fails; \
+ } \
+ } while(0)
+
+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;
+
+ const std::vector<byte> ctext = e.encrypt(message, rng);
+ if(ctext != expected)
+ {
+ std::cout << "FAILED (encrypt): " << algo << std::endl;
+ dump_data(ctext, expected);
+ ++fails;
+ }
+
+ std::vector<byte> decrypted = unlock(d.decrypt(ctext));
+
+ if(decrypted != message)
+ {
+ std::cout << "FAILED (decrypt): " << algo << std::endl;
+ dump_data(decrypted, message);
+ ++fails;
+ }
+
+ if(algo.find("/Raw") == std::string::npos)
+ {
+ AutoSeeded_RNG rng;
+
+ for(size_t i = 0; i != ctext.size(); ++i)
+ {
+ std::vector<byte> bad_ctext = ctext;
+
+ bad_ctext[i] ^= nonzero_byte(rng);
+
+ BOTAN_ASSERT(bad_ctext != ctext, "Made them different");
+
+ try
+ {
+ auto bad_ptext = unlock(d.decrypt(bad_ctext));
+ std::cout << algo << " failed - decrypted bad data\n";
+ std::cout << hex_encode(bad_ctext) << " -> " << hex_encode(bad_ptext) << "\n";
+ std::cout << hex_encode(ctext) << " -> " << hex_encode(decrypted) << "\n";
+ ++fails;
+ }
+ catch(...) {}
+ }
+ }
+
+ 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)
+ {
+ return validate_signature(v, s, algo, input, rng, rng, exp);
+ }
+
+size_t validate_signature(PK_Verifier& v, PK_Signer& s, const std::string& algo,
+ const std::string& input,
+ RandomNumberGenerator& signer_rng,
+ RandomNumberGenerator& test_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, signer_rng);
+
+ size_t fails = 0;
+
+ if(sig != expected)
+ {
+ std::cout << "FAILED (sign): " << algo << std::endl;
+ dump_data(sig, expected);
+ ++fails;
+ }
+
+ PK_TEST(v.verify_message(message, sig), "Correct signature is valid");
+
+ zero_mem(&sig[0], sig.size());
+
+ PK_TEST(!v.verify_message(message, sig), "All-zero signature is invalid");
+
+ for(size_t i = 0; i != 3; ++i)
+ {
+ auto bad_sig = sig;
+
+ const size_t idx = (test_rng.next_byte() * 256 + test_rng.next_byte()) % sig.size();
+ bad_sig[idx] ^= nonzero_byte(test_rng);
+
+ PK_TEST(!v.verify_message(message, bad_sig), "Incorrect signature is invalid");
+ }
+
+ 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& random,
+ const std::string& exp)
+ {
+ Fixed_Output_RNG fixed_rng(hex_decode(random));
+
+ return validate_signature(v, s, algo, input, fixed_rng, rng, exp);
+ }
+
+size_t validate_kas(PK_Key_Agreement& kas, const std::string& algo,
+ const std::vector<byte>& pubkey, const std::string& output,
+ size_t 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 test_pk_keygen()
+ {
+ AutoSeeded_RNG rng;
+
+ size_t tests = 0;
+ size_t fails = 0;
+
+#define DL_KEY(TYPE, GROUP) \
+ { \
+ TYPE key(rng, DL_Group(GROUP)); \
+ key.check_key(rng, true); \
+ ++tests; \
+ 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); \
+ ++tests; \
+ fails += validate_save_and_load(&key, rng); \
+ }
+
+#if defined(BOTAN_HAS_RSA)
+ {
+ RSA_PrivateKey rsa1024(rng, 1024);
+ rsa1024.check_key(rng, true);
+ ++tests;
+ fails += validate_save_and_load(&rsa1024, rng);
+
+ RSA_PrivateKey rsa2048(rng, 2048);
+ rsa2048.check_key(rng, true);
+ ++tests;
+ fails += validate_save_and_load(&rsa2048, rng);
+ }
+#endif
+
+#if defined(BOTAN_HAS_RW)
+ {
+ RW_PrivateKey rw1024(rng, 1024);
+ rw1024.check_key(rng, true);
+ ++tests;
+ 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
+
+ test_report("PK keygen", tests, fails);
+
+ return fails;
+ }