Skip to content

Instantly share code, notes, and snippets.

@jonwis
Last active December 20, 2023 04:25
Show Gist options
  • Save jonwis/289e9be08a02cc30103227e6a6fac655 to your computer and use it in GitHub Desktop.
Save jonwis/289e9be08a02cc30103227e6a6fac655 to your computer and use it in GitHub Desktop.
Obfuscation from a seed number
#include <random>
#include <string>
#include <vector>
#include <span>
#include <winrt/windows.storage.streams.h>
#include <winrt/windows.security.cryptography.h>
#include <winrt/windows.security.cryptography.core.h>
#include <winrt/windows.security.cryptography.certificates.h>
namespace winrt {
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Storage::Streams;
using namespace winrt::Windows::Security::Cryptography;
using namespace winrt::Windows::Security::Cryptography::Core;
}
struct key_pair
{
winrt::CryptographicKey key;
winrt::IBuffer initVector;
};
// This method generates a random buffer derived from a numeric seed value.
// It uses the Merseinne Twister algorithm to generate the random data over
// uniform distribution using ascii characters from 32 to 126 (' ' to '~').
// The result is the UTF-8 encoded password stored in a winrt::IBuffer for
// use with the Cryptography APIs.
winrt::IBuffer GenerateBufferFromSeed(uint32_t seed, uint32_t length)
{
std::wstring result;
result.resize(length);
std::mt19937 gen{ seed };
std::uniform_int_distribution<> dis{ ' ', '~' };
for (uint32_t i = 0; i < length; i++)
{
result[i] = dis(gen);
}
return winrt::CryptographicBuffer::ConvertStringToBinary(result, winrt::BinaryStringEncoding::Utf8);
}
// This method derives a key and salt from two numeric seeds. The output is a
// symmetric key for use with AES CBC PKCS7 encryption and a salt value for
// use as the initialization vector.
key_pair derive_keys(uint32_t key_seed, uint32_t salt_seed)
{
auto buffSecret = GenerateBufferFromSeed(key_seed, 16);
auto buffSalt = GenerateBufferFromSeed(salt_seed, 128);
auto keyDerivationProvider = winrt::KeyDerivationAlgorithmProvider::OpenAlgorithm(winrt::KeyDerivationAlgorithmNames::Pbkdf2Sha256());
auto keySource = keyDerivationProvider.CreateKey(buffSecret);
auto keyParams = winrt::KeyDerivationParameters::BuildForPbkdf2(buffSalt, 10000);
auto keyMaterial = winrt::CryptographicEngine::DeriveKeyMaterial(keySource, keyParams, 32);
auto keyProvider = winrt::SymmetricKeyAlgorithmProvider::OpenAlgorithm(winrt::SymmetricAlgorithmNames::AesCbcPkcs7());
return { keyProvider.CreateSymmetricKey(keyMaterial), std::move(buffSalt) };
}
// This method tanes a byte array and two numeric seeds and returns a base64
// encoded string version of the input, encrypted using AES CBC PKCS7 and a key
// and salt derived from the seed values.
std::string obfuscate_content(std::span<uint8_t> const& input, uint32_t key_seed, uint32_t salt_seed)
{
auto [key, iv] = derive_keys(key_seed, salt_seed);
// Encrypt the result, convert back to base64 then return it as a string.
auto buffOutput = winrt::CryptographicEngine::Encrypt(key, winrt::CryptographicBuffer::CreateFromByteArray({ input.data(), input.data() + input.size() }), iv);
auto encoded = winrt::CryptographicBuffer::EncodeToBase64String(buffOutput);
return winrt::to_string(encoded);
}
// This method takes a base64 encoded string and two numeric seeds and returns
// a byte array containing the decrypted data. The key and salt are derived
// from the seed values.
std::vector<uint8_t> deobfuscate_content(std::string const& input, uint32_t key_seed, uint32_t salt_seed)
{
auto [key, iv] = derive_keys(key_seed, salt_seed);
// Decrypt and return.
auto buffInput = winrt::CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(input));
auto buffOutput = winrt::CryptographicEngine::Decrypt(key, buffInput, iv);
auto buffOutputData = buffOutput.data();
return { buffOutputData, buffOutputData + buffOutput.Length() };
}
void test()
{
winrt::init_apartment();
std::string input = "Hello world";
uint32_t key_seed = 123;
uint32_t salt_seed = 456;
auto obfuscated = obfuscate_content(std::span<uint8_t>(reinterpret_cast<uint8_t*>(input.data()), input.size()), key_seed, salt_seed);
auto deobfuscated = deobfuscate_content(obfuscated, key_seed, salt_seed);
std::cout << "Input: " << input << std::endl;
std::cout << "Obfuscated: " << obfuscated << std::endl;
std::cout << "Deobfuscated: " << std::string(reinterpret_cast<char const*>(deobfuscated.data()), deobfuscated.size()) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment