Last active
December 20, 2023 04:25
-
-
Save jonwis/289e9be08a02cc30103227e6a6fac655 to your computer and use it in GitHub Desktop.
Obfuscation from a seed number
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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