A Delphi library that provides compile-time string encryption with enhanced runtime memory protection. Protects sensitive strings from both static analysis tools (like Ghidra) and provides significant memory protection during execution.
- β Encrypted in Binary: Strings are stored as encrypted byte arrays in the compiled executable
- β Hidden Encryption Key: The actual encryption key never appears in the binary - only encrypted bytes
- β Salt-Based Key Encryption: Key is XOR encrypted with salt
- β Ghidra-Proof: Static analysis tools cannot find plain-text strings or the actual key
- β Hex Editor Safe: No readable strings or keys visible in binary files
- β ISecureString Interface: Enhanced memory protection using reference-counted secure strings
- β Automatic Cleanup: Secure strings automatically clear memory when going out of scope
- β Secure Buffer Clearing: Temporary decryption buffers are immediately zeroed after use
- β Key Recovery: Actual key is reconstructed at runtime from encrypted bytes
β οΈ Limited by Delphi: Perfect memory protection is impossible due to automatic string copyingβ οΈ Concatenation Risk: String concatenation (+
operator) creates uncontrolled copies
- Install the Plugin Package: Open
src/LitCryptPlugin.dpk
in Delphi and Install it - Add Library Path: Go to Tools β Options β Language β Delphi β Library
- Library path - Click the "..." button next to Library path
- Add the full path to your
src
folder (e.g.,C:\YourPath\Delphi LitCrypt Plugin_v.1.1\src
) - Click OK to save
- Restart Delphi
- Verify: Tools β Encrypt Selected String Ctrl+Shift+E and Decrypt Selected String Ctrl+Shift+D menu appears
The LitCrypt
unit is now available in all your projects through the library path! Simply add it to your uses clause:
uses
System.SysUtils,
LitCrypt; // Available via library path - automatically initializes!
No file copying needed - Delphi will automatically find LitCrypt.pas
in the library path.
No manual initialization needed - The encryption system initializes automatically when the unit loads.
program MySecureApp;
uses LitCrypt; // That's it! No manual initialization needed.
begin
// Write your code with plain strings
WriteLn('Database password: ' + 'my-secret-password');
WriteLn('API Key: ' + 'sk-1234567890abcdef');
end.
- Select the string including quotes:
'my-secret-password'
- Press
Ctrl+Shift+E
(or Tools β Encrypt Selected String) - Result: String becomes
DecryptString([$66, $2A, $2D, ...])
// Before encryption
WriteLn('Database password: ' + 'my-secret-password');
// After encryption (done by plugin)
WriteLn('Database password: ' + DecryptString([$66, $2A, $2D, $32, $2A, $74, $66, $32, $2C, $33, $32, $67, $74, $2D, $26, $66, $66, $2E, $7B, $33, $75, $1A, $1B, $1C]));
- Key Encryption: The actual encryption key is XOR encrypted with a salt
- String Encryption: Selected strings are encrypted using XOR cipher with the actual key
- Code Generation: Replaces plain strings with
DecryptString([byte array])
- Binary Storage: Only encrypted key bytes and salt bytes are stored in the binary
- Key Recovery:
EncryptedKey XOR Salt = ActualKey
- String Decryption:
EncryptedString XOR ActualKey = PlainText
- Secure Memory Handling: All intermediate buffers are cleared after use
- Result: Original string is returned for immediate use
function DecryptString(const EncryptedData: array of Byte): string;
var
SecureStr: ISecureString;
begin
// Use secure decryption and return the data
// The secure string will auto-clear when this function exits
SecureStr := DecryptSecure(EncryptedData);
Result := SecureStr.Data; // Creates a copy - this is the limitation
end;
1. DecryptString() - Standard Usage:
var
Password: string;
begin
Password := DecryptString([$66, $2A, $2D, ...]); // Creates persistent copy
WriteLn('Password: ' + Password); // String concatenation creates more copies
end;
- β Secure decryption process
- β Returned string persists in memory
- β String operations create additional copies
2. DecryptSecure() - Enhanced Protection:
var
Password: ISecureString;
begin
Password := DecryptSecure([$66, $2A, $2D, ...]); // Secure container
WriteLn(Password.Data); // Direct output, minimal copies
// Password automatically cleared when going out of scope
end;
- β Secure decryption process
- β Automatic memory clearing on scope exit
β οΈ Accessing.Data
still creates temporary copies
Security Measure | DecryptString() | DecryptSecure() | Description |
---|---|---|---|
Secure Decryption | β | β | Temporary buffers cleared during decryption |
Automatic Cleanup | β | β | Memory cleared when variable goes out of scope |
Reference Counting | β | β | Uses Delphi's interface system for automatic cleanup |
Buffer Zeroing | β | β | SecureZeroMemory clears intermediate data |
Global Key Protection | β | β | Key cleared at program finalization |
β SAFE PRACTICES:
// Direct output without concatenation
SecStr := DecryptSecure([...]);
WriteLn(SecStr.Data);
// Separate operations
Write('Password: ');
WriteLn(SecStr.Data);
β UNSAFE PRACTICES:
// String concatenation creates persistent copies
WriteLn('Password: ' + SecStr.Data); // BREAKS MEMORY PROTECTION!
// Assignment to regular string variables
MyPassword := DecryptString([...]); // Creates persistent copy
- β Automatic String Copying: Delphi's string system creates copies automatically
- β Non-deterministic Cleanup: Garbage collection timing is unpredictable
- β Concatenation Risk: The
+
operator always creates new string objects - β No Ownership System: Unlike Rust, Delphi can't prevent uncontrolled copying
To verify the memory protection differences:
// Test 1: Standard approach (will persist in memory)
var Password: string;
begin
Password := DecryptString([$66, $2A, $2D, ...]);
WriteLn('Password: ' + Password); // Multiple copies created
end;
// Test 2: Secure approach (minimal memory exposure)
var SecStr: ISecureString;
begin
SecStr := DecryptSecure([$66, $2A, $2D, ...]);
WriteLn(SecStr.Data); // Direct output, auto-cleanup
end;
Testing Steps:
- Compile your program with both approaches
- Run a memory analyzer (Process Hacker, System Informer, etc.)
- Search for your decrypted strings in process memory
- Compare results between the two approaches
Expected Results:
- β Static analysis: No plaintext strings in binary
β οΈ Memory analysis: Secure approach shows significantly fewer instances- β Perfect protection: Not achievable due to Delphi's string system
Tool | What They See | Status |
---|---|---|
Strings Command | No plain text strings | β Protected |
Hex Editors | Only encrypted bytes 08 5C 5C 06 |
β Protected |
Ghidra/IDA Pro | Encrypted byte arrays, no readable keys | β Protected |
Attack Vector | DecryptString() | DecryptSecure() | Notes |
---|---|---|---|
Memory Dumps | β Enhanced | Secure version clears automatically | |
Debugger Inspection | β Visible | Strings still temporarily visible | |
Process Memory Scan | β Persistent | β Minimal | Depends on usage patterns |
String Concatenation | β Creates copies | β Still creates copies | Fundamental limitation |
Best Case Scenario (DecryptSecure + Careful Usage):
- Decrypted strings exist in memory only during scope lifetime
- Automatic cleanup when variables go out of scope
- Significantly reduced memory exposure compared to standard approach
Worst Case Scenario (DecryptString + Concatenation):
- Multiple persistent copies in memory
- No automatic cleanup
- Similar to storing plain text strings
Practical Reality:
- β Significant improvement over plain text storage
- β Automatic cleanup in many scenarios
β οΈ Not perfect due to Delphi language limitations- β String concatenation always breaks protection
π Use DecryptSecure() with direct output for best memory protection!
After installing the plugin, you must add the src
folder to your Delphi library path:
- Tools β Options β Language β Delphi β Library
- Library path - Click "..." next to "Library path"
- Add the full path to your
src
folder- Example:
C:\YourPath\Delphi LitCrypt Plugin_v.1.1\src
- Example:
- Click OK to save
This makes LitCrypt.pas
available to all your projects without copying files.
- Encryption key is encrypted with salt during compilation
- Same key derivation approach ensures consistent encryption/decryption
- No external dependencies - works on any computer
βββ src/ # Plugin & Runtime Library
β βββ LitCryptPlugin.dpk # Plugin package (Build & Install)
β βββ LitCrypt.pas # Runtime library (add src to library path)
β βββ LitCryptIDEPlugin.pas # IDE integration
β βββ LitCryptCore.pas # Plugin encryption logic
β
βββ tools/ # Utility Tools
β βββ KeyGenerator/ # Key generation utility
β βββ KeyGenerator.dpr # Generates secure encryption keys and salts
β
βββ demo/ # Examples
β βββ Demo.dpr # Example usage
β
βββ README.md # This file
# Compile your program, then test with strings command
strings MyProgram.exe | grep "my-secret-password"
# Should return nothing if properly encrypted
You can use System Informer for this.
- β Static analysis - Strings are encrypted, actual key is hidden
- β Automated string extraction tools - No plain-text strings in executable
- β Casual reverse engineering - Requires understanding of XOR decryption
- β Memory analysis - Keys and strings are cleared after use
- β Binary inspection - Actual encryption key never appears in binary
- β Determined reverse engineers with time and XOR knowledge
- β Runtime code injection attacks
- β Cryptographic attacks (uses simple XOR cipher)
- β Social engineering or other attack vectors
β οΈ Salt discovery (salt bytes might be identifiable in binary)
- Use for obfuscation and moderate security against casual analysis
- Significant improvement over plain text storage
- Salt-based approach hides the actual key from static analysis
- Combine with other security measures for high-security applications
- Works consistently across all computers without external dependencies
program MyApp;
uses LitCrypt;
begin
// Before
ConnectionString := 'Server=prod;Password=secret123;';
// After encryption
ConnectionString := DecryptString([$53, $32, $33, $76, $32, $33, ...]);
end.