/* * Public Key Interface * (C) 1999-2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #ifndef BOTAN_PUBKEY_H__ #define BOTAN_PUBKEY_H__ #include #include #include #include #include #include #include #if defined(BOTAN_HAS_SYSTEM_RNG) #include #define BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS #endif namespace Botan { /** * The two types of signature format supported by Botan. */ enum Signature_Format { IEEE_1363, DER_SEQUENCE }; /** * Public Key Encryptor */ class BOTAN_DLL PK_Encryptor { public: /** * Encrypt a message. * @param in the message as a byte array * @param length the length of the above byte array * @param rng the random number source to use * @return encrypted message */ std::vector encrypt(const byte in[], size_t length, RandomNumberGenerator& rng) const { return enc(in, length, rng); } /** * Encrypt a message. * @param in the message * @param rng the random number source to use * @return encrypted message */ template std::vector encrypt(const std::vector& in, RandomNumberGenerator& rng) const { return enc(in.data(), in.size(), rng); } /** * Return the maximum allowed message size in bytes. * @return maximum message size in bytes */ virtual size_t maximum_input_size() const = 0; PK_Encryptor() {} virtual ~PK_Encryptor() {} PK_Encryptor(const PK_Encryptor&) = delete; PK_Encryptor& operator=(const PK_Encryptor&) = delete; private: virtual std::vector enc(const byte[], size_t, RandomNumberGenerator&) const = 0; }; /** * Public Key Decryptor */ class BOTAN_DLL PK_Decryptor { public: /** * Decrypt a ciphertext, throwing an exception if the input * seems to be invalid (eg due to an accidental or malicious * error in the ciphertext). * * @param in the ciphertext as a byte array * @param length the length of the above byte array * @return decrypted message */ secure_vector decrypt(const byte in[], size_t length) const; /** * Same as above, but taking a vector * @param in the ciphertext * @return decrypted message */ template secure_vector decrypt(const std::vector& in) const { return decrypt(in.data(), in.size()); } /** * Decrypt a ciphertext. If the ciphertext is invalid (eg due to * invalid padding) or is not the expected length, instead * returns a random string of the expected length. Use to avoid * oracle attacks, especially against PKCS #1 v1.5 decryption. */ secure_vector decrypt_or_random(const byte in[], size_t length, size_t expected_pt_len, RandomNumberGenerator& rng) const; /** * Decrypt a ciphertext. If the ciphertext is invalid (eg due to * invalid padding) or is not the expected length, instead * returns a random string of the expected length. Use to avoid * oracle attacks, especially against PKCS #1 v1.5 decryption. * * Additionally checks (also in const time) that: * contents[required_content_offsets[i]] == required_content_bytes[i] * for 0 <= i < required_contents * * Used for example in TLS, which encodes the client version in * the content bytes: if there is any timing variation the version * check can be used as an oracle to recover the key. */ secure_vector decrypt_or_random(const byte in[], size_t length, size_t expected_pt_len, RandomNumberGenerator& rng, const byte required_content_bytes[], const byte required_content_offsets[], size_t required_contents) const; PK_Decryptor() {} virtual ~PK_Decryptor() = default; PK_Decryptor(const PK_Decryptor&) = delete; PK_Decryptor& operator=(const PK_Decryptor&) = delete; private: virtual secure_vector do_decrypt(byte& valid_mask, const byte in[], size_t in_len) const = 0; }; /** * Public Key Signer. Use the sign_message() functions for small * messages. Use multiple calls update() to process large messages and * generate the signature by finally calling signature(). */ class BOTAN_DLL PK_Signer final { public: /** * Construct a PK Signer. * @param key the key to use inside this signer * @param emsa the EMSA to use * An example would be "EMSA1(SHA-224)". * @param format the signature format to use */ PK_Signer(const Private_Key& key, RandomNumberGenerator& rng, const std::string& emsa, Signature_Format format = IEEE_1363, const std::string& provider = ""); #if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) /** * Construct a PK Signer. * @param key the key to use inside this signer * @param emsa the EMSA to use * An example would be "EMSA1(SHA-224)". * @param format the signature format to use */ BOTAN_DEPRECATED("Use constructor taking a RNG object") PK_Signer(const Private_Key& key, const std::string& emsa, Signature_Format format = IEEE_1363, const std::string& provider = "") : PK_Signer(key, system_rng(), emsa, format, provider) {} #endif ~PK_Signer(); PK_Signer(const PK_Signer&) = delete; PK_Signer& operator=(const PK_Signer&) = delete; /** * Sign a message all in one go * @param in the message to sign as a byte array * @param length the length of the above byte array * @param rng the rng to use * @return signature */ std::vector sign_message(const byte in[], size_t length, RandomNumberGenerator& rng) { this->update(in, length); return this->signature(rng); } /** * Sign a message. * @param in the message to sign * @param rng the rng to use * @return signature */ std::vector sign_message(const std::vector& in, RandomNumberGenerator& rng) { return sign_message(in.data(), in.size(), rng); } std::vector sign_message(const secure_vector& in, RandomNumberGenerator& rng) { return sign_message(in.data(), in.size(), rng); } /** * Add a message part (single byte). * @param in the byte to add */ void update(byte in) { update(&in, 1); } /** * Add a message part. * @param in the message part to add as a byte array * @param length the length of the above byte array */ void update(const byte in[], size_t length); /** * Add a message part. * @param in the message part to add */ void update(const std::vector& in) { update(in.data(), in.size()); } /** * Add a message part. * @param in the message part to add */ void update(const std::string& in) { update(reinterpret_cast(in.data()), in.size()); } /** * Get the signature of the so far processed message (provided by the * calls to update()). * @param rng the rng to use * @return signature of the total message */ std::vector signature(RandomNumberGenerator& rng); /** * Set the output format of the signature. * @param format the signature format to use */ void set_output_format(Signature_Format format) { m_sig_format = format; } private: std::unique_ptr m_op; Signature_Format m_sig_format; }; /** * Public Key Verifier. Use the verify_message() functions for small * messages. Use multiple calls update() to process large messages and * verify the signature by finally calling check_signature(). */ class BOTAN_DLL PK_Verifier final { public: /** * Construct a PK Verifier. * @param pub_key the public key to verify against * @param emsa the EMSA to use (eg "EMSA3(SHA-1)") * @param format the signature format to use */ PK_Verifier(const Public_Key& pub_key, const std::string& emsa, Signature_Format format = IEEE_1363, const std::string& provider = ""); ~PK_Verifier(); PK_Verifier& operator=(const PK_Verifier&) = delete; PK_Verifier(const PK_Verifier&) = delete; /** * Verify a signature. * @param msg the message that the signature belongs to, as a byte array * @param msg_length the length of the above byte array msg * @param sig the signature as a byte array * @param sig_length the length of the above byte array sig * @return true if the signature is valid */ bool verify_message(const byte msg[], size_t msg_length, const byte sig[], size_t sig_length); /** * Verify a signature. * @param msg the message that the signature belongs to * @param sig the signature * @return true if the signature is valid */ template bool verify_message(const std::vector& msg, const std::vector& sig) { return verify_message(msg.data(), msg.size(), sig.data(), sig.size()); } /** * Add a message part (single byte) of the message corresponding to the * signature to be verified. * @param in the byte to add */ void update(byte in) { update(&in, 1); } /** * Add a message part of the message corresponding to the * signature to be verified. * @param msg_part the new message part as a byte array * @param length the length of the above byte array */ void update(const byte msg_part[], size_t length); /** * Add a message part of the message corresponding to the * signature to be verified. * @param in the new message part */ void update(const std::vector& in) { update(in.data(), in.size()); } /** * Add a message part of the message corresponding to the * signature to be verified. */ void update(const std::string& in) { update(reinterpret_cast(in.data()), in.size()); } /** * Check the signature of the buffered message, i.e. the one build * by successive calls to update. * @param sig the signature to be verified as a byte array * @param length the length of the above byte array * @return true if the signature is valid, false otherwise */ bool check_signature(const byte sig[], size_t length); /** * Check the signature of the buffered message, i.e. the one build * by successive calls to update. * @param sig the signature to be verified * @return true if the signature is valid, false otherwise */ template bool check_signature(const std::vector& sig) { return check_signature(sig.data(), sig.size()); } /** * Set the format of the signatures fed to this verifier. * @param format the signature format to use */ void set_input_format(Signature_Format format); private: std::unique_ptr m_op; Signature_Format m_sig_format; }; /** * Key used for key agreement */ class BOTAN_DLL PK_Key_Agreement final { public: /** * Construct a PK Key Agreement. * @param key the key to use * @param kdf name of the KDF to use (or 'Raw' for no KDF) * @param provider the algo provider to use (or empty for default) */ PK_Key_Agreement(const Private_Key& key, RandomNumberGenerator& rng, const std::string& kdf, const std::string& provider = ""); #if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) /** * Construct a PK Key Agreement. * @param key the key to use * @param kdf name of the KDF to use (or 'Raw' for no KDF) * @param provider the algo provider to use (or empty for default) */ BOTAN_DEPRECATED("Use constructor taking a RNG object") PK_Key_Agreement(const Private_Key& key, const std::string& kdf, const std::string& provider = "") : PK_Key_Agreement(key, system_rng(), kdf, provider) {} #endif ~PK_Key_Agreement(); // For ECIES PK_Key_Agreement& operator=(PK_Key_Agreement&&); PK_Key_Agreement(PK_Key_Agreement&&); PK_Key_Agreement& operator=(const PK_Key_Agreement&) = delete; PK_Key_Agreement(const PK_Key_Agreement&) = delete; /* * Perform Key Agreement Operation * @param key_len the desired key output size * @param in the other parties key * @param in_len the length of in in bytes * @param params extra derivation params * @param params_len the length of params in bytes */ SymmetricKey derive_key(size_t key_len, const byte in[], size_t in_len, const byte params[], size_t params_len) const; /* * Perform Key Agreement Operation * @param key_len the desired key output size * @param in the other parties key * @param in_len the length of in in bytes * @param params extra derivation params * @param params_len the length of params in bytes */ SymmetricKey derive_key(size_t key_len, const std::vector& in, const byte params[], size_t params_len) const { return derive_key(key_len, in.data(), in.size(), params, params_len); } /* * Perform Key Agreement Operation * @param key_len the desired key output size * @param in the other parties key * @param in_len the length of in in bytes * @param params extra derivation params */ SymmetricKey derive_key(size_t key_len, const byte in[], size_t in_len, const std::string& params = "") const { return derive_key(key_len, in, in_len, reinterpret_cast(params.data()), params.length()); } /* * Perform Key Agreement Operation * @param key_len the desired key output size * @param in the other parties key * @param params extra derivation params */ SymmetricKey derive_key(size_t key_len, const std::vector& in, const std::string& params = "") const { return derive_key(key_len, in.data(), in.size(), reinterpret_cast(params.data()), params.length()); } private: std::unique_ptr m_op; }; /** * Encryption using a standard message recovery algorithm like RSA or * ElGamal, paired with an encoding scheme like OAEP. */ class BOTAN_DLL PK_Encryptor_EME final : public PK_Encryptor { public: size_t maximum_input_size() const override; /** * Construct an instance. * @param key the key to use inside the encryptor * @param padding the message encoding scheme to use (eg "OAEP(SHA-256)") */ PK_Encryptor_EME(const Public_Key& key, RandomNumberGenerator& rng, const std::string& padding, const std::string& provider = ""); #if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) /** * Construct an instance. * @param key the key to use inside the encryptor * @param padding the message encoding scheme to use (eg "OAEP(SHA-256)") */ BOTAN_DEPRECATED("Use constructor taking a RNG object") PK_Encryptor_EME(const Public_Key& key, const std::string& padding, const std::string& provider = "") : PK_Encryptor_EME(key, system_rng(), padding, provider) {} #endif ~PK_Encryptor_EME(); PK_Encryptor_EME& operator=(const PK_Encryptor_EME&) = delete; PK_Encryptor_EME(const PK_Encryptor_EME&) = delete; private: std::vector enc(const byte[], size_t, RandomNumberGenerator& rng) const override; std::unique_ptr m_op; }; /** * Decryption with an MR algorithm and an EME. */ class BOTAN_DLL PK_Decryptor_EME final : public PK_Decryptor { public: /** * Construct an instance. * @param key the key to use inside the decryptor * @param eme the EME to use * @param provider */ PK_Decryptor_EME(const Private_Key& key, RandomNumberGenerator& rng, const std::string& eme, const std::string& provider = ""); #if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) /** * Construct an instance. * @param key the key to use inside the decryptor * @param padding the message encoding scheme to use (eg "OAEP(SHA-256)") */ BOTAN_DEPRECATED("Use constructor taking a RNG object") PK_Decryptor_EME(const Private_Key& key, const std::string& eme, const std::string& provider = "") : PK_Decryptor_EME(key, system_rng(), eme, provider) {} #endif ~PK_Decryptor_EME(); PK_Decryptor_EME& operator=(const PK_Decryptor_EME&) = delete; PK_Decryptor_EME(const PK_Decryptor_EME&) = delete; private: secure_vector do_decrypt(byte& valid_mask, const byte in[], size_t in_len) const override; std::unique_ptr m_op; }; class BOTAN_DLL PK_KEM_Encryptor final { public: PK_KEM_Encryptor(const Public_Key& key, RandomNumberGenerator& rng, const std::string& kem_param = "", const std::string& provider = ""); #if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) BOTAN_DEPRECATED("Use constructor taking a RNG object") PK_KEM_Encryptor(const Public_Key& key, const std::string& kem_param = "", const std::string& provider = "") : PK_KEM_Encryptor(key, system_rng(), kem_param, provider) {} #endif ~PK_KEM_Encryptor(); PK_KEM_Encryptor& operator=(const PK_KEM_Encryptor&) = delete; PK_KEM_Encryptor(const PK_KEM_Encryptor&) = delete; void encrypt(secure_vector& out_encapsulated_key, secure_vector& out_shared_key, size_t desired_shared_key_len, Botan::RandomNumberGenerator& rng, const uint8_t salt[], size_t salt_len); template void encrypt(secure_vector& out_encapsulated_key, secure_vector& out_shared_key, size_t desired_shared_key_len, Botan::RandomNumberGenerator& rng, const std::vector& salt) { this->encrypt(out_encapsulated_key, out_shared_key, desired_shared_key_len, rng, salt.data(), salt.size()); } void encrypt(secure_vector& out_encapsulated_key, secure_vector& out_shared_key, size_t desired_shared_key_len, Botan::RandomNumberGenerator& rng) { this->encrypt(out_encapsulated_key, out_shared_key, desired_shared_key_len, rng, nullptr, 0); } private: std::unique_ptr m_op; }; class BOTAN_DLL PK_KEM_Decryptor final { public: PK_KEM_Decryptor(const Private_Key& key, RandomNumberGenerator& rng, const std::string& kem_param = "", const std::string& provider = ""); #if defined(BOTAN_PUBKEY_INCLUDE_DEPRECATED_CONSTRUCTORS) BOTAN_DEPRECATED("Use constructor taking a RNG object") PK_KEM_Decryptor(const Private_Key& key, const std::string& kem_param = "", const std::string& provider = "") : PK_KEM_Decryptor(key, system_rng(), kem_param, provider) {} #endif ~PK_KEM_Decryptor(); PK_KEM_Decryptor& operator=(const PK_KEM_Decryptor&) = delete; PK_KEM_Decryptor(const PK_KEM_Decryptor&) = delete; secure_vector decrypt(const byte encap_key[], size_t encap_key_len, size_t desired_shared_key_len, const uint8_t salt[], size_t salt_len); secure_vector decrypt(const byte encap_key[], size_t encap_key_len, size_t desired_shared_key_len) { return this->decrypt(encap_key, encap_key_len, desired_shared_key_len, nullptr, 0); } template secure_vector decrypt(const std::vector& encap_key, size_t desired_shared_key_len, const std::vector& salt) { return this->decrypt(encap_key.data(), encap_key.size(), desired_shared_key_len, salt.data(), salt.size()); } private: std::unique_ptr m_op; }; } #endif