Exemples de Cryptographie Windows C++

Exemples de cryptographie Windows C++ incluant le calcul de hash, le chiffrement/déchiffrement AES et l'encodage/décodage Base64

💻 Encodage/Décodage Base64 cpp

🟢 simple ⭐⭐

Encoder des données binaires en chaînes Base64 et décoder des chaînes Base64 en données binaires en utilisant Windows API

⏱️ 20 min 🏷️ cpp, base64, encoding, windows
Prerequisites: Basic C++, Windows Cryptography API
// Windows C++ Base64 Encoding/Decoding Examples
// Using Windows Cryptography API

#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <wincrypt.h>

#pragma comment(lib, "crypt32.lib")

// 1. Basic Base64 Encoding
class Base64Encoder {
public:
    static std::string encode(const std::vector<BYTE>& data) {
        DWORD encodedSize = 0;

        // Get the required buffer size
        if (!CryptBinaryToStringA(data.data(), static_cast<DWORD>(data.size()),
            CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, nullptr, &encodedSize)) {
            std::cerr << "Failed to get encoded size" << std::endl;
            return "";
        }

        // Allocate buffer and encode
        std::string encoded;
        encoded.resize(encodedSize);

        if (!CryptBinaryToStringA(data.data(), static_cast<DWORD>(data.size()),
            CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR,
            reinterpret_cast<LPSTR>(&encoded[0]), &encodedSize)) {
            std::cerr << "Failed to encode data" << std::endl;
            return "";
        }

        // Remove null terminator if present
        if (!encoded.empty() && encoded[encodedSize - 1] == '\0') {
            encoded.resize(encodedSize - 1);
        } else {
            encoded.resize(encodedSize);
        }

        return encoded;
    }

    static std::string encodeString(const std::string& text) {
        std::vector<BYTE> data(text.begin(), text.end());
        return encode(data);
    }

    static std::string encodeWithLineBreaks(const std::vector<BYTE>& data, int lineWidth = 76) {
        DWORD encodedSize = 0;

        // Get the required buffer size
        if (!CryptBinaryToStringA(data.data(), static_cast<DWORD>(data.size()),
            CRYPT_STRING_BASE64, nullptr, &encodedSize)) {
            return "";
        }

        std::string encoded;
        encoded.resize(encodedSize);

        if (!CryptBinaryToStringA(data.data(), static_cast<DWORD>(data.size()),
            CRYPT_STRING_BASE64,
            reinterpret_cast<LPSTR>(&encoded[0]), &encodedSize)) {
            return "";
        }

        if (!encoded.empty() && encoded[encodedSize - 1] == '\0') {
            encoded.resize(encodedSize - 1);
        } else {
            encoded.resize(encodedSize);
        }

        return encoded;
    }
};

// 2. Basic Base64 Decoding
class Base64Decoder {
public:
    static std::vector<BYTE> decode(const std::string& encoded) {
        DWORD decodedSize = 0;

        // Get the required buffer size
        if (!CryptStringToBinaryA(encoded.c_str(), 0, CRYPT_STRING_BASE64,
            nullptr, &decodedSize, nullptr, nullptr)) {
            std::cerr << "Failed to get decoded size" << std::endl;
            return {};
        }

        // Allocate buffer and decode
        std::vector<BYTE> decoded(decodedSize);

        if (!CryptStringToBinaryA(encoded.c_str(), 0, CRYPT_STRING_BASE64,
            decoded.data(), &decodedSize, nullptr, nullptr)) {
            std::cerr << "Failed to decode data" << std::endl;
            return {};
        }

        decoded.resize(decodedSize);
        return decoded;
    }

    static std::string decodeToString(const std::string& encoded) {
        std::vector<BYTE> data = decode(encoded);

        if (data.empty()) {
            return "";
        }

        return std::string(data.begin(), data.end());
    }
};

// 3. Base64 for URL Encoding (URL-safe variant)
class Base64URLEncoder {
public:
    static std::string encode(const std::vector<BYTE>& data) {
        // First, do standard base64 encoding
        std::string encoded = Base64Encoder::encode(data);

        // Make URL-safe: replace + with -, replace / with _, remove trailing =
        for (char& c : encoded) {
            if (c == '+') c = '-';
            else if (c == '/') c = '_';
        }

        // Remove padding characters
        size_t paddingPos = encoded.find('=');
        if (paddingPos != std::string::npos) {
            encoded = encoded.substr(0, paddingPos);
        }

        return encoded;
    }

    static std::vector<BYTE> decode(const std::string& encoded) {
        // Convert URL-safe back to standard base64
        std::string standard = encoded;

        for (char& c : standard) {
            if (c == '-') c = '+';
            else if (c == '_') c = '/';
        }

        // Add padding if necessary
        while (standard.size() % 4 != 0) {
            standard += '=';
        }

        return Base64Decoder::decode(standard);
    }
};

// 4. Base64 File Operations
class Base64File {
public:
    static bool encodeFile(const std::string& inputFile, const std::string& outputFile) {
        // Read input file
        std::ifstream inFile(inputFile, std::ios::binary);
        if (!inFile) {
            std::cerr << "Failed to open input file: " << inputFile << std::endl;
            return false;
        }

        std::vector<BYTE> fileData((std::istreambuf_iterator<char>(inFile)),
                                   std::istreambuf_iterator<char>());
        inFile.close();

        // Encode
        std::string encoded = Base64Encoder::encodeWithLineBreaks(fileData);

        // Write output file
        std::ofstream outFile(outputFile);
        if (!outFile) {
            std::cerr << "Failed to open output file: " << outputFile << std::endl;
            return false;
        }

        outFile << encoded;
        outFile.close();

        std::cout << "File encoded: " << inputFile << " -> " << outputFile << std::endl;
        std::cout << "Original size: " << fileData.size() << " bytes" << std::endl;
        std::cout << "Encoded size: " << encoded.size() << " characters" << std::endl;

        return true;
    }

