-
-
Save grejdi/9361828 to your computer and use it in GitHub Desktop.
using namespace std; | |
#include <openssl/evp.h> | |
#include <openssl/pem.h> | |
#include <iostream> | |
#include <string> | |
int main() | |
{ | |
// create private/public key pair | |
// init RSA context, so we can generate a key pair | |
EVP_PKEY_CTX *keyCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); | |
EVP_PKEY_keygen_init(keyCtx); | |
EVP_PKEY_CTX_set_rsa_keygen_bits(keyCtx, 4096); // RSA 4096 | |
// variable that will hold both private and public keys | |
EVP_PKEY *key = NULL; | |
// generate key | |
EVP_PKEY_keygen(keyCtx, &key); | |
// free up key context | |
EVP_PKEY_CTX_free(keyCtx); | |
// extract private key as string | |
// create a place to dump the IO, in this case in memory | |
BIO *privateBIO = BIO_new(BIO_s_mem()); | |
// dump key to IO | |
PEM_write_bio_PrivateKey(privateBIO, key, NULL, NULL, 0, 0, NULL); | |
// get buffer length | |
int privateKeyLen = BIO_pending(privateBIO); | |
// create char reference of private key length | |
unsigned char *privateKeyChar = (unsigned char *) malloc(privateKeyLen); | |
// read the key from the buffer and put it in the char reference | |
BIO_read(privateBIO, privateKeyChar, privateKeyLen); | |
// at this point we can save the private key somewhere | |
// extract public key as string | |
// create a place to dump the IO, in this case in memory | |
BIO *publicBIO = BIO_new(BIO_s_mem()); | |
// dump key to IO | |
PEM_write_bio_PUBKEY(publicBIO, key); | |
// get buffer length | |
int publicKeyLen = BIO_pending(publicBIO); | |
// create char reference of public key length | |
unsigned char *publicKeyChar = (unsigned char *) malloc(publicKeyLen); | |
// read the key from the buffer and put it in the char reference | |
BIO_read(publicBIO, publicKeyChar, publicKeyLen); | |
// at this point we can save the public somewhere | |
// pretend we are pulling the public key from some source and using it | |
// to encrypt a message | |
unsigned char *rsaPublicKeyChar = publicKeyChar; | |
// write char array to BIO | |
BIO *rsaPublicBIO = BIO_new_mem_buf(rsaPublicKeyChar, -1); | |
// create a RSA object from public key char array | |
RSA *rsaPublicKey = NULL; | |
PEM_read_bio_RSA_PUBKEY(rsaPublicBIO, &rsaPublicKey, NULL, NULL); | |
// create public key | |
EVP_PKEY *publicKey = EVP_PKEY_new(); | |
EVP_PKEY_assign_RSA(publicKey, rsaPublicKey); | |
// initialize encrypt context | |
EVP_CIPHER_CTX *rsaEncryptCtx = (EVP_CIPHER_CTX *) malloc(sizeof(EVP_CIPHER_CTX)); | |
EVP_CIPHER_CTX_init(rsaEncryptCtx); | |
// variables for where the encrypted secret, length, and IV reside | |
unsigned char *ek = (unsigned char *) malloc(EVP_PKEY_size(publicKey)); | |
int ekLen = 0; | |
unsigned char *iv = (unsigned char *) malloc(EVP_MAX_IV_LENGTH); | |
// generate AES secret, and encrypt it with public key | |
EVP_SealInit(rsaEncryptCtx, EVP_aes_256_cbc(), &ek, &ekLen, iv, &publicKey, 1); | |
// encrypt a message with AES secret | |
string message = "You can include the standard headers in any order, a standard header more than once, or two or more standard headers that define the same macro or the same type. Do not include a standard header within a declaration. Do not define macros that have the same names as keywords before you include a standard header."; | |
const unsigned char* messageChar = (const unsigned char*) message.c_str(); | |
// length of message | |
int messageLen = message.size() + 1; | |
// create char reference for where the encrypted message will reside | |
unsigned char *encryptedMessage = (unsigned char *) malloc(messageLen + EVP_MAX_IV_LENGTH); | |
// the length of the encrypted message | |
int encryptedMessageLen = 0; | |
int encryptedBlockLen = 0; | |
// encrypt message with AES secret | |
EVP_SealUpdate(rsaEncryptCtx, encryptedMessage, &encryptedBlockLen, messageChar, messageLen); | |
encryptedMessageLen = encryptedBlockLen; | |
// finalize by encrypting the padding | |
EVP_SealFinal(rsaEncryptCtx, encryptedMessage + encryptedBlockLen, &encryptedBlockLen); | |
encryptedMessageLen += encryptedBlockLen; | |
// pretend we are decrypting a message we have received using a the private key we have | |
unsigned char *rsaPrivateKeyChar = privateKeyChar; | |
// write char array to BIO | |
BIO *rsaPrivateBIO = BIO_new_mem_buf(rsaPrivateKeyChar, -1); | |
// create a RSA object from private key char array | |
RSA *rsaPrivateKey = NULL; | |
PEM_read_bio_RSAPrivateKey(rsaPrivateBIO, &rsaPrivateKey, NULL, NULL); | |
// create private key | |
EVP_PKEY *privateKey = EVP_PKEY_new(); | |
EVP_PKEY_assign_RSA(privateKey, rsaPrivateKey); | |
// initialize decrypt context | |
EVP_CIPHER_CTX *rsaDecryptCtx = (EVP_CIPHER_CTX *) malloc(sizeof(EVP_CIPHER_CTX)); | |
EVP_CIPHER_CTX_init(rsaDecryptCtx); | |
// decrypt EK with private key, and get AES secretp | |
EVP_OpenInit(rsaDecryptCtx, EVP_aes_256_cbc(), ek, ekLen, iv, privateKey); | |
// variable for where the decrypted message with be outputed to | |
unsigned char *decryptedMessage = (unsigned char *) malloc(encryptedMessageLen + EVP_MAX_IV_LENGTH); | |
// the length of the encrypted message | |
int decryptedMessageLen = 0; | |
int decryptedBlockLen = 0; | |
// decrypt message with AES secret | |
EVP_OpenUpdate(rsaDecryptCtx, decryptedMessage, &decryptedBlockLen, encryptedMessage, encryptedMessageLen); | |
decryptedMessageLen = decryptedBlockLen; | |
// finalize by decrypting padding | |
EVP_OpenFinal(rsaDecryptCtx, decryptedMessage + decryptedBlockLen, &decryptedBlockLen); | |
decryptedMessageLen += decryptedBlockLen; | |
printf("%s\n", encryptedMessage); | |
printf("\"%s\"\n", decryptedMessage); | |
} |
Thanks ,I am searching for this then I got here and learnt from ya...thanks so much ...cheers.
Thank you grejdi.
This is so helpful.
With so many different and mostly wrong instructions around the web, I almost lost hope to learn openssl.
Thank you once again.
Generates this compile error with GCC 12.1:
error: invalid application of 'sizeof' to incomplete type 'EVP_CIPHER_CTX'
on this line:
EVP_CIPHER_CTX *rsaEncryptCtx = (EVP_CIPHER_CTX *) malloc(sizeof(EVP_CIPHER_CTX));
Regards.
On line 65 and 102 you should now use EVP_CIPHER_CTX_new()
For example, EVP_CIPHER_CTX *rsaEncryptCtx = (EVP_CIPHER_CTX *) malloc(sizeof(EVP_CIPHER_CTX));
becomes EVP_CIPHER_CTX* rsaEncryptCtx = EVP_CIPHER_CTX_new();
Visual Studio was also crying with errors 4996 (deprecated stuff), so I also added #pragma warning(disable : 4996)
. Probably not the best or safest way, but I just wanted to try out the code for learning purposes.
To compile:
g++ -o main main.cpp -lssl -lcrypto