0

I'm prompting the user for input (a security token in this case). Then I'm encrypting it using DPAPI, and storing it in a text file for later use. The issue I'm having is that when I decrypt the file, it sometimes (often) has random trailing characters, and I can't figure out what the problem is.

Below are the functions I'm using to encrypt and decrypt the files

bool AuthManager::Encrypt(FString InString)
{
    const int32 Size = InString.Len();
    TArray<uint8> Data;
    Data.AddUninitialized(Size);
    StringToBytes(InString, Data.GetData(), Size);
    
    // Encrypt data from DATA_BLOB DataIn to DATA_BLOB DataOut.
    DATA_BLOB DataIn, DataOut;
    
    BYTE* PbDataInput = Data.GetData();
    const DWORD CBDataInput = strlen(reinterpret_cast<char*>(PbDataInput));
    
    DataIn.pbData = PbDataInput;    
    DataIn.cbData = CBDataInput;
    
    if(CryptProtectData(
         &DataIn,
         nullptr,
         nullptr,
         nullptr,
         nullptr,
         0,
         &DataOut))
    {
        const char* EncryptedTokenFile = "path\\to\\encryptedTokenFile.txt";
        
        std::ofstream EncryptedFile(EncryptedTokenFile, std::ios::out | std::ios::binary);
        
        EncryptedFile.write(reinterpret_cast<char*>(&DataOut.cbData), sizeof(DataOut.cbData));  
        EncryptedFile.write(reinterpret_cast<char*>(DataOut.pbData), DataOut.cbData); 
        EncryptedFile.close();
        LocalFree(DataOut.pbData);
    }
    else
    {
        UE_LOG(LogConsoleResponse, Error, TEXT("Encryption error using CryptProtectData."));
        return false;
    }
    return true;
}

//////////////////////////////////////////////////////////////////////
    
bool AuthManager::Decrypt(FString& OutString)
{
    const char* EncryptedTokenFile = "path\\to\\encryptedTokenFile.txt";
    
    std::ifstream ReadEncryptedFile(EncryptedTokenFile, std::ios::in | std::ios::binary);
    
    if(!ReadEncryptedFile.is_open())
    {
        UE_LOG(LogConsoleResponse, Error, TEXT("Cannot open %s. Please verify the file exists and is not read-protected."), *GetTokenFilePath());
        return false;
    }
    
    // Encrypt data from DATA_BLOB DataIn to DATA_BLOB DataOut.
    DATA_BLOB DataIn, DataOut;
    LPWSTR DataDesc = nullptr;
    
    ReadEncryptedFile.read(reinterpret_cast<char*>(&DataIn.cbData), sizeof(DataIn.cbData));  
    DataIn.pbData = new BYTE[DataIn.cbData];  
    ReadEncryptedFile.read(reinterpret_cast<char*>(DataIn.pbData), DataIn.cbData);
    
    // Begin unprotect phase.
    if (CryptUnprotectData(
            &DataIn,
            &DataDesc,
            nullptr,
            nullptr,
            nullptr,
            0,
            &DataOut))
    {

        // Convert byte output into FString
        OutString = BytesToString(DataOut.pbData, DataOut.cbData);
        
        UE_LOG(LogConsoleResponse, Display, TEXT("The OutString is: %s"), *OutString);
        
        LocalFree(DataOut.pbData);
        LocalFree(DataDesc);
    }
    else
    {
        UE_LOG(LogConsoleResponse, Error, TEXT("Decryption error using CryptUnprotectData."));
        return false;
    }
    
    return true;
}

I've tried increasing or decreasing the number of characters into the buffer, but it's inconsistent

  • Your call to `strlen` on the encryption path requires a terminating NUL-byte, which is very probably not always true. Set `CBDataInput = Size` instead. You also seem to assume that the input string only contains ASCII, as `StringToBytes` may produce more bytes than the number of characters (`Size`) otherwise. – Botje Mar 16 '23 at 08:47
  • Thank you, and yes the input string should only ever be ascii. However, how should I dummy-proof it just in case it doesn't? – MashedPotato6587 Mar 16 '23 at 16:41

0 Answers0