📄 pk.cpp
字号:
/* This file is in the public domain */#include <iostream>#include <fstream>#include <cctype>#include <string>#include <vector>#include <cstdio>#include <botan/rsa.h>#include <botan/rw.h>#include <botan/elgamal.h>#include <botan/dsa.h>#include <botan/nr.h>#include <botan/dh.h>#include <botan/look_pk.h>#include <botan/randpool.h>#include <botan/rng.h>using namespace Botan;SecureVector<byte> decode_hex(const std::string&);BigInt to_bigint(const std::string&);#define DEBUG 0class Fixed_Output_RNG : public RandomNumberGenerator { public: byte random() { if(position < output.size()) return output[position++]; else return 42; } void clear() throw() {} std::string name() const { return "Fixed Output RNG"; } void add_randomness(const byte[], u32bit) throw() {} Fixed_Output_RNG(const SecureVector<byte>& x) { output = x; position = 0; } private: SecureVector<byte> output; u32bit position; };std::vector<std::string> parse(const std::string&);void strip(std::string&);u32bit validate_dsa_sig(const std::string&, const std::vector<std::string>&);u32bit validate_rsa_enc(const std::string&, const std::vector<std::string>&);u32bit validate_rsa_sig(const std::string&, const std::vector<std::string>&);u32bit validate_rsa_ver(const std::string&, const std::vector<std::string>&);u32bit validate_rw_sig(const std::string&, const std::vector<std::string>&);u32bit validate_nr_sig(const std::string&, const std::vector<std::string>&);u32bit validate_elg_enc(const std::string&, const std::vector<std::string>&);u32bit validate_dh(const std::string&, const std::vector<std::string>&);u32bit do_pk_validation_tests(const std::string& filename) { std::ifstream test_data(filename.c_str()); if(!test_data) { std::cout << "Couldn't open test file " << filename << std::endl; std::exit(1); } u32bit errors = 0, alg_count = 0; std::string algorithm; while(!test_data.eof()) { if(test_data.bad() || test_data.fail()) { std::cout << "File I/O error." << std::endl; std::exit(1); } 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(algorithm != "") std::cout << std::endl; algorithm = line.substr(1, line.size() - 2); std::cout << "Testing " << algorithm << ": "; alg_count = 0; continue; } std::cout << "."; std::cout.flush(); std::vector<std::string> substr = parse(line);#if DEBUG std::cout << "Testing: " << algorithm << std::endl;#endif u32bit new_errors = 0; if(algorithm.find("DSA/") != std::string::npos) new_errors = validate_dsa_sig(algorithm, substr); else if(algorithm.find("NR/") != std::string::npos) new_errors = validate_nr_sig(algorithm, substr); else if(algorithm.find("RSAES/") != std::string::npos) new_errors = validate_rsa_enc(algorithm, substr); else if(algorithm.find("RSASSA/") != std::string::npos) new_errors = validate_rsa_sig(algorithm, substr); else if(algorithm.find("RSAVA/") != std::string::npos) new_errors = validate_rsa_ver(algorithm, substr); else if(algorithm.find("RWSSA/") != std::string::npos) new_errors = validate_rw_sig(algorithm, substr); else if(algorithm.find("ElGamal/") != std::string::npos) new_errors = validate_elg_enc(algorithm, substr); else if(algorithm.find("DHKAS/") != std::string::npos) new_errors = validate_dh(algorithm, substr); else std::cout << "WARNING: Unknown PK algorithm " << algorithm << std::endl; alg_count++; errors += new_errors; if(new_errors) std::cout << "ERROR: \"" << algorithm << "\" failed test #" << std::dec << alg_count << std::endl; } std::cout << std::endl; // reset the global rng, because validate_xxx will have replaced it set_global_rng(new Randpool); return errors; }void dump_data(const SecureVector<byte>& out, const SecureVector<byte>& expected) { // For whatever reason, I cannot figure out how to do this with cout... std::printf("Got: "); for(u32bit j = 0; j != out.size(); j++) std::printf("%02X", out[j]); std::printf("\nExp: "); for(u32bit j = 0; j != expected.size(); j++) std::printf("%02X", expected[j]); std::printf("\n"); std::fflush(stdout); }void validate_decryption(PK_Decryptor* d, const std::string& algo, const SecureVector<byte> ctext, const SecureVector<byte> ptext, bool& failure) { SecureVector<byte> decrypted = d->decrypt(ctext); if(decrypted != ptext) { std::cout << "FAILED (decrypt): " << algo << std::endl; dump_data(decrypted, ptext); failure = true; } delete d; }void validate_encryption(PK_Encryptor* e, PK_Decryptor* d, const std::string& algo, const std::string& input, const std::string& random, const std::string& exp, bool& failure) { SecureVector<byte> message = decode_hex(input); set_global_rng(new Fixed_Output_RNG(decode_hex(random))); SecureVector<byte> expected = decode_hex(exp); SecureVector<byte> out = e->encrypt(message); if(out != expected) { std::cout << "FAILED (encrypt): " << algo << std::endl; dump_data(out, expected); failure = true; } validate_decryption(d, algo, out, message, failure); delete e; }void validate_signature(PK_Verifier* v, PK_Signer* s, const std::string& algo, const std::string& input, const std::string& random, const std::string& exp, bool& failure) { SecureVector<byte> message = decode_hex(input); set_global_rng(new Fixed_Output_RNG(decode_hex(random))); SecureVector<byte> expected = decode_hex(exp); SecureVector<byte> sig = s->sign_message(message, message.size()); if(sig != expected) { std::cout << "FAILED (sign): " << algo << std::endl; dump_data(sig, expected); failure = true; } if(!v->verify_message(message, message.size(), sig, sig.size())) { std::cout << "FAILED (verify): " << algo << std::endl; failure = true; } /* This isn't a very thorough testing method, but it will hopefully catch any really horrible errors */ sig[sig.size()-5]++; if(v->verify_message(message, message.size(), sig, sig.size())) { std::cout << "FAILED (accepted bad sig): " << algo << std::endl; failure = true; }#if 0 delete v; delete s;#endif }void validate_kas(PK_Key_Agreement_Scheme* kas, const std::string& algo, const SecureVector<byte>& pubkey, const std::string& output, u32bit keylen, bool& failure) { SecureVector<byte> expected = decode_hex(output); SecureVector<byte> got = kas->derive_key(pubkey, keylen).copy(); if(got != expected) { std::cout << "FAILED: " << algo << std::endl; dump_data(got, expected); failure = true; } delete kas; }u32bit validate_rsa_enc(const std::string& algo, const std::vector<std::string>& str) { if(str.size() != 6) throw Exception("Invalid input from pk_valid.dat"); RSA_PrivateKey privkey(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* e = get_pk_encryptor(pubkey, eme); PK_Decryptor* d = get_pk_decryptor(privkey, eme); bool failure = false; validate_encryption(e, d, algo, str[3], str[4], str[5], failure); return (failure ? 1 : 0); }u32bit validate_elg_enc(const std::string& algo, const std::vector<std::string>& str) { if(str.size() != 6 && str.size() != 7) throw Exception("Invalid input from pk_valid.dat"); DL_Group domain(to_bigint(str[0]), to_bigint(str[1])); ElGamal_PrivateKey privkey(domain, to_bigint(str[2]), to_bigint(str[3])); ElGamal_PublicKey pubkey = privkey; std::string eme = algo.substr(8, std::string::npos); PK_Decryptor* d = get_pk_decryptor(privkey, eme); bool failure = false; if(str.size() == 7) { PK_Encryptor* e = get_pk_encryptor(pubkey, eme); validate_encryption(e, d, algo, str[4], str[5], str[6], failure); } else validate_decryption(d, algo, decode_hex(str[5]), decode_hex(str[4]), failure); return (failure ? 1 : 0); }u32bit validate_rsa_sig(const std::string& algo, const std::vector<std::string>& str) { if(str.size() != 6) throw Exception("Invalid input from pk_valid.dat"); RSA_PrivateKey privkey(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 = get_pk_verifier(pubkey, emsa); PK_Signer* s = get_pk_signer(privkey, emsa); bool failure = false; validate_signature(v, s, algo, str[3], str[4], str[5], failure); return (failure ? 1 : 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 Exception("Invalid input from pk_valid.dat"); RSA_PublicKey key(to_bigint(str[1]), to_bigint(str[0])); std::string emsa = algo.substr(6, std::string::npos); PK_Verifier* v = get_pk_verifier(key, emsa); SecureVector<byte> msg = decode_hex(str[2]); SecureVector<byte> sig = decode_hex(str[3]); bool passed = v->verify_message(msg, msg.size(), sig, sig.size()); delete v; return (passed ? 0 : 1); }u32bit validate_rw_sig(const std::string& algo, const std::vector<std::string>& str) { if(str.size() != 6) throw Exception("Invalid input from pk_valid.dat"); RW_PrivateKey privkey(to_bigint(str[1]), to_bigint(str[2]), to_bigint(str[0])); RW_PublicKey pubkey = privkey; std::string emsa = algo.substr(6, std::string::npos); PK_Verifier* v = get_pk_verifier(pubkey, emsa); PK_Signer* s = get_pk_signer(privkey, emsa); bool failure = false; validate_signature(v, s, algo, str[3], str[4], str[5], failure); return (failure ? 1 : 0); }u32bit validate_dsa_sig(const std::string& algo, const std::vector<std::string>& str) { if(str.size() != 8) throw Exception("Invalid input from pk_valid.dat"); DL_Group domain(to_bigint(str[0]), to_bigint(str[1]), to_bigint(str[2])); DSA_PrivateKey privkey(domain, to_bigint(str[4]), to_bigint(str[3])); DSA_PublicKey pubkey = privkey; std::string emsa = algo.substr(4, std::string::npos); PK_Verifier* v = get_pk_verifier(pubkey, emsa); PK_Signer* s = get_pk_signer(privkey, emsa); bool failure = false; validate_signature(v, s, algo, str[5], str[6], str[7], failure); return (failure ? 1 : 0); }u32bit validate_nr_sig(const std::string& algo, const std::vector<std::string>& str) { if(str.size() != 8) throw Exception("Invalid input from pk_valid.dat"); DL_Group domain(to_bigint(str[0]), to_bigint(str[1]), to_bigint(str[2])); NR_PrivateKey privkey(domain, to_bigint(str[4]), to_bigint(str[3])); NR_PublicKey pubkey = privkey; std::string emsa = algo.substr(3, std::string::npos); PK_Verifier* v = get_pk_verifier(pubkey, emsa); PK_Signer* s = get_pk_signer(privkey, emsa); bool failure = false; validate_signature(v, s, algo, str[5], str[6], str[7], failure); return (failure ? 1 : 0); }u32bit validate_dh(const std::string& algo, const std::vector<std::string>& str) { if(str.size() != 5 && str.size() != 6) throw Exception("Invalid input from pk_valid.dat"); DL_Group domain(to_bigint(str[0]), to_bigint(str[1])); DH_PrivateKey mykey(domain, to_bigint(str[2])); DH_PublicKey otherkey(domain, to_bigint(str[3])); std::string kdf = algo.substr(6, std::string::npos); u32bit keylen = 0; if(str.size() == 6) keylen = to_u32bit(str[5]); PK_Key_Agreement_Scheme* kas = get_pk_kas(mykey, kdf); bool failure = false; validate_kas(kas, algo, otherkey.public_value(), str[4], keylen, failure); return (failure ? 1 : 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -