Closed Marko-Sanchez closed 1 year ago
What you are trying to implement is a hybrid encryption scheme. Because RSA on its own cannot encrypt arbitrarily large data streams. In short you should: encrypt/authenticate your payload data with a symmetric cipher (preferable an AEAD, e.g. AES-256/OCB, AES-256/GCM or similar) under a random symmetric key. And then encrypt that random symmetric key using your RSA public key.
Maybe the example code below might help your understanding:
#include <iostream>
#include <botan/aead.h>
#include <botan/rsa.h>
#include <botan/auto_rng.h>
#include <botan/secmem.h>
#include <botan/pubkey.h>
struct EncryptedData {
Botan::secure_vector<uint8_t> ciphertext;
std::vector<uint8_t> nonce;
std::vector<uint8_t> encryptedKey;
};
std::unique_ptr<Botan::Private_Key>
generate_keypair(const size_t bits,
Botan::RandomNumberGenerator& rng)
{
return std::make_unique<Botan::RSA_PrivateKey>(rng, bits);
}
EncryptedData encrypt(const Botan::secure_vector<uint8_t>& data,
std::unique_ptr<Botan::Public_Key> pubkey,
Botan::RandomNumberGenerator& rng)
{
auto sym_cipher = Botan::AEAD_Mode::create_or_throw("AES-256/GCM", Botan::ENCRYPTION);
EncryptedData d;
// prepare random key material for the symmetric encryption/authentication
rng.random_vec(d.nonce, sym_cipher->default_nonce_length());
const auto key = rng.random_vec(sym_cipher->minimum_keylength());
d.ciphertext = data;
// encrypt/authenticate the data symmetrically
sym_cipher->set_key(key);
sym_cipher->start(d.nonce);
sym_cipher->finish(d.ciphertext);
// encrypt the symmetric key using RSA
Botan::PK_Encryptor_EME asym_cipher(*pubkey, rng, "EME-OAEP(SHA-256,MGF1)");
d.encryptedKey = asym_cipher.encrypt(key, rng);
return d;
}
Botan::secure_vector<uint8_t>
decrypt(const EncryptedData& encdata,
const Botan::Private_Key& privkey,
Botan::RandomNumberGenerator& rng)
{
// prepare random key material for the symmetric encryption/authentication
Botan::secure_vector<uint8_t> plaintext = encdata.ciphertext;
// decrypt the symmetric key
Botan::PK_Decryptor_EME asym_cipher(privkey, rng, "EME-OAEP(SHA-256,MGF1)");
const auto key = asym_cipher.decrypt(encdata.encryptedKey);
// decrypt the data symmetrically
auto sym_cipher = Botan::AEAD_Mode::create_or_throw("AES-256/GCM", Botan::DECRYPTION);
sym_cipher->set_key(key);
sym_cipher->start(encdata.nonce);
sym_cipher->finish(plaintext);
return plaintext;
}
template <typename Out, typename In>
Out as(const In& data)
{
return Out(data.data(), data.data() + data.size());
}
int main()
{
Botan::AutoSeeded_RNG rng;
const auto privkey = generate_keypair(2048 /* bits */, rng);
const std::string plaintext = "The quick brown fox jumps over the lazy dog.";
const auto ciphertext = encrypt(as<Botan::secure_vector<uint8_t>>(plaintext), privkey->public_key(), rng);
const auto new_plaintext = decrypt(ciphertext, *privkey, rng);
std::cout << as<std::string>(new_plaintext) << std::endl;
return 0;
}
Thank you, I have applied your suggestions, they have been very help full. I am wondering if there is anything I am doing incorrect, in my work. In terms of correctly applying Botan-2 elements, if this is out-of-scope for this thread, then we could close this thread. Thank you.
The areas of concern for me are the conversion of RSA key pairs to std::string
and the thought process of encrypting large messages like paragraphs (5 sentences), if anything different needs to be done (in case there are some limitation on how much AEAD can encrypt).
@reneme I think this ticket can be closed but before that happens could you please open a PR adding the above example code you wrote to src/examples
?
I have been having trouble locating a definitive guide or code examples to both create a RSA keypair and Encrypt/ decrypt using said keys.
My first method was using the given AEAD mode example given in the wiki but when I tried changing the code up to work with an RSA key. I was unable to find documentation or tutorials on how to do so.
What I'm attempting to do is:
One of the few reasonable examples I could find of creating a RSA keypair is below which I then attempt to convert to a string, to then be passed to the encryption and decryption functions:
The encryption algorithm I was originally using was AES-256/OCB.
I've looked at the documentation, but it seems to always point me elsewhere. Help with this would be appreciated alongside, some where to find examples of botan-2 aswell.