Elysia Tools
Navigation mobile
C++
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
Exemples
Entrées de cette collection
Calcul de Hash
Calculer les valeurs de hash MD5, SHA1, SHA256 et SHA512 pour les chaînes et les fichiers en utilisant Windows Cryptography API
Difficulté
6/10
Temps estimé
25 min
Étiquettes
cpp, cryptography, hash, windows
Prérequis
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
Implémenter le chiffrement et déchiffrement AES-256 en utilisant Windows Cryptography API (CNG)
Difficulté
8/10
Temps estimé
35 min
Étiquettes
cpp, cryptography, aes, encryption, windows
Prérequis
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 <algorithm>
#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;
}Encodage/Décodage Base64
Encoder des données binaires en chaînes Base64 et décoder des chaînes Base64 en données binaires en utilisant Windows API
Difficulté
4/10
Temps estimé
20 min
Étiquettes
cpp, base64, encoding, windows
Prérequis
Basic C++, Windows Cryptography API
// Windows C++ Base64 Encoding/Decoding Examples
// Using Windows Cryptography API
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#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;
}Outils
Outils souvent utilisés avec cet exemple
Associé