    static bool decodeFile(const std::string& inputFile, const std::string& outputFile) {
        // Read input file
        std::ifstream inFile(inputFile);
        if (!inFile) {
            std::cerr << "Failed to open input file: " << inputFile << std::endl;
            return false;
        }

        std::string encoded((std::istreambuf_iterator<char>(inFile)),
                           std::istreambuf_iterator<char>());
        inFile.close();

        // Decode
        std::vector<BYTE> fileData = Base64Decoder::decode(encoded);

        if (fileData.empty()) {
            std::cerr << "Failed to decode file data" << std::endl;
            return false;
        }

        // Write output file
        std::ofstream outFile(outputFile, std::ios::binary);
        if (!outFile) {
            std::cerr << "Failed to open output file: " << outputFile << std::endl;
            return false;
        }

        outFile.write(reinterpret_cast<const char*>(fileData.data()), fileData.size());
        outFile.close();

        std::cout << "File decoded: " << inputFile << " -> " << outputFile << std::endl;
        std::cout << "Encoded size: " << encoded.size() << " characters" << std::endl;
        std::cout << "Decoded size: " << fileData.size() << " bytes" << std::endl;

        return true;
    }
};

// 5. Base64 Hash Encoding
class Base64Hash {
public:
    // Encode SHA256 hash as base64
    static std::string encodeSHA256(const std::string& input) {
        // Calculate SHA256 hash
        std::vector<BYTE> hash = calculateSHA256(input);

        // Encode as base64
        return Base64Encoder::encode(hash);
    }

    // Common for JWT (JSON Web Tokens)
    static std::string encodeForJWT(const std::string& data) {
        std::vector<BYTE> bytes(data.begin(), data.end());

        // Use URL-safe base64 encoding
        return Base64URLEncoder::encode(bytes);
    }

private:
    static std::vector<BYTE> calculateSHA256(const std::string& input) {
        // This would normally use Windows Cryptography API
        // For demonstration, returning a placeholder
        std::vector<BYTE> hash(32, 0x42);
        return hash;
    }
};

// 6. Base64 Image Encoding
class Base64Image {
public:
    static std::string encodeImageWithHeader(const std::string& imageFile, const std::string& mimeType) {
        // Read image file
        std::ifstream inFile(imageFile, std::ios::binary);
        if (!inFile) {
            return "";
        }

        std::vector<BYTE> imageData((std::istreambuf_iterator<char>(inFile)),
                                    std::istreambuf_iterator<char>());
        inFile.close();

        // Encode as base64
        std::string base64Data = Base64Encoder::encode(imageData);

        // Add data URI header
        return "data:" + mimeType + ";base64," + base64Data;
    }

    static bool saveImageFromDataURI(const std::string& dataURI, const std::string& outputFile) {
        // Check for data URI header
        const std::string prefix = "data:image/";
        size_t startPos = dataURI.find(prefix);

        if (startPos == std::string::npos) {
            std::cerr << "Invalid data URI" << std::endl;
            return false;
        }

        startPos = dataURI.find(";base64,") + 8; // Skip ";base64,"
        std::string base64Data = dataURI.substr(startPos);

        // Decode base64
        std::vector<BYTE> imageData = Base64Decoder::decode(base64Data);

        if (imageData.empty()) {
            return false;
        }

        // Write to file
        std::ofstream outFile(outputFile, std::ios::binary);
        if (!outFile) {
            return false;
        }

        outFile.write(reinterpret_cast<const char*>(imageData.data()), imageData.size());
        outFile.close();

        return true;
    }
};

// 7. Base64 Chunked Encoding
class Base64Chunked {
public:
    // Split data into chunks and encode each chunk separately
    static std::vector<std::string> encodeChunked(const std::vector<BYTE>& data, int chunkSize = 1024) {
        std::vector<std::string> chunks;

        for (size_t i = 0; i < data.size(); i += chunkSize) {
            size_t end = std::min(i + chunkSize, data.size());
            std::vector<BYTE> chunk(data.begin() + i, data.begin() + end);

            std::string encoded = Base64Encoder::encode(chunk);
            chunks.push_back(encoded);
        }

        return chunks;
    }

    // Decode chunks and combine
    static std::vector<BYTE> decodeChunked(const std::vector<std::string>& chunks) {
        std::vector<BYTE> result;

        for (const auto& chunk : chunks) {
            std::vector<BYTE> decoded = Base64Decoder::decode(chunk);

            if (decoded.empty()) {
                return {}; // Error
            }

            result.insert(result.end(), decoded.begin(), decoded.end());
        }

        return result;
    }
};

// 8. Base64 Validation
class Base64Validator {
public:
    static bool isValidBase64(const std::string& str) {
        if (str.empty()) {
            return false;
        }

        // Check each character
        for (char c : str) {
            bool valid = (c >= 'A' && c <= 'Z') ||
                       (c >= 'a' && c <= 'z') ||
                       (c >= '0' && c <= '9') ||
                       c == '+' || c == '/' || c == '=' ||
                       c == '\r' || c == '\n';

            if (!valid) {
                return false;
            }
        }

        // Check length is multiple of 4 (ignoring whitespace)
        int contentLength = 0;
        for (char c : str) {
            if (c != '\r' && c != '\n' && c != ' ') {
                contentLength++;
            }
        }

        return contentLength % 4 == 0;
    }

    static std::string cleanBase64String(const std::string& str) {
        std::string cleaned;

        for (char c : str) {
            if (c != '\r' && c != '\n' && c != ' ' && c != '\t') {
                cleaned += c;
            }
        }

        return cleaned;
    }
};

