aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pubkey/pubkey.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/pubkey/pubkey.cpp')
-rw-r--r--src/lib/pubkey/pubkey.cpp386
1 files changed, 386 insertions, 0 deletions
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp
new file mode 100644
index 000000000..313d54c16
--- /dev/null
+++ b/src/lib/pubkey/pubkey.cpp
@@ -0,0 +1,386 @@
+/*
+* Public Key Base
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/pubkey.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/bigint.h>
+#include <botan/parsing.h>
+#include <botan/libstate.h>
+#include <botan/engine.h>
+#include <botan/lookup.h>
+#include <botan/internal/bit_ops.h>
+#include <memory>
+
+namespace Botan {
+
+/*
+* PK_Encryptor_EME Constructor
+*/
+PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key,
+ const std::string& eme_name)
+ {
+ Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());
+ RandomNumberGenerator& rng = global_state().global_rng();
+
+ while(const Engine* engine = i.next())
+ {
+ op = engine->get_encryption_op(key, rng);
+ if(op)
+ break;
+ }
+
+ if(!op)
+ throw Lookup_Error("Encryption with " + key.algo_name() + " not supported");
+
+ eme = (eme_name == "Raw") ? nullptr : get_eme(eme_name);
+ }
+
+/*
+* Encrypt a message
+*/
+std::vector<byte>
+PK_Encryptor_EME::enc(const byte in[],
+ size_t length,
+ RandomNumberGenerator& rng) const
+ {
+ if(eme)
+ {
+ secure_vector<byte> encoded =
+ eme->encode(in, length, op->max_input_bits(), rng);
+
+ if(8*(encoded.size() - 1) + high_bit(encoded[0]) > op->max_input_bits())
+ throw Invalid_Argument("PK_Encryptor_EME: Input is too large");
+
+ return unlock(op->encrypt(&encoded[0], encoded.size(), rng));
+ }
+ else
+ {
+ if(8*(length - 1) + high_bit(in[0]) > op->max_input_bits())
+ throw Invalid_Argument("PK_Encryptor_EME: Input is too large");
+
+ return unlock(op->encrypt(&in[0], length, rng));
+ }
+ }
+
+/*
+* Return the max size, in bytes, of a message
+*/
+size_t PK_Encryptor_EME::maximum_input_size() const
+ {
+ if(!eme)
+ return (op->max_input_bits() / 8);
+ else
+ return eme->maximum_input_size(op->max_input_bits());
+ }
+
+/*
+* PK_Decryptor_EME Constructor
+*/
+PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key,
+ const std::string& eme_name)
+ {
+ Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());
+ RandomNumberGenerator& rng = global_state().global_rng();
+
+ while(const Engine* engine = i.next())
+ {
+ op = engine->get_decryption_op(key, rng);
+ if(op)
+ break;
+ }
+
+ if(!op)
+ throw Lookup_Error("Decryption with " + key.algo_name() + " not supported");
+
+ eme = (eme_name == "Raw") ? nullptr : get_eme(eme_name);
+ }
+
+/*
+* Decrypt a message
+*/
+secure_vector<byte> PK_Decryptor_EME::dec(const byte msg[],
+ size_t length) const
+ {
+ try {
+ secure_vector<byte> decrypted = op->decrypt(msg, length);
+ if(eme)
+ return eme->decode(decrypted, op->max_input_bits());
+ else
+ return decrypted;
+ }
+ catch(Invalid_Argument)
+ {
+ throw Decoding_Error("PK_Decryptor_EME: Input is invalid");
+ }
+ }
+
+/*
+* PK_Signer Constructor
+*/
+PK_Signer::PK_Signer(const Private_Key& key,
+ const std::string& emsa_name,
+ Signature_Format format,
+ Fault_Protection prot)
+ {
+ Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());
+ RandomNumberGenerator& rng = global_state().global_rng();
+
+ op = nullptr;
+ verify_op = nullptr;
+
+ while(const Engine* engine = i.next())
+ {
+ if(!op)
+ op = engine->get_signature_op(key, rng);
+
+ if(!verify_op && prot == ENABLE_FAULT_PROTECTION)
+ verify_op = engine->get_verify_op(key, rng);
+
+ if(op && (verify_op || prot == DISABLE_FAULT_PROTECTION))
+ break;
+ }
+
+ if(!op || (!verify_op && prot == ENABLE_FAULT_PROTECTION))
+ throw Lookup_Error("Signing with " + key.algo_name() + " not supported");
+
+ emsa = get_emsa(emsa_name);
+ sig_format = format;
+ }
+
+/*
+* Sign a message
+*/
+std::vector<byte> PK_Signer::sign_message(const byte msg[], size_t length,
+ RandomNumberGenerator& rng)
+ {
+ update(msg, length);
+ return signature(rng);
+ }
+
+/*
+* Add more to the message to be signed
+*/
+void PK_Signer::update(const byte in[], size_t length)
+ {
+ emsa->update(in, length);
+ }
+
+/*
+* Check the signature we just created, to help prevent fault attacks
+*/
+bool PK_Signer::self_test_signature(const std::vector<byte>& msg,
+ const std::vector<byte>& sig) const
+ {
+ if(!verify_op)
+ return true; // checking disabled, assume ok
+
+ if(verify_op->with_recovery())
+ {
+ std::vector<byte> recovered =
+ unlock(verify_op->verify_mr(&sig[0], sig.size()));
+
+ if(msg.size() > recovered.size())
+ {
+ size_t extra_0s = msg.size() - recovered.size();
+
+ for(size_t i = 0; i != extra_0s; ++i)
+ if(msg[i] != 0)
+ return false;
+
+ return same_mem(&msg[extra_0s], &recovered[0], recovered.size());
+ }
+
+ return (recovered == msg);
+ }
+ else
+ return verify_op->verify(&msg[0], msg.size(),
+ &sig[0], sig.size());
+ }
+
+/*
+* Create a signature
+*/
+std::vector<byte> PK_Signer::signature(RandomNumberGenerator& rng)
+ {
+ std::vector<byte> encoded = unlock(emsa->encoding_of(emsa->raw_data(),
+ op->max_input_bits(),
+ rng));
+
+ std::vector<byte> plain_sig = unlock(op->sign(&encoded[0], encoded.size(), rng));
+
+ BOTAN_ASSERT(self_test_signature(encoded, plain_sig), "Signature was consistent");
+
+ if(op->message_parts() == 1 || sig_format == IEEE_1363)
+ return plain_sig;
+
+ if(sig_format == DER_SEQUENCE)
+ {
+ if(plain_sig.size() % op->message_parts())
+ throw Encoding_Error("PK_Signer: strange signature size found");
+ const size_t SIZE_OF_PART = plain_sig.size() / op->message_parts();
+
+ std::vector<BigInt> sig_parts(op->message_parts());
+ for(size_t j = 0; j != sig_parts.size(); ++j)
+ sig_parts[j].binary_decode(&plain_sig[SIZE_OF_PART*j], SIZE_OF_PART);
+
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode_list(sig_parts)
+ .end_cons()
+ .get_contents_unlocked();
+ }
+ else
+ throw Encoding_Error("PK_Signer: Unknown signature format " +
+ std::to_string(sig_format));
+ }
+
+/*
+* PK_Verifier Constructor
+*/
+PK_Verifier::PK_Verifier(const Public_Key& key,
+ const std::string& emsa_name,
+ Signature_Format format)
+ {
+ Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());
+ RandomNumberGenerator& rng = global_state().global_rng();
+
+ while(const Engine* engine = i.next())
+ {
+ op = engine->get_verify_op(key, rng);
+ if(op)
+ break;
+ }
+
+ if(!op)
+ throw Lookup_Error("Verification with " + key.algo_name() + " not supported");
+
+ emsa = get_emsa(emsa_name);
+ sig_format = format;
+ }
+
+/*
+* Set the signature format
+*/
+void PK_Verifier::set_input_format(Signature_Format format)
+ {
+ if(op->message_parts() == 1 && format != IEEE_1363)
+ throw Invalid_State("PK_Verifier: This algorithm always uses IEEE 1363");
+ sig_format = format;
+ }
+
+/*
+* Verify a message
+*/
+bool PK_Verifier::verify_message(const byte msg[], size_t msg_length,
+ const byte sig[], size_t sig_length)
+ {
+ update(msg, msg_length);
+ return check_signature(sig, sig_length);
+ }
+
+/*
+* Append to the message
+*/
+void PK_Verifier::update(const byte in[], size_t length)
+ {
+ emsa->update(in, length);
+ }
+
+/*
+* Check a signature
+*/
+bool PK_Verifier::check_signature(const byte sig[], size_t length)
+ {
+ try {
+ if(sig_format == IEEE_1363)
+ return validate_signature(emsa->raw_data(), sig, length);
+ else if(sig_format == DER_SEQUENCE)
+ {
+ BER_Decoder decoder(sig, length);
+ BER_Decoder ber_sig = decoder.start_cons(SEQUENCE);
+
+ size_t count = 0;
+ std::vector<byte> real_sig;
+ while(ber_sig.more_items())
+ {
+ BigInt sig_part;
+ ber_sig.decode(sig_part);
+ real_sig += BigInt::encode_1363(sig_part, op->message_part_size());
+ ++count;
+ }
+
+ if(count != op->message_parts())
+ throw Decoding_Error("PK_Verifier: signature size invalid");
+
+ return validate_signature(emsa->raw_data(),
+ &real_sig[0], real_sig.size());
+ }
+ else
+ throw Decoding_Error("PK_Verifier: Unknown signature format " +
+ std::to_string(sig_format));
+ }
+ catch(Invalid_Argument) { return false; }
+ }
+
+/*
+* Verify a signature
+*/
+bool PK_Verifier::validate_signature(const secure_vector<byte>& msg,
+ const byte sig[], size_t sig_len)
+ {
+ if(op->with_recovery())
+ {
+ secure_vector<byte> output_of_key = op->verify_mr(sig, sig_len);
+ return emsa->verify(output_of_key, msg, op->max_input_bits());
+ }
+ else
+ {
+ RandomNumberGenerator& rng = global_state().global_rng();
+
+ secure_vector<byte> encoded =
+ emsa->encoding_of(msg, op->max_input_bits(), rng);
+
+ return op->verify(&encoded[0], encoded.size(), sig, sig_len);
+ }
+ }
+
+/*
+* PK_Key_Agreement Constructor
+*/
+PK_Key_Agreement::PK_Key_Agreement(const PK_Key_Agreement_Key& key,
+ const std::string& kdf_name)
+ {
+ Algorithm_Factory::Engine_Iterator i(global_state().algorithm_factory());
+ RandomNumberGenerator& rng = global_state().global_rng();
+
+ while(const Engine* engine = i.next())
+ {
+ op = engine->get_key_agreement_op(key, rng);
+ if(op)
+ break;
+ }
+
+ if(!op)
+ throw Lookup_Error("Key agreement with " + key.algo_name() + " not supported");
+
+ kdf = (kdf_name == "Raw") ? nullptr : get_kdf(kdf_name);
+ }
+
+SymmetricKey PK_Key_Agreement::derive_key(size_t key_len, const byte in[],
+ size_t in_len, const byte params[],
+ size_t params_len) const
+ {
+ secure_vector<byte> z = op->agree(in, in_len);
+
+ if(!kdf)
+ return z;
+
+ return kdf->derive_key(key_len, z, params, params_len);
+ }
+
+}