I needed OpenSSL for my Winsock client/server to implement symmetrical encryption/decryption for UDP messages and file data during socket session, for which I send an initial decryption key via socket from client side to server, and server returns a key acknowledgement awaiting further action from client (sendto/recvfrom).
OpenSSL was exactly what I was looking for. It works just fine, uses EVP* functions and utilizes aes256-cbc algorithm using a secret key. Includes 2 functions:
void encrypt(const char *inputString, const unsigned char *key, char *encryptedOutput)
void decrypt(const char *hexString, const unsigned char *key, char **decryptedOutput)
Now, the point was to find a non-MSVCRT version of the libcrypto DLL, and find the static libraries which was available from 3 different online repos and are code signed until June 2024. You just locate a newer copy by that point, and you will also be on a newer OpenSSL version.
The first page I found was at
https://wiki.openssl.org/index.php/Binaries
Which gave me a clear direction. I chose OpenSSL 3.2.0
https://kb.firedaemon.com/support/solutions/articles/4000121705
Now in the ZIP contains x86 and x64 versions of the necessary files.
(ZIP) openssl-3/x64/lib/libssl.lib
(ZIP) openssl-3/x64/lib/libcrypto.lib
(ZIP) openssl-3/x64/include/*
(ZIP) openssl-3/x64/bin/libssl-3-x64.dll
Rename "include" directory to "openssl" and place in application path.
Place both libs in same directory as application, and place libssl-3-x64.dll (or libssl-3.dll) in same path too.
#pragma comment(lib, "libssl.lib")
#pragma comment(lib, "libcrypto.lib")
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/conf.h>
Generate the key:
// Init OpenSSL
OpenSSL_add_all_algorithms();
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
unsigned char key[EVP_MAX_KEY_LENGTH];
// Generate random key
if (RAND_bytes(key, sizeof(key)) != 1) {
log_error("Failed to generate random key");
return 0;
}
// Convert the key to a hexadecimal string
char hexKey[(EVP_MAX_KEY_LENGTH * 2) + 1];
for (int i = 0; i < sizeof(key); ++i) {
sprintf(&hexKey[i * 2], "%02x", key[i]);
}
hexKey[sizeof(key) * 2] = '\0';
Encrypting text with same key
char encryptedMessage[512];
encrypt("Some secret text here", (const unsigned char *)hexKey, encryptedMessage);
Decrypting text with same key
char *decryptedData;
decrypt(encryptedMessage, (const unsigned char *)hexKey, &decryptedData);
Encrypt/decrypt functions:
void encrypt(const char *inputString, const unsigned char *key, char *encryptedOutput) {
EVP_CIPHER_CTX *ctx;
int len;
int ciphertextLen;
unsigned char ciphertext[512];
// Create and initialize the context
ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, NULL);
// Encrypt the input string
EVP_EncryptUpdate(ctx, ciphertext, &len, (const unsigned char *)inputString, strlen(inputString));
ciphertextLen = len;
// Finalize the encryption
EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
ciphertextLen += len;
// Clean up the context
EVP_CIPHER_CTX_free(ctx);
// Convert the encrypted data to a hexadecimal string
for (int i = 0; i < ciphertextLen; ++i) {
sprintf(&encryptedOutput[i * 2], "%02x", ciphertext[i]);
}
encryptedOutput[ciphertextLen * 2] = '\0';
}
void decrypt(const char *hexString, const unsigned char *key, char **decryptedOutput) {
EVP_CIPHER_CTX *ctx;
int len;
int plaintextLen;
// Create and initialize the context
ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, NULL);
// Convert the hexadecimal string to binary
int hexLen = strlen(hexString);
unsigned char *binaryData = (unsigned char *)malloc(hexLen / 2);
for (int i = 0; i < hexLen / 2; ++i) {
sscanf(&hexString[i * 2], "%2hhx", &binaryData[i]);
}
// Decrypt the binary data
unsigned char *plaintext = (unsigned char *)malloc(hexLen / 2);
EVP_DecryptUpdate(ctx, plaintext, &len, binaryData, hexLen / 2);
plaintextLen = len;
// Finalize the decryption
EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
plaintextLen += len;
// Clean up the context
EVP_CIPHER_CTX_free(ctx);
free(binaryData); // Free the dynamically allocated memory
// Null-terminate the decrypted data
plaintext[plaintextLen] = '\0';
// Assign the decrypted data to the output buffer
*decryptedOutput = (char *)plaintext;
}
Working perfectly for me. In case this helps anyone.
WiiLF23- Great contribution.
I had looked at OpenSSL in the past and got bogged down in the implementation.
Looks like you have nailed it down.
John Z
You can try with LibCurl OpenSSL that I ported to PellesC on my github account (https://github.com/Frankie-PellesC/Curl/blob/master/libcurl/openssl.c).
Thanks guys! Yeah I added a array of supported algorithms that I load up into a combobox control. On WM_CLOSE it sets the index of the array in memory, so we can do this manually by selection instead of calling a direct function
const EVP_CIPHER *algorithm = EVP_get_cipherbyname("AES-256-CBC");
if (algorithm == NULL) {
log_error("Unknown algorithm!");
return;
}
EVP_get_cipherbyname works with narrow chars. This became easy to allow selection!
Combo box setup:
static const char *algorithms[] = {
"AES-128-ECB", "AES-128-CBC", "AES-128-CTR", "AES-128-GCM",
"AES-192-ECB", "AES-192-CBC", "AES-192-CTR", "AES-192-GCM",
"AES-256-ECB", "AES-256-CBC", "AES-256-CTR", "AES-256-GCM",
"DES-ECB", "DES-CBC", "3DES-ECB", "3DES-CBC",
"RC4",
"Camellia-128-CBC", "Camellia-192-CBC", "Camellia-256-CBC",
"IDEA-ECB", "IDEA-CBC",
"SEED-ECB", "SEED-CBC",
"ChaCha20-Poly1305"
};
WM_INITDIALOG:
HWND comboBox = GetDlgItem(hwndDlg, MY_COMBO_BOX_ID);
for (size_t i = 0; i < sizeof(algorithms) / sizeof(algorithms[0]); ++i) {
int wideSize = MultiByteToWideChar(CP_UTF8, 0, algorithms[i], -1, NULL, 0);
wchar_t *wideString = (wchar_t*)malloc(wideSize * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, algorithms[i], -1, wideString, wideSize);
SendMessage(comboBox, CB_ADDSTRING, 0, (LPARAM)wideString);
free(wideString);
}
SendMessage(comboBox, CB_SETCURSEL, 10, 0); // Set index (optional)
Had to convert narrow to wide for the combobox for list, to allow the EVP_get_cipherbyname() function to take the string without issues.
(https://i.ibb.co/fGYh13T/secure-pic.jpg)
You can read the OpenSSL version (see pic) by calling:
const char *openssl_version = OpenSSL_version(OPENSSL_VERSION);
An ANSI string in UNICODE program
SendMessageA(comboBox, CB_ADDSTRING, 0, (LPARAM)algorithms[i]);