// Main demonstration
int main() {
    std::cout << "=== Windows C++ Base64 Encoding/Decoding Examples ===" << std::endl;

    // 1. Basic encoding
    std::cout << "\n--- Basic Encoding ---" << std::endl;
    std::string text = "Hello, World!";
    std::vector<BYTE> data(text.begin(), text.end());

    std::string encoded = Base64Encoder::encode(data);
    std::cout << "Original: " << text << std::endl;
    std::cout << "Encoded: " << encoded << std::endl;

    // 2. Basic decoding
    std::cout << "\n--- Basic Decoding ---" << std::endl;
    std::vector<BYTE> decoded = Base64Decoder::decode(encoded);
    std::string decodedText(decoded.begin(), decoded.end());
    std::cout << "Decoded: " << decodedText << std::endl;

    // 3. String encoding/decoding
    std::cout << "\n--- String Operations ---" << std::endl;
    std::string message = "This is a secret message.";
    std::string encodedMessage = Base64Encoder::encodeString(message);
    std::string decodedMessage = Base64Decoder::decodeToString(encodedMessage);

    std::cout << "Original: " << message << std::endl;
    std::cout << "Encoded: " << encodedMessage << std::endl;
    std::cout << "Decoded: " << decodedMessage << std::endl;

    // 4. URL-safe encoding
    std::cout << "\n--- URL-Safe Encoding ---" << std::endl;
    std::vector<BYTE> urlData = {0x00, 0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD};
    std::string urlEncoded = Base64URLEncoder::encode(urlData);
    std::cout << "URL-safe encoded: " << urlEncoded << std::endl;

    std::vector<BYTE> urlDecoded = Base64URLEncoder::decode(urlEncoded);
    std::cout << "URL-safe decoded: " << (urlDecoded == urlData ? "SUCCESS" : "FAILED") << std::endl;

    // 5. File encoding/decoding
    std::cout << "\n--- File Operations ---" << std::endl;
    std::ofstream testFile("test_data.txt");
    testFile << "This is test data for Base64 encoding.";
    testFile.close();

    Base64File::encodeFile("test_data.txt", "test_data.b64");
    Base64File::decodeFile("test_data.b64", "test_data_decoded.txt");

    // 6. Image encoding
    std::cout << "\n--- Image Data URI ---" << std::endl;
    std::ofstream testImage("test_image.png");
    // Write minimal PNG data (1x1 pixel transparent PNG)
    unsigned char pngData[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
    testImage.write(reinterpret_cast<const char*>(pngData), 8);
    testImage.close();

    std::string dataUri = Base64Image::encodeImageWithHeader("test_image.png", "image/png");
    std::cout << "Data URI (truncated): " << dataUri.substr(0, 100) << "..." << std::endl;

    // 7. Chunked encoding
    std::cout << "\n--- Chunked Encoding ---" << std::endl;
    std::vector<BYTE> largeData(3000);
    for (size_t i = 0; i < largeData.size(); i++) {
        largeData[i] = static_cast<BYTE>(i % 256);
    }

    std::vector<std::string> chunks = Base64Chunked::encodeChunked(largeData, 1000);
    std::cout << "Split into " << chunks.size() << " chunks" << std::endl;

    std::vector<BYTE> reassembled = Base64Chunked::decodeChunked(chunks);
    std::cout << "Reassembly: " << (reassembled == largeData ? "SUCCESS" : "FAILED") << std::endl;

    // 8. Validation
    std::cout << "\n--- Validation ---" << std::endl;
    std::string validBase64 = "SGVsbG8sIFdvcmxkIQ==";
    std::string invalidBase64 = "Invalid@Base64!";

    std::cout << "'" << validBase64 << "' is valid: "
              << (Base64Validator::isValidBase64(validBase64) ? "YES" : "NO") << std::endl;
    std::cout << "'" << invalidBase64 << "' is valid: "
              << (Base64Validator::isValidBase64(invalidBase64) ? "YES" : "NO") << std::endl;

    std::cout << "\n=== All Base64 Examples Completed ===" << std::endl;
    return 0;
}

💻 Calcul de Hash cpp

🟡 intermediate ⭐⭐⭐

Calculer les valeurs de hash MD5, SHA1, SHA256 et SHA512 pour les chaînes et les fichiers en utilisant Windows Cryptography API

⏱️ 25 min 🏷️ cpp, cryptography, hash, windows
Prerequisites: Intermediate C++, Windows Cryptography API
// Windows C++ Hash Calculation Examples
// Using Windows Cryptography API (CryptoAPI/CNG)

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <windows.h>
#include <wincrypt.h>

#pragma comment(lib, "crypt32.lib")

// 1. MD5 Hash Calculation
class MD5Hash {
public:
    static std::string calculate(const std::string& input) {
        HCRYPTPROV hProv = 0;
        HCRYPTHASH hHash = 0;

        // Get handle to crypto provider
        if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
            std::cerr << "CryptAcquireContext failed" << std::endl;
            return "";
        }

        // Create hash object
        if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
            CryptReleaseContext(hProv, 0);
            std::cerr << "CryptCreateHash failed" << std::endl;
            return "";
        }

        // Hash data
        if (!CryptHashData(hHash, reinterpret_cast<const BYTE*>(input.c_str()), input.size(), 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            std::cerr << "CryptHashData failed" << std::endl;
            return "";
        }

        // Get hash value
        DWORD hashLen = 16; // MD5 is 16 bytes
        std::vector<BYTE> hash(hashLen);

        if (!CryptGetHashParam(hHash, HP_HASHVAL, hash.data(), &hashLen, 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            std::cerr << "CryptGetHashParam failed" << std::endl;
            return "";
        }

        // Clean up
        CryptDestroyHash(hHash);
        CryptReleaseContext(hProv, 0);

        // Convert to hexadecimal string
        return bytesToHex(hash);
    }

    static std::string calculateFile(const std::string& filename) {
        std::ifstream file(filename, std::ios::binary);
        if (!file) {
            std::cerr << "Failed to open file: " << filename << std::endl;
            return "";
        }

        HCRYPTPROV hProv = 0;
        HCRYPTHASH hHash = 0;

        if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
            return "";
        }

        if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
            CryptReleaseContext(hProv, 0);
            return "";
        }

        // Hash file in chunks
        const int BUFFER_SIZE = 4096;
        std::vector<BYTE> buffer(BUFFER_SIZE);

        while (file) {
            file.read(reinterpret_cast<char*>(buffer.data()), BUFFER_SIZE);
            std::streamsize bytesRead = file.gcount();

            if (bytesRead > 0) {
                if (!CryptHashData(hHash, buffer.data(), static_cast<DWORD>(bytesRead), 0)) {
                    CryptDestroyHash(hHash);
                    CryptReleaseContext(hProv, 0);
                    return "";
                }
            }
        }

        DWORD hashLen = 16;
        std::vector<BYTE> hash(hashLen);

        if (!CryptGetHashParam(hHash, HP_HASHVAL, hash.data(), &hashLen, 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return "";
        }

        CryptDestroyHash(hHash);
        CryptReleaseContext(hProv, 0);

        return bytesToHex(hash);
    }

private:
    static std::string bytesToHex(const std::vector<BYTE>& bytes) {
        std::string hex;
        hex.reserve(bytes.size() * 2);

        for (BYTE b : bytes) {
            char buf[3];
            sprintf_s(buf, "%02x", b);
            hex += buf;
        }

        return hex;
    }
};

