RustemSoft · .NET Protection

How does .NET String Encryption work?

This article explains how .NET string encryption protects sensitive literals, such as connection strings, license keys, and internal messages, from easy extraction and reverse engineering.

Short answer

.NET string encryption works by replacing readable string literals in your compiled assemblies with encrypted data and injecting decryption logic that runs only at runtime. The obfuscator encrypts each string using a key and algorithm, stores the ciphertext instead of the original text, and then transparently decrypts it when the code executes, making static analysis and simple decompilation much harder.

Core concept

What is .NET string encryption in practice?

In a typical .NET application, every string literal, error messages, SQL queries, API keys, internal protocol commands, ends up stored in the assembly metadata in plain text. A decompiler can list them instantly. String encryption is an obfuscation technique that transforms those literals into encrypted blobs and adds a small runtime routine that decrypts them only when needed.

From the perspective of your source code, you still write normal strings. The obfuscation step rewrites the compiled IL, injects an encryption key and algorithm, and replaces each literal with a call to a decryption helper. Attackers who inspect the binary see opaque data instead of meaningful text.

How it works internally

Step‑by‑step: how encryption is applied

1. Scan and collect string literals

The obfuscator analyzes the compiled assembly and finds all string literals that should be protected. You can usually configure which namespaces, classes, or attributes are in scope.

2. Encrypt each string with a key

For every selected literal, the tool applies a symmetric encryption algorithm (for example, AES or a custom variant) using a key that is embedded or derived at runtime. The result is binary ciphertext, often stored as a byte array or encoded string.

3. Rewrite IL to use a decryption helper

Instead of loading the original literal, the IL is modified to load the encrypted data and call a helper method like DecryptString(int id) or Decrypt(byte[] data). That helper contains the decryption logic and any key derivation.

4. Decrypt on demand at runtime

When the application runs and reaches the string usage, the helper decrypts the ciphertext in memory and returns the original text. The decrypted value typically lives only in RAM and is not stored back into the assembly.

5. Optional: cache or re‑encrypt

Some implementations cache decrypted strings for performance, while others avoid caching to reduce the window in which sensitive data is present in memory. Advanced obfuscators may also randomize keys or use per‑string keys to complicate analysis.

Example pattern in C# (conceptual)

// Original code
string message = "License validation failed";

// After obfuscation (conceptual)
string message = StringDecryptor.Decrypt(0x12AF); // 0x12AF indexes encrypted data

// Decryptor (simplified)
internal static class StringDecryptor
{
    public static string Decrypt(int id)
    {
        byte[] cipher = StringTable.GetCipher(id);
        byte[] key = KeyDerivation.GetKey();
        byte[] plain = AesLikeDecrypt(cipher, key);
        return System.Text.Encoding.UTF8.GetString(plain);
    }
}
Graph structure

String encryption flow (@graph structure)

The diagram below shows the logical flow from your source code to runtime decryption as a simple graph.

Source code
Developer writes normal string literals in C#/VB.NET.
Compilation
Strings are emitted into IL and assembly metadata in plain text.
Obfuscator
Scans IL, selects literals, encrypts them, and injects decryption helpers.
Protected assembly
Contains encrypted blobs and calls to decryption methods instead of raw strings.
Runtime decryption
When code executes, helper derives key and decrypts the required string in memory.
Execution
Application uses the decrypted value; attackers see only ciphertext in the binary.