Skip to content

Latest commit

 

History

History
300 lines (236 loc) · 11.5 KB

README.md

File metadata and controls

300 lines (236 loc) · 11.5 KB

Delphi LitCrypt - String Encryption with Disk & Memory Protection

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.

🔒 Security Features

Disk Protection (Static Analysis)

  • ✅ 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

Memory Protection (Runtime Analysis)

  • ✅ 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

🚀 Quick Start

1. Install the Plugin

  1. Install the Plugin Package: Open src/LitCryptPlugin.dpk in Delphi and Install it
  2. 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
  3. Restart Delphi
  4. Verify: Tools → Encrypt Selected String Ctrl+Shift+E and Decrypt Selected String Ctrl+Shift+D menu appears

2. Use in Your Projects

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.

3. Use Encrypted Strings

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.

4. Encrypt Strings

  1. Select the string including quotes: 'my-secret-password'
  2. Press Ctrl+Shift+E (or Tools → Encrypt Selected String)
  3. 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]));

🔧 How It Works

Encryption Process (Compile Time)

  1. Key Encryption: The actual encryption key is XOR encrypted with a salt
  2. String Encryption: Selected strings are encrypted using XOR cipher with the actual key
  3. Code Generation: Replaces plain strings with DecryptString([byte array])
  4. Binary Storage: Only encrypted key bytes and salt bytes are stored in the binary

Decryption Process (Runtime)

  1. Key Recovery: EncryptedKey XOR Salt = ActualKey
  2. String Decryption: EncryptedString XOR ActualKey = PlainText
  3. Secure Memory Handling: All intermediate buffers are cleared after use
  4. 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;

🛡️ Memory Protection

Two-Tier Protection System

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

Memory Protection Features

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

Critical Memory Protection Rules

✅ 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

Delphi Limitations:

  • ❌ 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

Testing Memory Protection

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:

  1. Compile your program with both approaches
  2. Run a memory analyzer (Process Hacker, System Informer, etc.)
  3. Search for your decrypted strings in process memory
  4. 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

🛡️ Security Analysis

Protection Against Static Analysis

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

Protection Against Memory Analysis

Attack Vector DecryptString() DecryptSecure() Notes
Memory Dumps ⚠️ Limited ✅ Enhanced Secure version clears automatically
Debugger Inspection ❌ Visible ⚠️ Reduced Strings still temporarily visible
Process Memory Scan ❌ Persistent ✅ Minimal Depends on usage patterns
String Concatenation ❌ Creates copies ❌ Still creates copies Fundamental limitation

Real-World Memory Protection

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!

Key Security

  • Encryption key is encrypted with salt during compilation
  • Same key derivation approach ensures consistent encryption/decryption
  • No external dependencies - works on any computer

📁 Project Structure

├── 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

🔍 Testing Security

Test Static Analysis Protection

# Compile your program, then test with strings command
strings MyProgram.exe | grep "my-secret-password"
# Should return nothing if properly encrypted

Test Memory Analysis Protection

You can use System Informer for this.

⚠️ Security Notes

What This Protects Against

  • ✅ 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

What This Does NOT Protect Against

  • ❌ 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)

Recommendations

  • 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 dependenciess