// 2. SHA1 Hash Calculation
class SHA1Hash {
public:
    static std::string calculate(const std::string& input) {
        HCRYPTPROV hProv = 0;
        HCRYPTHASH hHash = 0;

        if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
            return "";
        }

        if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) {
            CryptReleaseContext(hProv, 0);
            return "";
        }

        if (!CryptHashData(hHash, reinterpret_cast<const BYTE*>(input.c_str()), input.size(), 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return "";
        }

        DWORD hashLen = 20; // SHA1 is 20 bytes
        std::vector<BYTE> hash(hashLen);

        if (!CryptGetHashParam(hHash, HP_HASHVAL, hash.data(), &hashLen, 0)) {
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            return "";
        }

        CryptDestroyHash(hHash);
        CryptReleaseContext(hProv, 0);

        return bytesToHex(hash);
    }

private:
    static std::string bytesToHex(const std::vector<BYTE>& bytes) {
        std::string hex;
        hex.reserve(bytes.size() * 2);

        for (BYTE b : bytes) {
            char buf[3];
            sprintf_s(buf, "%02x", b);
            hex += buf;
        }

        return hex;
    }
};

// 3. SHA256 Hash Calculation (using CNG - Cryptography Next Generation)
#include <bcrypt.h>

#pragma comment(lib, "bcrypt.lib")

class SHA256Hash {
public:
    static std::string calculate(const std::string& input) {
        BCRYPT_ALG_HANDLE hAlg = nullptr;
        BCRYPT_HASH_HANDLE hHash = nullptr;
        NTSTATUS status;
        DWORD hashLen = 0;
        DWORD resultLen = 0;

        // Open algorithm provider
        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, nullptr, 0);
        if (status != 0) {
            std::cerr << "BCryptOpenAlgorithmProvider failed: " << status << std::endl;
            return "";
        }

        // Get hash length
        status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, reinterpret_cast<PBYTE>(&hashLen), sizeof(hashLen), &resultLen, 0);
        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        // Create hash object
        status = BCryptCreateHash(hAlg, &hHash, nullptr, 0, nullptr, 0, 0);
        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        // Hash data
        status = BCryptHashData(hHash, reinterpret_cast<PBYTE>(const_cast<char*>(input.c_str())), input.size(), 0);
        if (status != 0) {
            BCryptDestroyHash(hHash);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        // Get hash value
        std::vector<BYTE> hash(hashLen);
        status = BCryptFinishHash(hHash, hash.data(), hashLen, 0);
        if (status != 0) {
            BCryptDestroyHash(hHash);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        // Clean up
        BCryptDestroyHash(hHash);
        BCryptCloseAlgorithmProvider(hAlg, 0);

        return bytesToHex(hash);
    }

    static std::string calculateFile(const std::string& filename) {
        BCRYPT_ALG_HANDLE hAlg = nullptr;
        BCRYPT_HASH_HANDLE hHash = nullptr;
        NTSTATUS status;
        DWORD hashLen = 0;
        DWORD resultLen = 0;

        std::ifstream file(filename, std::ios::binary);
        if (!file) {
            std::cerr << "Failed to open file: " << filename << std::endl;
            return "";
        }

        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, nullptr, 0);
        if (status != 0) {
            return "";
        }

        status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, reinterpret_cast<PBYTE>(&hashLen), sizeof(hashLen), &resultLen, 0);
        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        status = BCryptCreateHash(hAlg, &hHash, nullptr, 0, nullptr, 0, 0);
        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        // Hash file in chunks
        const int BUFFER_SIZE = 4096;
        std::vector<BYTE> buffer(BUFFER_SIZE);

        while (file) {
            file.read(reinterpret_cast<char*>(buffer.data()), BUFFER_SIZE);
            std::streamsize bytesRead = file.gcount();

            if (bytesRead > 0) {
                status = BCryptHashData(hHash, buffer.data(), static_cast<ULONG>(bytesRead), 0);
                if (status != 0) {
                    BCryptDestroyHash(hHash);
                    BCryptCloseAlgorithmProvider(hAlg, 0);
                    return "";
                }
            }
        }

        std::vector<BYTE> hash(hashLen);
        status = BCryptFinishHash(hHash, hash.data(), hashLen, 0);
        if (status != 0) {
            BCryptDestroyHash(hHash);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        BCryptDestroyHash(hHash);
        BCryptCloseAlgorithmProvider(hAlg, 0);

        return bytesToHex(hash);
    }

private:
    static std::string bytesToHex(const std::vector<BYTE>& bytes) {
        std::string hex;
        hex.reserve(bytes.size() * 2);

        for (BYTE b : bytes) {
            char buf[3];
            sprintf_s(buf, "%02x", b);
            hex += buf;
        }

        return hex;
    }
};

// 4. SHA512 Hash Calculation
class SHA512Hash {
public:
    static std::string calculate(const std::string& input) {
        BCRYPT_ALG_HANDLE hAlg = nullptr;
        BCRYPT_HASH_HANDLE hHash = nullptr;
        NTSTATUS status;
        DWORD hashLen = 0;
        DWORD resultLen = 0;

        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA512_ALGORITHM, nullptr, 0);
        if (status != 0) {
            return "";
        }

