Secure Chat Application C++
👤 Sharing: AI
```cpp
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <random>
#include <chrono>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <stdexcept>
// Constants for encryption/decryption
const int KEY_LENGTH = 32; // 256-bit key
const int IV_LENGTH = 16; // 128-bit IV
const EVP_CIPHER* CIPHER = EVP_aes_256_cbc(); // AES-256-CBC
// Function prototypes
std::string generateRandomKey(int length);
std::string encryptMessage(const std::string& message, const std::string& key);
std::string decryptMessage(const std::string& ciphertext, const std::string& key);
std::string base64Encode(const unsigned char* buffer, size_t length);
std::vector<unsigned char> base64Decode(const std::string& base64String);
void handleErrors();
// Error handling macro
#define HANDLE_OPENSSL_ERROR(func) \
if (!(func)) { \
handleErrors(); \
return ""; \
}
// Error handling macro for decryption
#define HANDLE_OPENSSL_DECRYPT_ERROR(func) \
if (!(func)) { \
handleErrors(); \
return ""; \
}
// Function to handle OpenSSL errors
void handleErrors() {
unsigned long errCode;
while ((errCode = ERR_get_error())) {
char errStr[256];
ERR_error_string_n(errCode, errStr, sizeof(errStr));
std::cerr << "OpenSSL Error: " << errStr << std::endl;
}
throw std::runtime_error("OpenSSL Error occurred. Check console for details."); // Throw an exception to stop execution.
}
// Function to generate a random key
std::string generateRandomKey(int length) {
std::string key(length, 0);
if (RAND_bytes((unsigned char*)key.data(), length) != 1) {
handleErrors();
return "";
}
return key;
}
// Function to perform base64 encoding
std::string base64Encode(const unsigned char* buffer, size_t length) {
BIO *bio, *b64;
BUF_MEM *bufferPtr;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_NOCRLF); // No newlines to play nice with C++ strings
BIO_write(bio, buffer, length);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);
BIO_set_close(bio, BIO_NOCLOSE);
std::string encoded(bufferPtr->data, bufferPtr->length);
BIO_free_all(bio);
return encoded;
}
// Function to perform base64 decoding
std::vector<unsigned char> base64Decode(const std::string& base64String) {
BIO *bio, *b64;
std::vector<unsigned char> decoded(base64String.length()); // Preallocate memory. Sufficient for worst-case size.
int decoded_length = 0;
bio = BIO_new_mem_buf(base64String.c_str(), base64String.length());
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_NOCRLF);
decoded_length = BIO_read(bio, decoded.data(), base64String.length()); // Write to preallocated memory
if (decoded_length < 0) {
BIO_free_all(bio);
throw std::runtime_error("Base64 decode failed.");
}
decoded.resize(decoded_length); // Adjust size to actual decoded length
BIO_free_all(bio);
return decoded;
}
// Function to encrypt a message
std::string encryptMessage(const std::string& message, const std::string& key) {
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
handleErrors();
return "";
}
std::string iv = generateRandomKey(IV_LENGTH); // Generate a new IV for each message.
if (iv.empty()) {
EVP_CIPHER_CTX_free(ctx);
return "";
}
HANDLE_OPENSSL_ERROR(EVP_EncryptInit_ex(ctx, CIPHER, NULL, (const unsigned char*)key.data(), (const unsigned char*)iv.data()));
std::vector<unsigned char> ciphertext(message.length() + EVP_CIPHER_CTX_block_size(ctx)); // Allocate ciphertext buffer (worst-case size)
int ciphertext_len = 0;
int len;
HANDLE_OPENSSL_ERROR(EVP_EncryptUpdate(ctx, ciphertext.data(), &len, (const unsigned char*)message.data(), message.length()));
ciphertext_len += len;
HANDLE_OPENSSL_ERROR(EVP_EncryptFinal_ex(ctx, ciphertext.data() + ciphertext_len, &len));
ciphertext_len += len;
ciphertext.resize(ciphertext_len); // Resize the vector to the actual ciphertext length
EVP_CIPHER_CTX_free(ctx);
// Prepend the IV to the ciphertext (IV is needed for decryption). Base64 encode the IV + ciphertext
std::vector<unsigned char> combined(iv.begin(), iv.end());
combined.insert(combined.end(), ciphertext.begin(), ciphertext.end());
return base64Encode(combined.data(), combined.size());
}
// Function to decrypt a message
std::string decryptMessage(const std::string& ciphertext, const std::string& key) {
std::vector<unsigned char> decoded = base64Decode(ciphertext);
if (decoded.empty()) {
return "";
}
if (decoded.size() < IV_LENGTH) {
std::cerr << "Ciphertext too short (missing IV)." << std::endl;
return ""; // Or throw an exception
}
std::string iv((char*)decoded.data(), IV_LENGTH);
std::vector<unsigned char> actual_ciphertext(decoded.begin() + IV_LENGTH, decoded.end());
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
handleErrors();
return "";
}
HANDLE_OPENSSL_DECRYPT_ERROR(EVP_DecryptInit_ex(ctx, CIPHER, NULL, (const unsigned char*)key.data(), (const unsigned char*)iv.data()));
std::vector<unsigned char> plaintext(actual_ciphertext.size()); // Allocate plaintext buffer. Cannot be larger than ciphertext.
int plaintext_len = 0;
int len;
HANDLE_OPENSSL_DECRYPT_ERROR(EVP_DecryptUpdate(ctx, plaintext.data(), &len, actual_ciphertext.data(), actual_ciphertext.size()));
plaintext_len += len;
HANDLE_OPENSSL_DECRYPT_ERROR(EVP_DecryptFinal_ex(ctx, plaintext.data() + plaintext_len, &len));
plaintext_len += len;
plaintext.resize(plaintext_len); // Resize to actual plaintext length.
EVP_CIPHER_CTX_free(ctx);
return std::string(plaintext.begin(), plaintext.end());
}
int main() {
// Initialize OpenSSL (only needed once at the start of your program)
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
std::string key = generateRandomKey(KEY_LENGTH);
if (key.empty()) {
std::cerr << "Failed to generate key." << std::endl;
return 1;
}
std::string message = "This is a secret message!";
std::cout << "Original message: " << message << std::endl;
std::string ciphertext = encryptMessage(message, key);
if (ciphertext.empty()) {
std::cerr << "Encryption failed." << std::endl;
return 1;
}
std::cout << "Ciphertext: " << ciphertext << std::endl;
std::string decryptedMessage = decryptMessage(ciphertext, key);
if (decryptedMessage.empty()) {
std::cerr << "Decryption failed." << std::endl;
return 1;
}
std::cout << "Decrypted message: " << decryptedMessage << std::endl;
if (message == decryptedMessage) {
std::cout << "Encryption and decryption successful!" << std::endl;
} else {
std::cout << "Encryption and decryption failed!" << std::endl;
}
// Clean up OpenSSL (only needed once at the end of your program)
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
return 0;
}
```
👁️ Viewed: 6
Comments