22#include < string>
33#include < fstream>
44#include < iostream>
5- #include < openssl/evp.h>
65#include < Windows.h>
76
7+ #include < openssl/evp.h>
8+ #include < boost/algorithm/hex.hpp>
9+
810#pragma comment(lib, "libeay32")
911
1012// / <summary>
1416// / <returns>Container of sequential bytes or empty container on error.</returns>
1517std::vector<uint8_t > ReadAllBytes (const std::string &path)
1618{
17- try
19+ std::ifstream inStream (path, std::ios::binary | std::ios::ate);
20+ auto fileSize = static_cast <size_t >(inStream.tellg ());
21+ if (fileSize == 0 )
1822 {
19- std::ifstream inStream (path, std::ios::binary | std::ios::ate);
20- auto fileSize = static_cast <size_t >(inStream.tellg ());
21- auto fileBytes = std::vector<uint8_t >(fileSize);
23+ throw std::exception (" File is empty" );
24+ }
2225
23- inStream.seekg (0 , std::ios::beg);
24- inStream.read (reinterpret_cast <char *>(&fileBytes[0 ]), fileSize);
25- inStream.close ();
26+ auto fileBytes = std::vector<uint8_t >(fileSize);
2627
27- return fileBytes;
28- }
29- catch (const std::exception& ex)
30- {
31- std::cerr << " Failed to read file '" << path << " ' - " << ex.what () << std::endl;
32- return std::vector<uint8_t >();
33- }
28+ inStream.seekg (0 , std::ios::beg);
29+ inStream.read (reinterpret_cast <char *>(&fileBytes[0 ]), fileSize);
30+ inStream.close ();
31+
32+ return fileBytes;
3433}
3534
3635// / <summary>
@@ -42,55 +41,40 @@ std::vector<uint8_t> ReadAllBytes(const std::string &path)
4241// / <param name="initialization_vector">Initialization vector used for decryption.</param>
4342// / <param name="out_plaintext">[out] Decrypted bytes.</param>
4443// / <returns>True on success.</returns>
45- bool Decrypt (
44+ std::vector< uint8_t > Decrypt (
4645 const std::vector<uint8_t > &cipherText,
4746 const std::vector<uint8_t > &key,
48- const std::vector<uint8_t > &initialization_vector,
49- std::vector<uint8_t > &out_plaintext)
47+ const std::vector<uint8_t > &initialization_vector)
5048{
51- out_plaintext.resize (cipherText.size ());
52- int plaintext_length = 0 ;
53-
49+ auto out_plaintext = std::vector<uint8_t >(cipherText.size ());
50+ auto plaintext_length = 0 ;
5451 auto cipher = EVP_aes_256_cbc ();
5552 auto ctx = EVP_CIPHER_CTX_new ();
5653
5754 EVP_CIPHER_CTX_init (ctx);
5855
59- auto is_successful = EVP_DecryptInit_ex (ctx, cipher, nullptr , &key[0 ], &initialization_vector[0 ]);
60- if (is_successful == false )
56+ if (!EVP_DecryptInit_ex (ctx, cipher, nullptr , &key[0 ], &initialization_vector[0 ]))
6157 {
62- std::cerr << " EVP_DecryptInit_ex - FAILED" << std::endl;
6358 EVP_CIPHER_CTX_free (ctx);
64- return false ;
59+ throw std::exception ( " EVP_DecryptInit_ex - FAILED " ) ;
6560 }
6661
67- is_successful = EVP_DecryptUpdate (
68- ctx,
69- &out_plaintext[0 ],
70- &plaintext_length,
71- &cipherText[0 ],
72- static_cast <int >(cipherText.size ())
73- );
74-
75- if (is_successful == false )
62+ if (!EVP_DecryptUpdate (ctx, &out_plaintext[0 ], &plaintext_length, &cipherText[0 ], static_cast <int >(cipherText.size ())))
7663 {
77- std::cerr << " EVP_DecryptUpdate - FAILED" << std::endl;
7864 EVP_CIPHER_CTX_free (ctx);
79- return false ;
65+ throw std::exception ( " EVP_DecryptUpdate - FAILED " ) ;
8066 }
8167
8268 auto additional_length = 0 ;
83- is_successful = EVP_DecryptFinal_ex (ctx, &out_plaintext[plaintext_length], &additional_length);
84- if (is_successful == false )
69+ if (!EVP_DecryptFinal_ex (ctx, &out_plaintext[plaintext_length], &additional_length))
8570 {
86- std::cerr << " EVP_DecryptFinal_ex - FAILED" << std::endl;
8771 EVP_CIPHER_CTX_free (ctx);
88- return false ;
72+ throw std::exception ( " EVP_DecryptFinal_ex - FAILED " ) ;
8973 }
9074
9175 out_plaintext.resize (plaintext_length + additional_length);
9276 EVP_CIPHER_CTX_free (ctx);
93- return true ;
77+ return out_plaintext ;
9478}
9579
9680// / <summary>
@@ -101,7 +85,7 @@ bool Decrypt(
10185// / <param name="out_key">[out] Generated key.</param>
10286// / <param name="out_initialization_vector">[out] Generated initialization vector.</param>
10387// / <returns>True on success.</returns>
104- bool GetKeys (
88+ void GetKeys (
10589 const std::vector<uint8_t > &salt,
10690 const std::vector<uint8_t > &source_bytes,
10791 std::vector<uint8_t > &out_key,
@@ -115,7 +99,7 @@ bool GetKeys(
11599 out_key.resize (cipher->key_len );
116100 out_initialization_vector.resize (cipher->iv_len );
117101
118- auto result = EVP_BytesToKey (
102+ auto derived_key_length = EVP_BytesToKey (
119103 cipher,
120104 md,
121105 &salt[0 ],
@@ -125,7 +109,11 @@ bool GetKeys(
125109 &out_key[0 ],
126110 &out_initialization_vector[0 ]
127111 );
128- return result > 0 ;
112+
113+ if (derived_key_length == 0 )
114+ {
115+ throw std::exception (" EVP_BytesToKey - Failed to generate key" );
116+ }
129117}
130118
131119// / <summary>
@@ -165,26 +153,23 @@ std::string GetMachineGuid()
165153 if (result != ERROR_SUCCESS)
166154 {
167155 RegCloseKey (key_handle);
168- std::cerr << " RegOpenKeyEx - FAILED" << std::endl;
169- return " " ;
156+ throw std::exception (" RegOpenKeyEx - FAILED" );
170157 }
171158
172159 DWORD buff_size = 0 ;
173160 result = RegQueryValueExA (key_handle, kMachineGuidName .c_str (), nullptr , nullptr , nullptr , &buff_size);
174161 if (result != ERROR_SUCCESS)
175162 {
176163 RegCloseKey (key_handle);
177- std::cerr << " RegQueryValueEx - FAILED" << std::endl;
178- return " " ;
164+ throw std::exception (" RegQueryValueEx - FAILED" );
179165 }
180166
181167 auto machine_guid = std::vector<uint8_t >(buff_size);
182168 result = RegQueryValueExA (key_handle, kMachineGuidName .c_str (), nullptr , nullptr , &machine_guid[0 ], &buff_size);
183169 if (result != ERROR_SUCCESS)
184170 {
185171 RegCloseKey (key_handle);
186- std::cerr << " RegQueryValueEx - FAILED" << std::endl;
187- return " " ;
172+ throw std::exception (" RegQueryValueEx - FAILED" );
188173 }
189174
190175 RegCloseKey (key_handle);
@@ -215,56 +200,50 @@ std::string GetPathToUserPreferencesBag()
215200 return local_app_data_path + kDefaultUserPreferencesPath ;
216201}
217202
218- int main (int argc, char * argv[])
219- {
220- // The salt is hardcoded
221- static const std::vector<uint8_t > kSalt {
222- 0x6E , 0x3F , 0x03 , 0x29 , 0x49 , 0x63 , 0x7D , 0x2E
223- };
224203
225- auto machine_guid = GetMachineGuid ();
226- if (machine_guid.empty ())
227- {
228- std::cerr << " Failed to get MachineGuid" << std::endl;
229- return 0 ;
230- }
204+ // / <summary>
205+ // / Decrypts the specified encrypted user preferences file
206+ // / </summary>
207+ // / <param name="file_path">Path to the encrypted UserPreferences.bag</param>
208+ // / <param name="machine_guid">Machine GUID used to encrypt the UserPreferences.bag</param>
209+ // / <param name="salt_string">Salt used to encrypt UserPreferences.bag</param>
210+ // / <returns>Decrypted user preferences</returns>
211+ std::string DecryptUserPreferences (const std::string& file_path, const std::string& machine_guid, const std::string& salt_string)
212+ {
213+ std::vector<uint8_t > salt_bytes;
214+ boost::algorithm::unhex (salt_string.begin (), salt_string.end (), std::back_inserter (salt_bytes));
231215
232216 auto machine_guid_bytes = std::vector<uint8_t >(machine_guid.begin (), machine_guid.end () - 1 );
233217 auto mangled_data = MangleData (machine_guid_bytes);
234218
235219 std::vector<uint8_t > key;
236220 std::vector<uint8_t > initialization_vector;
237- if (!GetKeys (kSalt , mangled_data, key, initialization_vector))
238- {
239- std::cerr << " Failed to generate keys" << std::endl;
240- return EXIT_FAILURE;
241- }
221+ GetKeys (salt_bytes, mangled_data, key, initialization_vector);
242222
243- std::string path_to_decrypt;
244- if (argc == 2 )
245- {
246- path_to_decrypt = std::string (argv[1 ]);
247- }
248- else
249- {
250- path_to_decrypt = GetPathToUserPreferencesBag ();
251- }
223+ auto cipher_text = ReadAllBytes (file_path);
224+ auto plaintext = Decrypt (cipher_text, key, initialization_vector);
225+
226+ return std::string (plaintext.begin (), plaintext.end ());
227+ }
252228
253- auto cipher_text = ReadAllBytes (path_to_decrypt);
254- if (cipher_text.empty ())
229+ int main (int argc, char * argv[])
230+ {
231+ static const auto kSalt = std::string (" 6E3F032949637D2E" );
232+
233+ try
255234 {
256- std::cerr << " ReadAllBytes - FAILED " << std::endl ;
257- return EXIT_FAILURE ;
258- }
235+ auto user_preferences_path = GetPathToUserPreferencesBag () ;
236+ auto machine_guid = GetMachineGuid () ;
237+ auto salt = kSalt ;
259238
260- auto plaintext = std::vector<uint8_t >(cipher_text.size ());
261- if (!Decrypt (cipher_text, key, initialization_vector, plaintext))
239+ auto decrypted_preferences = DecryptUserPreferences (user_preferences_path, machine_guid, salt);
240+ std::cout << decrypted_preferences << std::endl;
241+ }
242+ catch (const std::exception& ex)
262243 {
263- std::cerr << " Decrypt - FAILED " << std::endl;
244+ std::cerr << " Failed to decrypt user preferences: " << ex. what () << std::endl;
264245 return EXIT_FAILURE;
265246 }
266-
267- std::cout << &plaintext[0 ] << std::endl;
268-
247+
269248 return EXIT_SUCCESS;
270249}
0 commit comments