        status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, reinterpret_cast<PBYTE>(&hashLen), sizeof(hashLen), &resultLen, 0);
        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        status = BCryptCreateHash(hAlg, &hHash, nullptr, 0, nullptr, 0, 0);
        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        status = BCryptHashData(hHash, reinterpret_cast<PBYTE>(const_cast<char*>(input.c_str())), input.size(), 0);
        if (status != 0) {
            BCryptDestroyHash(hHash);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        std::vector<BYTE> hash(hashLen);
        status = BCryptFinishHash(hHash, hash.data(), hashLen, 0);
        if (status != 0) {
            BCryptDestroyHash(hHash);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        BCryptDestroyHash(hHash);
        BCryptCloseAlgorithmProvider(hAlg, 0);

        return bytesToHex(hash);
    }

private:
    static std::string bytesToHex(const std::vector<BYTE>& bytes) {
        std::string hex;
        hex.reserve(bytes.size() * 2);

        for (BYTE b : bytes) {
            char buf[3];
            sprintf_s(buf, "%02x", b);
            hex += buf;
        }

        return hex;
    }
};

// 5. Compare Hash Values
class HashComparator {
public:
    static bool compare(const std::string& hash1, const std::string& hash2) {
        // Case-insensitive comparison
        if (hash1.length() != hash2.length()) {
            return false;
        }

        for (size_t i = 0; i < hash1.length(); ++i) {
            char c1 = tolower(hash1[i]);
            char c2 = tolower(hash2[i]);

            if (c1 != c2) {
                return false;
            }
        }

        return true;
    }

    static bool verifyFileIntegrity(const std::string& filename, const std::string& expectedHash) {
        std::string actualHash = SHA256Hash::calculateFile(filename);

        if (actualHash.empty()) {
            return false;
        }

        return compare(actualHash, expectedHash);
    }
};

// 6. HMAC (Hash-based Message Authentication Code)
class HMACSHA256 {
public:
    static std::string calculate(const std::string& message, const std::string& key) {
        BCRYPT_ALG_HANDLE hAlg = nullptr;
        BCRYPT_HASH_HANDLE hHash = nullptr;
        NTSTATUS status;
        DWORD hashLen = 0;
        DWORD resultLen = 0;

        // Open algorithm provider
        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG);
        if (status != 0) {
            std::cerr << "Failed to open algorithm provider" << std::endl;
            return "";
        }

        // Create hash with key
        status = BCryptCreateHash(hAlg, &hHash, nullptr, 0,
            reinterpret_cast<PBYTE>(const_cast<char*>(key.c_str())),
            static_cast<ULONG>(key.size()), 0);

        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        // Hash message
        status = BCryptHashData(hHash, reinterpret_cast<PBYTE>(const_cast<char*>(message.c_str())),
            static_cast<ULONG>(message.size()), 0);

        if (status != 0) {
            BCryptDestroyHash(hHash);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        // Get hash length
        status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, reinterpret_cast<PBYTE>(&hashLen), sizeof(hashLen), &resultLen, 0);
        if (status != 0) {
            BCryptDestroyHash(hHash);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        // Get hash value
        std::vector<BYTE> hash(hashLen);
        status = BCryptFinishHash(hHash, hash.data(), hashLen, 0);

        if (status != 0) {
            BCryptDestroyHash(hHash);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return "";
        }

        BCryptDestroyHash(hHash);
        BCryptCloseAlgorithmProvider(hAlg, 0);

        return bytesToHex(hash);
    }

private:
    static std::string bytesToHex(const std::vector<BYTE>& bytes) {
        std::string hex;
        hex.reserve(bytes.size() * 2);

        for (BYTE b : bytes) {
            char buf[3];
            sprintf_s(buf, "%02x", b);
            hex += buf;
        }

        return hex;
    }
};

// Main demonstration
int main() {
    std::cout << "=== Windows C++ Hash Calculation Examples ===" << std::endl;

    std::string testString = "Hello, World!";
    std::cout << "Input string: " << testString << std::endl;

    // 1. MD5
    std::cout << "\n--- MD5 Hash ---" << std::endl;
    std::string md5Hash = MD5Hash::calculate(testString);
    std::cout << "MD5: " << md5Hash << std::endl;

    // 2. SHA1
    std::cout << "\n--- SHA1 Hash ---" << std::endl;
    std::string sha1Hash = SHA1Hash::calculate(testString);
    std::cout << "SHA1: " << sha1Hash << std::endl;

    // 3. SHA256
    std::cout << "\n--- SHA256 Hash ---" << std::endl;
    std::string sha256Hash = SHA256Hash::calculate(testString);
    std::cout << "SHA256: " << sha256Hash << std::endl;

    // 4. SHA512
    std::cout << "\n--- SHA512 Hash ---" << std::endl;
    std::string sha512Hash = SHA512Hash::calculate(testString);
    std::cout << "SHA512: " << sha512Hash << std::endl;

    // 5. File hashing
    std::cout << "\n--- File Hashing ---" << std::endl;
    // Create test file
    std::ofstream testFile("test_file.txt");
    testFile << "This is a test file for hash calculation.";
    testFile.close();

    std::string fileMD5 = MD5Hash::calculateFile("test_file.txt");
    std::cout << "File MD5: " << fileMD5 << std::endl;

    std::string fileSHA256 = SHA256Hash::calculateFile("test_file.txt");
    std::cout << "File SHA256: " << fileSHA256 << std::endl;

    // 6. Hash comparison
    std::cout << "\n--- Hash Comparison ---" << std::endl;
    std::string hash1 = "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146";
    std::string hash2 = "A591A6D40BF420404A011733CFB7B190D62C65BF0BCDA32B57B277D9AD9F146";

    bool match = HashComparator::compare(hash1, hash2);
    std::cout << "Hash comparison (case insensitive): " << (match ? "MATCH" : "NO MATCH") << std::endl;

    // Verify file integrity
    bool integrity = HashComparator::verifyFileIntegrity("test_file.txt", fileSHA256);
    std::cout << "File integrity check: " << (integrity ? "PASSED" : "FAILED") << std::endl;

    // 7. HMAC
    std::cout << "\n--- HMAC-SHA256 ---" << std::endl;
    std::string message = "Important message to authenticate";
    std::string key = "secret_key_123";

    std::string hmac = HMACSHA256::calculate(message, key);
    std::cout << "Message: " << message << std::endl;
    std::cout << "Key: " << key << std::endl;
    std::cout << "HMAC-SHA256: " << hmac << std::endl;

    std::cout << "\n=== All Hash Calculation Examples Completed ===" << std::endl;
    return 0;
}

