What is the recommended way of encrypting a short std::string
into another std::string
using the openssl
C library (not the command-line tool of the same name) using a public keyfile, and knowing the algorithm? (in this case the string is no larger than ~100 bytes, keyfile is in .pem
format, algorithm can be any asymmetric one like RSA/ECDSA/etc).
I am looking to write a function with an interface like so: bool EncryptString(const std::string& InStr, const std::string& InPublicKey, std::string& OutString)
.
Looking through documentation it seems like EVP_PKEY_encrypt
is the function to use, which requires an EVP_PKEY_CTX *ctx
variable. My assumption is, this variable should be initialized with EVP_PKEY_CTX_new
, which in turn requires an EVP_PKEY *pkey
and an ENGINE *e
. Those I don't know how to initialize, and searching through the documentation leaves me very confused.
Maybe these functions are not the easiest approach, I am not familiar with this library at all and have no cryptography knowledge. I simply care about a black-box way of converting a string to an encrypted string.
Thank you
As it turned out in the comments, RSA is an acceptable option for you.
When implementing RSA with OpenSSL, the following steps are required for encryption:
The implementation below for encryption with RSA and OpenSSL runs successfully on my machine and shows how the functions are called (without exception handling for simplicity):
#include <openssl/pem.h>
#include <string>
...
bool EncryptString(const std::string& InStr /*plaintext*/, const std::string& InPublicKey /*path to public key pem file*/, std::string& OutString /*ciphertext*/) {
// Load key
FILE* f = fopen(InPublicKey.c_str(), "r");
EVP_PKEY* pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
fclose(f);
// Create/initialize context
EVP_PKEY_CTX* ctx;
ctx = EVP_PKEY_CTX_new(pkey, NULL);
EVP_PKEY_encrypt_init(ctx);
// Specify padding: default is PKCS#1 v1.5
// EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING); // for OAEP with SHA1 for both digests
// Encryption
size_t ciphertextLen;
EVP_PKEY_encrypt(ctx, NULL, &ciphertextLen, (const unsigned char*)InStr.c_str(), InStr.size());
unsigned char* ciphertext = (unsigned char*)OPENSSL_malloc(ciphertextLen);
EVP_PKEY_encrypt(ctx, ciphertext, &ciphertextLen, (const unsigned char*)InStr.c_str(), InStr.size());
OutString.assign((char*)ciphertext, ciphertextLen);
// Release memory
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
OPENSSL_free(ciphertext);
return true; // add exception/error handling
}
With the ciphertext it must be considered that it is a byte sequence that does not represent real text (it may contain 0x00 values, for example). If the ciphertext is to be represented as real text, an additional binary-to-text encoding such as Base64 encoding must be performed.
The code requires a PEM encoded public key in X.509/SPKI format. If the public key has the PKCS#1 format, it can be imported using PEM_read_RSAPublicKey()
and EVP_PKEY_set1_RSA()
.