Skip to content

Commit 15f049e

Browse files
Encrypts/decrypts tokens on saving/loading to json file (so that no tokens are stored in plain text.
1 parent 4148b74 commit 15f049e

File tree

3 files changed

+147
-6
lines changed

3 files changed

+147
-6
lines changed

src/elgato-cloud-data.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,17 @@ void ElgatoCloud::_LoadUserData(bool loadData)
498498

499499
void ElgatoCloud::_SaveState()
500500
{
501-
obs_data_set_string(_config, "AccessToken", _accessToken.c_str());
502-
obs_data_set_string(_config, "RefreshToken", _refreshToken.c_str());
501+
std::string accessTokenEncrypted = "";
502+
std::string refreshTokenEncrypted = "";
503+
if (_accessToken != "") {
504+
accessTokenEncrypted = encryptString(_accessToken);
505+
}
506+
if (_refreshToken != "") {
507+
refreshTokenEncrypted = encryptString(_refreshToken);
508+
}
509+
510+
obs_data_set_string(_config, "AccessToken", accessTokenEncrypted.c_str());
511+
obs_data_set_string(_config, "RefreshToken", refreshTokenEncrypted.c_str());
503512
obs_data_set_int(_config, "AccessTokenExpiration",
504513
_accessTokenExpiration);
505514
obs_data_set_int(_config, "RefreshTokenExpiration",
@@ -510,8 +519,20 @@ void ElgatoCloud::_SaveState()
510519

511520
void ElgatoCloud::_GetSavedState()
512521
{
513-
_accessToken = obs_data_get_string(_config, "AccessToken");
514-
_refreshToken = obs_data_get_string(_config, "RefreshToken");
522+
std::string accessTokenEncrypted = obs_data_get_string(_config, "AccessToken");
523+
std::string refreshTokenEncrypted = obs_data_get_string(_config, "RefreshToken");
524+
if (accessTokenEncrypted.size() > 25) {
525+
_accessToken = decryptString(accessTokenEncrypted);
526+
} else {
527+
_accessToken = "";
528+
}
529+
530+
if (refreshTokenEncrypted.size() > 25) {
531+
_refreshToken = decryptString(refreshTokenEncrypted);
532+
} else {
533+
_refreshToken = "";
534+
}
535+
515536
_accessTokenExpiration =
516537
obs_data_get_int(_config, "AccessTokenExpiration");
517538
_refreshTokenExpiration =

src/util.cpp

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ with this program. If not, see <https://www.gnu.org/licenses/>
3939
#include "platform.h"
4040
#include "util.h"
4141

42+
#pragma comment(lib, "crypt32.lib")
43+
#include <Windows.h>
44+
#include <Wincrypt.h>
45+
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
46+
4247
obs_data_t *get_module_config()
4348
{
4449
const auto confPath = obs_module_config_path("config.json");
@@ -516,4 +521,116 @@ std::string releaseType()
516521
c = tolower(c);
517522
}
518523
return rt == "release" ? "" : " " + rt;
519-
}
524+
}
525+
526+
std::string binaryToString(const BYTE* binaryData, DWORD dataLen, DWORD flags = CRYPT_STRING_BASE64) {
527+
DWORD stringLen = 0;
528+
// Get the required string length, not including the null terminator.
529+
if (!CryptBinaryToStringA(binaryData, dataLen, flags, nullptr, &stringLen)) {
530+
obs_log(LOG_ERROR, "Could not convert binary data to string.");
531+
return "";
532+
}
533+
534+
// Allocate memory for the string, including the null terminator.
535+
std::string encodedString;
536+
encodedString.resize(stringLen);
537+
538+
// Perform the actual conversion.
539+
if (!CryptBinaryToStringA(binaryData, dataLen, flags, encodedString.data(), &stringLen)) {
540+
obs_log(LOG_ERROR, "Could not convert binary data to string.");
541+
return "";
542+
}
543+
return encodedString;
544+
}
545+
546+
DATA_BLOB stringToBinary(const std::string& input, DWORD flags = CRYPT_STRING_BASE64) {
547+
DWORD binarySize = 0;
548+
DATA_BLOB output;
549+
output.pbData = nullptr;
550+
output.cbData = 0;
551+
// Get the required size for the binary data
552+
if (!CryptStringToBinaryA(input.c_str(), (DWORD)input.length(), flags, nullptr, &binarySize, nullptr, nullptr)) {
553+
obs_log(LOG_INFO, "Could not string to binary. Could not determine needed binary data size.");
554+
return output;
555+
}
556+
557+
// Allocate memory for the binary data
558+
output.pbData = (BYTE*)LocalAlloc(LMEM_FIXED, binarySize);
559+
if (output.pbData == nullptr) {
560+
obs_log(LOG_INFO, "Could not convert string to binary. Memory allocation error.");
561+
return output;
562+
}
563+
output.cbData = binarySize;
564+
// Perform the actual conversion
565+
if (!CryptStringToBinaryA(input.c_str(), (DWORD)input.length(), flags, output.pbData, &binarySize, nullptr, nullptr)) {
566+
obs_log(LOG_INFO, "Could not string to binary. Invalid conversion.");
567+
return output;
568+
}
569+
return output;
570+
}
571+
572+
// Encrypts a string, and returns string of encrypted binary data
573+
// as a formatted BASE 64 encoded string.
574+
std::string encryptString(std::string input)
575+
{
576+
DATA_BLOB DataIn;
577+
DATA_BLOB DataOut;
578+
BYTE* pbDataInput = (BYTE*)input.c_str();
579+
DWORD cbDataInput = DWORD(strlen((char*)pbDataInput) + 1);
580+
DataIn.pbData = pbDataInput;
581+
DataIn.cbData = cbDataInput;
582+
std::string encrypted = "";
583+
if (CryptProtectData(
584+
&DataIn,
585+
L"",
586+
NULL,
587+
NULL,
588+
NULL,
589+
0,
590+
&DataOut))
591+
{
592+
//convert binary to formatted base 64 encoded string.
593+
encrypted = binaryToString(DataOut.pbData, DataOut.cbData);
594+
LocalFree(DataOut.pbData);
595+
} else {
596+
obs_log(LOG_ERROR, "Could not encrypt string.");
597+
}
598+
return encrypted;
599+
}
600+
601+
// Decrypts a formatted base64 encoded string. First
602+
// converts string to binary blob, then uses windows
603+
// cryto API to decrypt the binary blob into a usable
604+
// string
605+
std::string decryptString(std::string input)
606+
{
607+
DATA_BLOB ToDecrypt = stringToBinary(input);
608+
if (ToDecrypt.pbData == nullptr) {
609+
return "";
610+
}
611+
DATA_BLOB DataVerify;
612+
LPWSTR pDescrOut = NULL;
613+
614+
std::string decrypted = "";
615+
616+
if (CryptUnprotectData(
617+
&ToDecrypt,
618+
&pDescrOut,
619+
NULL,
620+
NULL,
621+
NULL,
622+
0,
623+
&DataVerify))
624+
{
625+
decrypted = std::string(reinterpret_cast<char*>(DataVerify.pbData), DataVerify.cbData);
626+
LocalFree(DataVerify.pbData);
627+
LocalFree(pDescrOut);
628+
if (ToDecrypt.pbData != nullptr) {
629+
LocalFree(ToDecrypt.pbData);
630+
}
631+
} else {
632+
obs_log(LOG_ERROR, "Could not decrypt string.");
633+
}
634+
return decrypted;
635+
}
636+

src/util.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,7 @@ template<class T, class U> auto_closer<T, U> auto_close(T *self, U closer)
8484
bool generate_safe_path(std::string unsafe, std::string &safe);
8585
std::string versionNoBuild();
8686
std::string buildNumber();
87-
std::string releaseType();
87+
std::string releaseType();
88+
89+
std::string encryptString(std::string input);
90+
std::string decryptString(std::string input);

0 commit comments

Comments
 (0)