💻 Chiffrement/Déchiffrement AES cpp

🟡 intermediate ⭐⭐⭐⭐

Implémenter le chiffrement et déchiffrement AES-256 en utilisant Windows Cryptography API (CNG)

⏱️ 35 min 🏷️ cpp, cryptography, aes, encryption, windows
Prerequisites: Advanced C++, Windows Cryptography API (CNG)
// Windows C++ AES Encryption/Decryption Examples
// Using Cryptography Next Generation (CNG) API

#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <bcrypt.h>

#pragma comment(lib, "bcrypt.lib")

// 1. Basic AES-256 Encryption
class AESEncryptor {
private:
    BCRYPT_ALG_HANDLE hAlg;
    BCRYPT_KEY_HANDLE hKey;
    std::vector<BYTE> keyObject;
    std::vector<BYTE> iv;

public:
    AESEncryptor() : hAlg(nullptr), hKey(nullptr) {}

    ~AESEncryptor() {
        cleanup();
    }

    bool initialize(const std::vector<BYTE>& key) {
        NTSTATUS status;
        DWORD resultLen;

        // Open algorithm provider (AES-256-CBC)
        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_AES_ALGORITHM, nullptr, 0);
        if (status != 0) {
            std::cerr << "BCryptOpenAlgorithmProvider failed: " << status << std::endl;
            return false;
        }

        // Set chaining mode to CBC
        status = BCryptSetProperty(hAlg, BCRYPT_CHAINING_MODE,
            reinterpret_cast<PBYTE>(const_cast<char*>(BCRYPT_CHAIN_MODE_CBC)),
            sizeof(BCRYPT_CHAIN_MODE_CBC), 0);

        if (status != 0) {
            std::cerr << "BCryptSetProperty failed: " << status << std::endl;
            cleanup();
            return false;
        }

        // Get key object length
        status = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH,
            reinterpret_cast<PBYTE>(&resultLen), sizeof(resultLen), &resultLen, 0);

        if (status != 0) {
            cleanup();
            return false;
        }

        keyObject.resize(resultLen);

        // Generate key from key material
        status = BCryptGenerateSymmetricKey(hAlg, &hKey,
            keyObject.data(), keyObject.size(),
            const_cast<PBYTE>(key.data()), key.size(), 0);

        if (status != 0) {
            std::cerr << "BCryptGenerateSymmetricKey failed: " << status << std::endl;
            cleanup();
            return false;
        }

        // Get IV length
        status = BCryptGetProperty(hAlg, BCRYPT_BLOCK_LENGTH,
            reinterpret_cast<PBYTE>(&resultLen), sizeof(resultLen), &resultLen, 0);

        if (status != 0) {
            cleanup();
            return false;
        }

        iv.resize(resultLen, 0); // Initialize with zeros

        return true;
    }

    std::vector<BYTE> encrypt(const std::vector<BYTE>& plaintext) {
        if (hAlg == nullptr || hKey == nullptr) {
            std::cerr << "Encryptor not initialized" << std::endl;
            return {};
        }

        NTSTATUS status;
        DWORD resultLen;

        // Get ciphertext length
        status = BCryptEncrypt(hKey, const_cast<PBYTE>(plaintext.data()),
            static_cast<ULONG>(plaintext.size()), nullptr,
            iv.data(), iv.size(), nullptr, 0, &resultLen, BCRYPT_BLOCK_PADDING);

        if (status != 0) {
            std::cerr << "BCryptEncrypt (get size) failed: " << status << std::endl;
            return {};
        }

        std::vector<BYTE> ciphertext(resultLen);

        // Encrypt data
        status = BCryptEncrypt(hKey, const_cast<PBYTE>(plaintext.data()),
            static_cast<ULONG>(plaintext.size()), nullptr,
            iv.data(), iv.size(), ciphertext.data(),
            static_cast<ULONG>(ciphertext.size()), &resultLen, BCRYPT_BLOCK_PADDING);

        if (status != 0) {
            std::cerr << "BCryptEncrypt failed: " << status << std::endl;
            return {};
        }

        ciphertext.resize(resultLen);
        return ciphertext;
    }

    std::vector<BYTE> decrypt(const std::vector<BYTE>& ciphertext) {
        if (hAlg == nullptr || hKey == nullptr) {
            std::cerr << "Encryptor not initialized" << std::endl;
            return {};
        }

        NTSTATUS status;
        DWORD resultLen;

        // Get plaintext length
        status = BCryptDecrypt(hKey, const_cast<PBYTE>(ciphertext.data()),
            static_cast<ULONG>(ciphertext.size()), nullptr,
            iv.data(), iv.size(), nullptr, 0, &resultLen, BCRYPT_BLOCK_PADDING);

        if (status != 0) {
            std::cerr << "BCryptDecrypt (get size) failed: " << status << std::endl;
            return {};
        }

        std::vector<BYTE> plaintext(resultLen);

        // Decrypt data
        status = BCryptDecrypt(hKey, const_cast<PBYTE>(ciphertext.data()),
            static_cast<ULONG>(ciphertext.size()), nullptr,
            iv.data(), iv.size(), plaintext.data(),
            static_cast<ULONG>(plaintext.size()), &resultLen, BCRYPT_BLOCK_PADDING);

        if (status != 0) {
            std::cerr << "BCryptDecrypt failed: " << status << std::endl;
            return {};
        }

        plaintext.resize(resultLen);
        return plaintext;
    }

    void setIV(const std::vector<BYTE>& newIV) {
        iv = newIV;
    }

    std::vector<BYTE> getIV() const {
        return iv;
    }

private:
    void cleanup() {
        if (hKey) {
            BCryptDestroyKey(hKey);
            hKey = nullptr;
        }
        if (hAlg) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            hAlg = nullptr;
        }
    }
};

