Skip to content

Core.Security

Dennis Steffen edited this page Jan 4, 2026 · 1 revision

This encryption system is designed as a modular plugin architecture for any system that requires data protection, such as asset loaders, save game managers, or network handlers. At its core is the IEncryptDecryptSink interface, which allows you to swap security strategies without changing the consuming code.

The IEncryptDecryptSink Implementations

Depending on your performance needs and security requirements, you can choose between three provided "sinks":

  1. DirectResourceSink (No Encryption)

    • Performance: Extremely fast (it just copies or returns the original data).
    • Security: None.
    • Use Case: Ideal for development, debugging, or public assets where encryption overhead is unnecessary.
  2. XnorResourceSink (Simple Encryption)

    • Performance: Very fast. It uses bitwise XNOR operations which are computationally cheap.
    • Security: Low. It provides basic obfuscation to prevent casual "plain-text" reading of your files but is vulnerable to determined reverse engineering.
    • Use Case: Good for assets that need a layer of protection without impacting CPU performance significantly.
  3. AesResourceSink (High Security)

    • Performance: Slowest. It uses AES-256 with PBKDF2 key derivation (100,000 iterations).
    • Security: High. This is standard-grade industry encryption.
    • Use Case: Use this for sensitive data like player save files, configuration settings containing credentials, or premium game content.

Important: Performance & Threading

Do not use these sinks on the main thread during active gameplay.

Because encryption (especially the AesResourceSink) involves heavy mathematical computations and potential I/O bottlenecks, running it on the main thread will cause hiccups and frame drops. Always perform resource loading and decryption on a background thread or via asynchronous tasks.


Usage Examples

1. Basic Setup and Selection

You can decide which sink to use based on the environment or the type of data:

using Meatcorps.Engine.Core.Interfaces.Security;
using Meatcorps.Engine.Core.Security.Sinks;

// For high security (Slow)
IEncryptDecryptSink secureSink = new AesResourceSink("YourSuperSecretPassword");

// For basic obfuscation (Fast)
IEncryptDecryptSink obfuscatedSink = new XnorResourceSink(0xAF);

// For no encryption (Immediate)
IEncryptDecryptSink nullSink = new DirectResourceSink();

2. Encrypting and Decrypting Data

The API is consistent regardless of the implementation chosen:

byte[] originalData = System.Text.Encoding.UTF8.GetBytes("Sensitive Game Data");

// Encrypt
byte[] encryptedData = secureSink.Encrypt(originalData);

// Decrypt
byte[] decryptedData = secureSink.Decrypt(encryptedData);
string result = System.Text.Encoding.UTF8.GetString(decryptedData);

3. Recommended Asynchronous Loading (Background Thread)

To avoid stuttering mid-game, wrap your decryption logic in a Task:

public async Task<byte[]> LoadResourceAsync(string path, IEncryptDecryptSink sink)
{
    // Run the decryption on the thread pool to keep the UI/Game thread smooth
    return await Task.Run(() =>
    {
        byte[] encryptedFile = File.ReadAllBytes(path);
        return sink.Decrypt(encryptedFile);
    });
}

4. Configuration Integration

In a real-world scenario, you might configure this via an asset manager:

public class MyGameAssetConfig : IAssetPackagerConfig
{
    // The main sink used for the entire project
    public IEncryptDecryptSink EncryptDecryptSink => new AesResourceSink("GlobalPassword123");

    public List<AssetPack> AssetPacks => new List<AssetPack>
    {
        new AssetPack
        {
            Name = "CoreAssets.pak",
            // You can override the sink for specific packs
            EncryptDecryptSink = new XnorResourceSink(0x42) 
        }
    };
}

Clone this wiki locally