- Status
- Offline
- Joined
- Mar 3, 2026
- Messages
- 381
- Reaction score
- 7
If you are looking to protect your payloads, data blobs, or cheat assets from simple string scans and basic reversing, you need more than a generic XOR wrapper. I found this clean C# implementation that handles file encryption with a decent security stack.
This isn't just a simple AES paste. It uses PBKDF2 for key derivation with 100,000 iterations and SHA512, which makes brute-forcing significantly more expensive. It also integrates GZip compression before encryption, which is a nice touch for reducing the final file size and making the data structure less predictable for heuristic scanners.
Technical Stack:
Implementation Notes:
While this provides a solid cryptographic foundation, remember that the "FUD" status depends on how you handle the executable itself. If you're building a loader, use this to decrypt your DLL or shellcode in memory rather than dropping it to disk. The 100k iteration count is great for security but might cause a slight delay on low-end systems when dealing with large assets.
If you're using this in a production environment, make sure to handle the Pepper storage correctly—hardcoding it defeats the purpose if someone dumps your memory.
anyone tweaked this to use different cipher modes like GCM?
This isn't just a simple AES paste. It uses PBKDF2 for key derivation with 100,000 iterations and SHA512, which makes brute-forcing significantly more expensive. It also integrates GZip compression before encryption, which is a nice touch for reducing the final file size and making the data structure less predictable for heuristic scanners.
Technical Stack:
- AES-256 (CBC Mode) with PKCS7 Padding.
- PBKDF2 with 100,000 iterations for key derivation.
- SHA512 hashing algorithm.
- SecureString usage to minimize the footprint of passwords in memory.
- Dynamic Pepper and Salt generation.
- Automatic GZip compression/decompression.
Code:
using System;
using System.IO;
using System.IO.Compression;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Encryption
{
public sealed class Encryptor : IDisposable
{
private const int KeySize = 256; // AES-256
private const int Iterations = 100000; // PBKDF2 iteration count
private const int SaltSize = 128; // 128-bit salt
private const int PepperSize = 32; // 256-bit pepper
private const int MinPasswordLength = 12;
private readonly byte[] _pepper;
private bool _disposed = false;
public Encryptor()
{
try
{
// Generate application-specific pepper
_pepper = new byte[PepperSize];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(_pepper);
}
}
catch (Exception ex)
{
throw new CryptographicException("Failed to initialize encryptor", ex);
}
}
public void EncryptFile(string inputFile, string outputFile, SecureString password)
{
ValidateParameters(inputFile, outputFile, password);
try
{
byte[] salt = GenerateSalt();
byte[] compressedData = CompressFile(inputFile);
byte[] passwordBytes = SecureStringToBytes(password);
try
{
PerformEncryption(outputFile, salt, compressedData, passwordBytes);
}
finally
{
SecureClear(compressedData);
SecureClear(passwordBytes);
}
}
catch (Exception ex) when (!(ex is OperationCanceledException))
{
throw new CryptographicException($"Encryption failed: {ex.Message}", ex);
}
}
public void DecryptFile(string inputFile, string outputFile, SecureString password)
{
ValidateParameters(inputFile, outputFile, password);
try
{
byte[] passwordBytes = SecureStringToBytes(password);
try
{
byte[] salt = ReadSaltFromFile(inputFile);
byte[] decryptedData = PerformDecryption(inputFile, passwordBytes, salt);
DecompressToFile(decryptedData, outputFile);
SecureClear(decryptedData);
}
finally
{
SecureClear(passwordBytes);
}
}
catch (CryptographicException)
{
throw; // Preserve original cryptographic exceptions
}
catch (Exception ex) when (!(ex is OperationCanceledException))
{
throw new CryptographicException($"Decryption failed: {ex.Message}", ex);
}
}
#region Core Operations
private byte[] GenerateSalt()
{
var salt = new byte[SaltSize / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
return salt;
}
private void PerformEncryption(string outputFile, byte[] salt, byte[] data, byte[] passwordBytes)
{
using (var derivedKey = new Rfc2898DeriveBytes(
password: Combine(passwordBytes, salt),
salt: Combine(salt, _pepper),
iterations: Iterations,
hashAlgorithm: HashAlgorithmName.SHA512))
{
byte[] key = derivedKey.GetBytes(KeySize / 8);
byte[] iv = derivedKey.GetBytes(128 / 8);
try
{
using (var aes = Aes.Create())
{
ConfigureAes(aes, key, iv);
WriteEncryptedFile(outputFile, salt, data, aes);
}
}
finally
{
SecureClear(key);
SecureClear(iv);
}
}
}
private byte[] PerformDecryption(string inputFile, byte[] passwordBytes, byte[] salt)
{
using (var derivedKey = new Rfc2898DeriveBytes(
password: Combine(passwordBytes, salt),
salt: Combine(salt, _pepper),
iterations: Iterations,
hashAlgorithm: HashAlgorithmName.SHA512))
{
byte[] key = derivedKey.GetBytes(KeySize / 8);
byte[] iv = derivedKey.GetBytes(128 / 8);
try
{
using (var aes = Aes.Create())
{
ConfigureAes(aes, key, iv);
return ReadAndDecryptFile(inputFile, salt.Length, aes);
}
}
finally
{
SecureClear(key);
SecureClear(iv);
}
}
}
#endregion
#region File Operations
private byte[] CompressFile(string inputFile)
{
try
{
using (var memoryStream = new MemoryStream())
{
using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal, leaveOpen: true))
using (var fileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read))
{
fileStream.CopyTo(gzipStream);
}
return memoryStream.ToArray();
}
}
catch (IOException ex)
{
throw new InvalidOperationException($"Compression failed for {inputFile}", ex);
}
}
private void DecompressToFile(byte[] compressedData, string outputFile)
{
try
{
using (var memoryStream = new MemoryStream(compressedData))
using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
using (var fileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
{
gzipStream.CopyTo(fileStream);
}
}
catch (InvalidDataException ex)
{
throw new InvalidOperationException("Invalid compressed data format", ex);
}
catch (IOException ex)
{
throw new InvalidOperationException($"Failed to write decompressed file to {outputFile}", ex);
}
}
private byte[] ReadSaltFromFile(string inputFile)
{
try
{
using (var fileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
{
byte[] salt = new byte[SaltSize / 8];
int bytesRead = fileStream.Read(salt, 0, salt.Length);
if (bytesRead != salt.Length)
{
throw new InvalidDataException("File is too short to contain salt");
}
return salt;
}
}
catch (IOException ex)
{
throw new InvalidOperationException($"Failed to read salt from {inputFile}", ex);
}
}
private void WriteEncryptedFile(string outputPath, byte[] salt, byte[] data, SymmetricAlgorithm algorithm)
{
try
{
using (var fileStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
{
// Write salt
fileStream.Write(salt, 0, salt.Length);
// Write encrypted data
using (var cryptoStream = new CryptoStream(
fileStream,
algorithm.CreateEncryptor(),
CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
}
}
}
catch (IOException ex)
{
throw new InvalidOperationException($"Failed to write encrypted file to {outputPath}", ex);
}
}
private byte[] ReadAndDecryptFile(string inputPath, int saltLength, SymmetricAlgorithm algorithm)
{
try
{
using (var fileStream = new FileStream(inputPath, FileMode.Open, FileAccess.Read))
{
// Skip salt
fileStream.Position = saltLength;
using (var memoryStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(
fileStream,
algorithm.CreateDecryptor(),
CryptoStreamMode.Read))
{
cryptoStream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
}
catch (IOException ex)
{
throw new InvalidOperationException($"Failed to read encrypted file from {inputPath}", ex);
}
}
#endregion
#region Security Utilities
private byte[] SecureStringToBytes(SecureString secureString)
{
IntPtr bstr = IntPtr.Zero;
try
{
bstr = Marshal.SecureStringToBSTR(secureString);
int length = Marshal.ReadInt32(bstr, -4);
byte[] bytes = new byte[length];
for (int i = 0; i < length; i++)
{
bytes[i] = Marshal.ReadByte(bstr, i);
}
return bytes;
}
finally
{
if (bstr != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(bstr);
}
}
}
private void SecureClear(byte[] data)
{
if (data != null)
{
Array.Clear(data, 0, data.Length);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private byte[] Combine(byte[] first, byte[] second)
{
var combined = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, combined, 0, first.Length);
Buffer.BlockCopy(second, 0, combined, first.Length, second.Length);
return combined;
}
private void ConfigureAes(SymmetricAlgorithm algorithm, byte[] key, byte[] iv)
{
algorithm.Key = key;
algorithm.IV = iv;
algorithm.Mode = CipherMode.CBC;
algorithm.Padding = PaddingMode.PKCS7;
}
#endregion
#region Validation
private void ValidateParameters(string inputFile, string outputFile, SecureString password)
{
if (string.IsNullOrWhiteSpace(inputFile))
throw new ArgumentNullException(nameof(inputFile), "Input file path cannot be empty");
if (string.IsNullOrWhiteSpace(outputFile))
throw new ArgumentNullException(nameof(outputFile), "Output file path cannot be empty");
if (password == null)
throw new ArgumentNullException(nameof(password), "Password cannot be null");
if (password.Length < MinPasswordLength)
throw new ArgumentException($"Password must be at least {MinPasswordLength} characters", nameof(password));
if (!File.Exists(inputFile))
throw new FileNotFoundException("Input file not found", inputFile);
try
{
string outputDir = Path.GetDirectoryName(outputFile);
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
}
catch (Exception ex)
{
throw new ArgumentException($"Invalid output path: {ex.Message}", nameof(outputFile), ex);
}
}
#endregion
#region IDisposable Implementation
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing && _pepper != null)
{
SecureClear(_pepper);
}
_disposed = true;
}
}
~Encryptor()
{
Dispose(false);
}
#endregion
}
}
Implementation Notes:
While this provides a solid cryptographic foundation, remember that the "FUD" status depends on how you handle the executable itself. If you're building a loader, use this to decrypt your DLL or shellcode in memory rather than dropping it to disk. The 100k iteration count is great for security but might cause a slight delay on low-end systems when dealing with large assets.
If you're using this in a production environment, make sure to handle the Pepper storage correctly—hardcoding it defeats the purpose if someone dumps your memory.
anyone tweaked this to use different cipher modes like GCM?