// 2. Generate Random AES Key
class KeyGenerator {
public:
    static std::vector<BYTE> generateAESKey(int bits = 256) {
        BCRYPT_ALG_HANDLE hAlg = nullptr;
        NTSTATUS status;

        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, nullptr, 0);
        if (status != 0) {
            std::cerr << "Failed to open RNG provider" << std::endl;
            return {};
        }

        int keyLen = bits / 8;
        std::vector<BYTE> key(keyLen);

        status = BCryptGenRandom(hAlg, key.data(), keyLen, 0);
        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return {};
        }

        BCryptCloseAlgorithmProvider(hAlg, 0);
        return key;
    }

    static std::vector<BYTE> generateIV(int size = 16) {
        BCRYPT_ALG_HANDLE hAlg = nullptr;
        NTSTATUS status;

        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, nullptr, 0);
        if (status != 0) {
            return {};
        }

        std::vector<BYTE> iv(size);

        status = BCryptGenRandom(hAlg, iv.data(), size, 0);
        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return {};
        }

        BCryptCloseAlgorithmProvider(hAlg, 0);
        return iv;
    }
};

// 3. String Encryption/Decryption Helper
class StringCryptor {
public:
    static std::string encryptString(const std::string& plaintext, const std::vector<BYTE>& key) {
        // Convert string to byte vector
        std::vector<BYTE> data(plaintext.begin(), plaintext.end());

        AESEncryptor encryptor;
        if (!encryptor.initialize(key)) {
            return "";
        }

        std::vector<BYTE> ciphertext = encryptor.encrypt(data);

        // Return as hex string for display
        return bytesToHex(ciphertext);
    }

    static std::string decryptString(const std::string& hexCiphertext, const std::vector<BYTE>& key) {
        // Convert hex string to byte vector
        std::vector<BYTE> ciphertext = hexToBytes(hexCiphertext);

        AESEncryptor encryptor;
        if (!encryptor.initialize(key)) {
            return "";
        }

        std::vector<BYTE> plaintext = encryptor.decrypt(ciphertext);

        return std::string(plaintext.begin(), plaintext.end());
    }

private:
    static std::string bytesToHex(const std::vector<BYTE>& bytes) {
        std::string hex;
        hex.reserve(bytes.size() * 2);

        for (BYTE b : bytes) {
            char buf[3];
            sprintf_s(buf, "%02x", b);
            hex += buf;
        }

        return hex;
    }

    static std::vector<BYTE> hexToBytes(const std::string& hex) {
        std::vector<BYTE> bytes;

        for (size_t i = 0; i < hex.length(); i += 2) {
            std::string byteString = hex.substr(i, 2);
            BYTE byte = static_cast<BYTE>(strtol(byteString.c_str(), nullptr, 16));
            bytes.push_back(byte);
        }

        return bytes;
    }
};

// 4. File Encryption/Decryption
class FileCryptor {
public:
    static bool encryptFile(const std::string& inputFile, const std::string& outputFile,
                           const std::vector<BYTE>& key) {
        // Read input file
        std::ifstream inFile(inputFile, std::ios::binary);
        if (!inFile) {
            std::cerr << "Failed to open input file" << std::endl;
            return false;
        }

        std::vector<BYTE> plaintext((std::istreambuf_iterator<char>(inFile)),
                                   std::istreambuf_iterator<char>());
        inFile.close();

        // Encrypt
        AESEncryptor encryptor;
        if (!encryptor.initialize(key)) {
            return false;
        }

        std::vector<BYTE> ciphertext = encryptor.encrypt(plaintext);
        if (ciphertext.empty()) {
            return false;
        }

        // Write output file
        std::ofstream outFile(outputFile, std::ios::binary);
        if (!outFile) {
            std::cerr << "Failed to open output file" << std::endl;
            return false;
        }

        outFile.write(reinterpret_cast<const char*>(ciphertext.data()), ciphertext.size());
        outFile.close();

        std::cout << "File encrypted: " << inputFile << " -> " << outputFile << std::endl;
        return true;
    }

    static bool decryptFile(const std::string& inputFile, const std::string& outputFile,
                           const std::vector<BYTE>& key) {
        // Read input file
        std::ifstream inFile(inputFile, std::ios::binary);
        if (!inFile) {
            std::cerr << "Failed to open input file" << std::endl;
            return false;
        }

        std::vector<BYTE> ciphertext((std::istreambuf_iterator<char>(inFile)),
                                    std::istreambuf_iterator<char>());
        inFile.close();

        // Decrypt
        AESEncryptor encryptor;
        if (!encryptor.initialize(key)) {
            return false;
        }

        std::vector<BYTE> plaintext = encryptor.decrypt(ciphertext);
        if (plaintext.empty()) {
            return false;
        }

        // Write output file
        std::ofstream outFile(outputFile, std::ios::binary);
        if (!outFile) {
            std::cerr << "Failed to open output file" << std::endl;
            return false;
        }

        outFile.write(reinterpret_cast<const char*>(plaintext.data()), plaintext.size());
        outFile.close();

        std::cout << "File decrypted: " << inputFile << " -> " << outputFile << std::endl;
        return true;
    }
};

// 5. AES-GCM (Galois/Counter Mode) - Authenticated Encryption
class AESGCM {
public:
    struct GCMResult {
        std::vector<BYTE> ciphertext;
        std::vector<BYTE> tag;
    };

    static GCMResult encrypt(const std::vector<BYTE>& plaintext, const std::vector<BYTE>& key,
                            const std::vector<BYTE>& iv, const std::vector<BYTE>& aad = {}) {
        GCMResult result;

        BCRYPT_ALG_HANDLE hAlg = nullptr;
        BCRYPT_KEY_HANDLE hKey = nullptr;
        NTSTATUS status;

        // Open AES provider
        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_AES_ALGORITHM, nullptr, 0);
        if (status != 0) {
            return result;
        }

