File Encryptor — C# source
Encrypt or decrypt any file with AES-256-GCM in your browser. Password-based, zero server contact. Drag, drop, done.
This is the C# implementation — the same logic the interactive tool runs, in a shareable, citable form.
// File Encryptor — password-based AES-256-GCM file encryption.
//
// Language: C# (.NET 8+, standard library only)
// Source: CosmoDev polyglot showcase port of the File Encryptor tool, ported
// from src/lib/file-encryptor.ts (the canonical TypeScript
// implementation).
// License: display source — part of CosmoDev's polyglot tool pages.
//
// Wire format: salt (16 B) || IV (12 B) || AES-256-GCM ciphertext + tag.
// The 256-bit key is derived from the password with PBKDF2-SHA256 and a fresh
// random salt per encryption, so the same file + password never encrypts to
// the same bytes, and the password itself is never stored or derivable from
// the output.
using System;
using System.Security.Cryptography;
using System.Text;
public static class FileEncryptor
{
public const int SaltLength = 16;
public const int IvLength = 12;
public const int Iterations = 100_000;
// GCM appends a 16-byte auth tag to the ciphertext; the smallest possible
// encrypted payload is therefore salt + IV + tag = 44 bytes.
private const int TagLength = 16;
private const int MinLength = SaltLength + IvLength + TagLength;
/// <summary>PBKDF2-SHA256 (100k iterations) → a 256-bit AES key.</summary>
private static byte[] DeriveKey(string password, byte[] salt) =>
Rfc2898DeriveBytes.Pbkdf2(
Encoding.UTF8.GetBytes(password), salt, Iterations, HashAlgorithmName.SHA256, 32);
/// <summary>Encrypt <paramref name="data"/> under <paramref name="password"/>.
/// Returns salt || IV || ciphertext+tag.</summary>
public static byte[] EncryptFile(byte[] data, string password)
{
if (string.IsNullOrEmpty(password))
{
throw new ArgumentException("Password must not be empty.");
}
if (data.Length == 0)
{
throw new ArgumentException("Input data is empty - nothing to encrypt.");
}
var salt = new byte[SaltLength];
var iv = new byte[IvLength];
RandomNumberGenerator.Fill(salt);
RandomNumberGenerator.Fill(iv);
var key = DeriveKey(password, salt);
var ciphertext = new byte[data.Length + TagLength];
try
{
using var aes = new AesGcm(key, TagLength);
aes.Encrypt(iv, data, ciphertext[..data.Length], ciphertext[data.Length..]);
}
finally
{
CryptographicOperations.ZeroMemory(key);
}
var output = new byte[SaltLength + IvLength + ciphertext.Length];
Buffer.BlockCopy(salt, 0, output, 0, SaltLength);
Buffer.BlockCopy(iv, 0, output, SaltLength, IvLength);
Buffer.BlockCopy(ciphertext, 0, output, SaltLength + IvLength, ciphertext.Length);
return output;
}
/// <summary>
/// Decrypt a payload produced by <see cref="EncryptFile"/>. Throws when the
/// password is wrong or the payload was corrupted/tampered (GCM auth-tag
/// failure).
/// </summary>
public static byte[] DecryptFile(byte[] data, string password)
{
if (string.IsNullOrEmpty(password))
{
throw new ArgumentException("Password must not be empty.");
}
if (data.Length < MinLength)
{
throw new ArgumentException(
$"Input is too short to be an encrypted file (needs at least {MinLength} bytes: salt + IV + auth tag).");
}
var salt = data[..SaltLength];
var iv = data[SaltLength..(SaltLength + IvLength)];
var ciphertext = data[(SaltLength + IvLength)..];
var plaintext = new byte[ciphertext.Length - TagLength];
var key = DeriveKey(password, salt);
try
{
using var aes = new AesGcm(key, TagLength);
// A GCM auth-tag failure means the key did not match (wrong
// password) or the payload was modified after encryption.
aes.Decrypt(iv, ciphertext[..plaintext.Length], ciphertext[plaintext.Length..], plaintext);
}
catch (CryptographicException)
{
throw new CryptographicException("Decryption failed: wrong password or corrupted file.");
}
finally
{
CryptographicOperations.ZeroMemory(key);
}
return plaintext;
}
}
Also available in 8 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →