Skip to content

Commit e124a7a

Browse files
committed
Restructuring to introduce basic testing and seperating frontend from backend logic
1 parent acc38bc commit e124a7a

8 files changed

Lines changed: 427 additions & 276 deletions

File tree

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
#include <openssl/evp.h>
2+
#include <boost/algorithm/hex.hpp>
3+
4+
#include "UserPreferences.h"
5+
#include "Utils.h"
6+
7+
#pragma comment(lib, "libeay32")
8+
9+
namespace Encryption
10+
{
11+
namespace
12+
{
13+
/// <summary>
14+
/// Decrypts ciphertext using the given key and initialization vector.
15+
/// </summary>
16+
/// <param name="ciphertext">Encrypted bytes to decrypt.</param>
17+
/// <param name="key">Key used for decryption.</param>
18+
/// <param name="initialization_vector">Initialization vector used for decryption.</param>
19+
/// <returns>Decrypted contents of ciphertext.</returns>
20+
std::vector<uint8_t> Decrypt(
21+
const std::vector<uint8_t> &ciphertext,
22+
const std::vector<uint8_t> &key,
23+
const std::vector<uint8_t> &initialization_vector)
24+
{
25+
auto out_plaintext = std::vector<uint8_t>(ciphertext.size());
26+
auto plaintext_length = 0;
27+
auto cipher = EVP_aes_256_cbc();
28+
auto ctx = EVP_CIPHER_CTX_new();
29+
30+
EVP_CIPHER_CTX_init(ctx);
31+
32+
if (!EVP_DecryptInit_ex(ctx, cipher, nullptr, &key[0], &initialization_vector[0]))
33+
{
34+
EVP_CIPHER_CTX_free(ctx);
35+
throw std::exception("EVP_DecryptInit_ex - FAILED");
36+
}
37+
38+
if (!EVP_DecryptUpdate(ctx, &out_plaintext[0], &plaintext_length, &ciphertext[0], static_cast<int>(ciphertext.size())))
39+
{
40+
EVP_CIPHER_CTX_free(ctx);
41+
throw std::exception("EVP_DecryptUpdate - FAILED");
42+
}
43+
44+
auto additional_length = 0;
45+
if (!EVP_DecryptFinal_ex(ctx, &out_plaintext[plaintext_length], &additional_length))
46+
{
47+
EVP_CIPHER_CTX_free(ctx);
48+
throw std::exception("EVP_DecryptFinal_ex - FAILED");
49+
}
50+
51+
out_plaintext.resize(plaintext_length + additional_length);
52+
EVP_CIPHER_CTX_free(ctx);
53+
return out_plaintext;
54+
}
55+
56+
/// <summary>
57+
/// Encrypts plaintext into using the given key and initialization vector.
58+
/// </summary>
59+
/// <param name="plaintext">Plaintext to encrypt.</param>
60+
/// <param name="key">Key used for encryption.</param>
61+
/// <param name="initialization_vector">Initialization vector used for encryption.</param>
62+
/// <returns>Encrypted plaintext.</returns>
63+
std::vector<uint8_t> Encrypt(
64+
const std::vector<uint8_t> &plaintext,
65+
const std::vector<uint8_t> &key,
66+
const std::vector<uint8_t> &initialization_vector)
67+
{
68+
auto plaintext_length = 0;
69+
auto cipher = EVP_aes_256_cbc();
70+
auto ctx = EVP_CIPHER_CTX_new();
71+
72+
auto num_blocks = plaintext.size() / cipher->block_size;
73+
if (plaintext.size() % cipher->block_size != 0) {
74+
++num_blocks;
75+
}
76+
auto out_plaintext = std::vector<uint8_t>(cipher->block_size * num_blocks);
77+
memset(&out_plaintext[0], 0, out_plaintext.size());
78+
79+
EVP_CIPHER_CTX_init(ctx);
80+
81+
if (!EVP_EncryptInit_ex(ctx, cipher, nullptr, &key[0], &initialization_vector[0]))
82+
{
83+
EVP_CIPHER_CTX_free(ctx);
84+
throw std::exception("EVP_EncryptInit_ex - FAILED");
85+
}
86+
87+
if (!EVP_EncryptUpdate(ctx, &out_plaintext[0], &plaintext_length, &plaintext[0], static_cast<int>(plaintext.size())))
88+
{
89+
EVP_CIPHER_CTX_free(ctx);
90+
throw std::exception("EVP_EncryptUpdate - FAILED");
91+
}
92+
93+
auto additional_length = 0;
94+
if (!EVP_EncryptFinal_ex(ctx, &out_plaintext[plaintext_length], &additional_length))
95+
{
96+
EVP_CIPHER_CTX_free(ctx);
97+
throw std::exception("EVP_EncryptFinal_ex - FAILED");
98+
}
99+
100+
out_plaintext.resize(plaintext_length + additional_length);
101+
EVP_CIPHER_CTX_free(ctx);
102+
return out_plaintext;
103+
}
104+
105+
/// <summary>
106+
/// Generates a key and initialization_vector out of the specified salt and source bytes.
107+
/// </summary>
108+
/// <param name="salt">Salt bytes used to generate the key and initialization vector.</param>
109+
/// <param name="source_bytes">Source bytes used to generate the key and initialization vector.</param>
110+
/// <param name="out_key">[out] Generated key.</param>
111+
/// <param name="out_initialization_vector">[out] Generated initialization vector.</param>
112+
/// <returns>True on success.</returns>
113+
void GetKeys(
114+
const std::vector<uint8_t> &salt,
115+
const std::vector<uint8_t> &source_bytes,
116+
std::vector<uint8_t> &out_key,
117+
std::vector<uint8_t> &out_initialization_vector)
118+
{
119+
static const int kIterationCount = 5;
120+
121+
auto cipher = EVP_aes_256_cbc();
122+
auto md = EVP_sha1();
123+
124+
out_key.resize(cipher->key_len);
125+
out_initialization_vector.resize(cipher->iv_len);
126+
127+
auto derived_key_length = EVP_BytesToKey(
128+
cipher,
129+
md,
130+
&salt[0],
131+
&source_bytes[0],
132+
static_cast<int>(source_bytes.size()),
133+
kIterationCount,
134+
&out_key[0],
135+
&out_initialization_vector[0]
136+
);
137+
138+
if (derived_key_length == 0)
139+
{
140+
throw std::exception("EVP_BytesToKey - Failed to generate key");
141+
}
142+
}
143+
144+
/// <summary>
145+
/// Mangles data for use as source bytes when generating a key and initialization vector.
146+
/// </summary>
147+
/// <param name="data_to_mangle">Bytes to mangle.</param>
148+
/// <returns>Collection of mangled bytes.</returns>
149+
std::vector<uint8_t> MangleData(const std::vector<uint8_t> &data_to_mangle)
150+
{
151+
auto mangled_data = std::vector<uint8_t>(data_to_mangle);
152+
const auto kMangledDataSize = mangled_data.size();
153+
154+
for (size_t index = 0; index < kMangledDataSize; ++index)
155+
{
156+
auto mangled_character = ((index + 2) * mangled_data[index]) % 128;
157+
if (mangled_character != 0)
158+
{
159+
mangled_data[index] = static_cast<uint8_t>(mangled_character);
160+
}
161+
}
162+
163+
return mangled_data;
164+
}
165+
166+
/// <summary>
167+
/// Encrypts or decrypts data
168+
/// </summary>
169+
/// <param name="data">Data to encrypt or decrypt</param>
170+
/// <param name="machine_guid">Machine GUID used to encrypt data</param>
171+
/// <param name="salt_string">Salt used to encrypt data</param>
172+
/// <param name="is_encrypting">Determines if data should be encrypted or decrypted</param>
173+
/// <returns>Encrypted or decrypted data</returns>
174+
std::vector<uint8_t> EncryptOrDecryptData(
175+
const std::vector<uint8_t>& data,
176+
const std::string& machine_guid,
177+
const std::string& salt_string,
178+
bool is_encrypting)
179+
{
180+
std::vector<uint8_t> salt_bytes;
181+
boost::algorithm::unhex(salt_string.begin(), salt_string.end(), std::back_inserter(salt_bytes));
182+
183+
auto machine_guid_bytes = std::vector<uint8_t>(machine_guid.begin(), machine_guid.end());
184+
auto mangled_data = MangleData(machine_guid_bytes);
185+
186+
std::vector<uint8_t> key;
187+
std::vector<uint8_t> initialization_vector;
188+
GetKeys(salt_bytes, mangled_data, key, initialization_vector);
189+
190+
if (is_encrypting)
191+
{
192+
return Encrypt(data, key, initialization_vector);
193+
}
194+
else
195+
{
196+
return Decrypt(data, key, initialization_vector);
197+
}
198+
}
199+
}
200+
201+
std::vector<uint8_t> DecryptData(
202+
const std::vector<uint8_t>& encrypted_data,
203+
const std::string& machine_guid,
204+
const std::string& salt_string)
205+
{
206+
return EncryptOrDecryptData(encrypted_data, machine_guid, salt_string, false);
207+
}
208+
209+
std::vector<uint8_t> EncryptData(
210+
const std::vector<uint8_t>& plaintext_data,
211+
const std::string& machine_guid,
212+
const std::string& salt_string)
213+
{
214+
return EncryptOrDecryptData(plaintext_data, machine_guid, salt_string, true);
215+
}
216+
}