        // Set GCM mode
        status = BCryptSetProperty(hAlg, BCRYPT_CHAINING_MODE,
            reinterpret_cast<PBYTE>(const_cast<char*>(BCRYPT_CHAIN_MODE_GCM)),
            sizeof(BCRYPT_CHAIN_MODE_GCM), 0);

        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return result;
        }

        // Create key
        std::vector<BYTE> keyObj;
        DWORD keyObjLen;
        BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH,
            reinterpret_cast<PBYTE>(&keyObjLen), sizeof(keyObjLen), &keyObjLen, 0);

        keyObj.resize(keyObjLen);

        status = BCryptGenerateSymmetricKey(hAlg, &hKey,
            keyObj.data(), keyObj.size(),
            const_cast<PBYTE>(key.data()), key.size(), 0);

        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return result;
        }

        // Get tag length
        DWORD tagLen = 16;
        BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo = {0};
        authInfo.pbNonce = const_cast<PBYTE>(iv.data());
        authInfo.cbNonce = iv.size();
        authInfo.pbAuthData = const_cast<PBYTE>(aad.data());
        authInfo.cbAuthData = aad.size();
        authInfo.pbTag = result.tag.data();
        authInfo.cbTag = tagLen;

        result.tag.resize(tagLen);

        // Get output length
        DWORD ciphertextLen;
        status = BCryptEncrypt(hKey, const_cast<PBYTE>(plaintext.data()), plaintext.size(),
            &authInfo, nullptr, 0, nullptr, 0, &ciphertextLen, 0);

        if (status != 0) {
            BCryptDestroyKey(hKey);
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return result;
        }

        result.ciphertext.resize(ciphertextLen);

        // Encrypt
        status = BCryptEncrypt(hKey, const_cast<PBYTE>(plaintext.data()), plaintext.size(),
            &authInfo, nullptr, 0, result.ciphertext.data(), ciphertextLen, &ciphertextLen, 0);

        result.ciphertext.resize(ciphertextLen);

        BCryptDestroyKey(hKey);
        BCryptCloseAlgorithmProvider(hAlg, 0);

        return result;
    }
};

// 6. Password-Based Key Derivation (PBKDF2)
class PasswordKeyDerivation {
public:
    static std::vector<BYTE> deriveKey(const std::string& password, const std::vector<BYTE>& salt,
                                       int iterations = 10000, int keyLen = 32) {
        BCRYPT_ALG_HANDLE hAlg = nullptr;
        NTSTATUS status;

        status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, nullptr, 0);
        if (status != 0) {
            return {};
        }

        // Create hash for password
        BCRYPT_HASH_HANDLE hHash = nullptr;
        std::vector<BYTE> hashObj;
        DWORD hashObjLen;
        BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH,
            reinterpret_cast<PBYTE>(&hashObjLen), sizeof(hashObjLen), &hashObjLen, 0);

        hashObj.resize(hashObjLen);

        status = BCryptCreateHash(hAlg, &hHash, hashObj.data(), hashObjLen,
            nullptr, 0, 0);

        if (status != 0) {
            BCryptCloseAlgorithmProvider(hAlg, 0);
            return {};
        }

        // Simple key derivation (in production, use proper KDF like BCryptDeriveKeyPBKDF2)
        std::vector<BYTE> key(keyLen);
        std::vector<BYTE> passwordBytes(password.begin(), password.end());

        // Combine password + salt and hash
        std::vector<BYTE> combined = passwordBytes;
        combined.insert(combined.end(), salt.begin(), salt.end());

        for (int i = 0; i < iterations; i++) {
            BCryptHashData(hHash, combined.data(), combined.size(), 0);

            DWORD hashLen = 32;
            std::vector<BYTE> hash(32);
            BCryptFinishHash(hHash, hash.data(), hashLen, 0);

            if (i == iterations - 1) {
                // Use final hash as key
                std::copy(hash.begin(), hash.begin() + std::min(keyLen, 32), key.begin());
            }

            // Use hash as input for next iteration
            combined = hash;
        }

        BCryptDestroyHash(hHash);
        BCryptCloseAlgorithmProvider(hAlg, 0);

        return key;
    }
};

// Main demonstration
int main() {
    std::cout << "=== Windows C++ AES Encryption/Decryption Examples ===" << std::endl;

    // 1. Generate random key
    std::cout << "\n--- Key Generation ---" << std::endl;
    std::vector<BYTE> key = KeyGenerator::generateAESKey(256);

    std::cout << "Generated AES-256 Key: ";
    for (BYTE b : key) {
        printf("%02x", b);
    }
    std::cout << std::endl;

    std::vector<BYTE> iv = KeyGenerator::generateIV(16);
    std::cout << "Generated IV: ";
    for (BYTE b : iv) {
        printf("%02x", b);
    }
    std::cout << std::endl;

    // 2. String encryption/decryption
    std::cout << "\n--- String Encryption ---" << std::endl;
    std::string plaintext = "Hello, World! This is a secret message.";
    std::cout << "Original: " << plaintext << std::endl;

    std::string encryptedHex = StringCryptor::encryptString(plaintext, key);
    std::cout << "Encrypted: " << encryptedHex << std::endl;

    std::string decrypted = StringCryptor::decryptString(encryptedHex, key);
    std::cout << "Decrypted: " << decrypted << std::endl;

    // 3. File encryption/decryption
    std::cout << "\n--- File Encryption ---" << std::endl;
    std::ofstream testFile("plain_file.txt");
    testFile << "This is the content of a secret file.";
    testFile.close();

    FileCryptor::encryptFile("plain_file.txt", "encrypted_file.bin", key);
    FileCryptor::decryptFile("encrypted_file.bin", "decrypted_file.txt", key);

    // 4. Password-based key derivation
    std::cout << "\n--- Password Key Derivation ---" << std::endl;
    std::string password = "mySecurePassword123";
    std::vector<BYTE> salt = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

    std::vector<BYTE> derivedKey = PasswordKeyDerivation::deriveKey(password, salt, 10000, 32);

    std::cout << "Password: " << password << std::endl;
    std::cout << "Derived Key: ";
    for (BYTE b : derivedKey) {
        printf("%02x", b);
    }
    std::cout << std::endl;

    std::cout << "\n=== All AES Encryption Examples Completed ===" << std::endl;
    return 0;
}