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