UserPreferencesExplorer/Main.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include <string>
2+
#include <iostream>
3+
#include <boost/program_options.hpp>
4+
5+
#include "UserPreferences.h"
6+
#include "Utils.h"
7+
8+
int main(int argc, char* argv[])
9+
{
10+
namespace po = boost::program_options;
11+
static const auto kSalt = std::string("6E3F032949637D2E");
12+
13+
try
14+
{
15+
auto arg_salt = po::value<std::string>()->default_value(kSalt, "");
16+
auto arg_guid = po::value<std::string>()->default_value(Utils::GetMachineGuid(), "");
17+
auto arg_path = po::value<std::string>()->default_value(Utils::GetPathToUserPreferencesBag(), "");
18+
19+
auto commandline_descriptions = po::options_description("Arguments");
20+
commandline_descriptions.add_options()
21+
("help", "Help")
22+
("salt", arg_salt, "Salt used for key generation.")
23+
("guid", arg_guid, "GUID used for key generation.")
24+
("path", arg_path, "Path to the UserPreferences.bag to decrypt.");
25+
26+
auto parsed_options = po::parse_command_line(argc, argv, commandline_descriptions);
27+
po::variables_map vm;
28+
po::store(parsed_options, vm);
29+
po::notify(vm);
30+
31+
if (vm.count("help"))
32+
{
33+
std::cout << commandline_descriptions << std::endl;
34+
return EXIT_SUCCESS;
35+
}
36+
37+
auto path = vm["path"].as<std::string>();
38+
auto guid = vm["guid"].as<std::string>();
39+
auto salt = vm["salt"].as<std::string>();
40+
41+
auto ciphertext = Utils::ReadAllBytes(vm["path"].as<std::string>());
42+
auto plaintext = Encryption::DecryptData(ciphertext, guid, salt);
43+
auto plaintext_string = std::string(plaintext.begin(), plaintext.end());
44+
45+
std::cout << plaintext_string << std::endl;
46+
}
47+
catch (const std::exception& ex)
48+
{
49+
std::cerr << "Failed to decrypt user preferences: " << ex.what() << std::endl;
50+
return EXIT_FAILURE;
51+
}
52+
53+
return EXIT_SUCCESS;
54+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <string>
5+
6+
namespace Encryption
7+
{
8+
/// <summary>
9+
/// Decrypts encrypted data
10+
/// </summary>
11+
/// <param name="encrypted_data">Encrypted data</param>
12+
/// <param name="machine_guid">Machine GUID used to encrypt data</param>
13+
/// <param name="salt_string">Salt used to encrypt data</param>
14+
/// <returns>Decrypted data</returns>
15+
std::vector<uint8_t> DecryptData(
16+
const std::vector<uint8_t>& encrypted_data,
17+
const std::string& machine_guid,
18+
const std::string& salt_string);
19+
20+
/// <summary>
21+
/// Encrypts data
22+
/// </summary>
23+
/// <param name="encrypted_data">Data to encrypt</param>
24+
/// <param name="machine_guid">Machine GUID used to encrypt data</param>
25+
/// <param name="salt_string">Salt used to encrypt data</param>
26+
/// <returns>Decrypted data</returns>
27+
std::vector<uint8_t> EncryptData(const std::vector<uint8_t>& plaintext_data,
28+
const std::string& machine_guid,
29+
const std::string& salt_string);
30+
};

0 commit comments

Comments
 (0)