using System.Buffers.Binary;
using System.Security.Cryptography;
public static class Program
public static void Main()
string password = "very secure password";
using var aesObj = new AesGcmService(password);
string plain = "This is a test message.";
Console.WriteLine($"Plain: \"{plain}\"");
string enc = aesObj.Encrypt(plain);
Console.WriteLine($"Encrypted: \"{enc}\"");
string dec = aesObj.Decrypt(enc);
Console.WriteLine($"Decrypted: \"{dec}\"");
public class AesGcmService : IDisposable
private readonly AesGcm _aes;
public AesGcmService(string password)
byte[] key = new Rfc2898DeriveBytes(password, new byte[8], 1000).GetBytes(16);
public string Encrypt(string plain)
byte[] plainBytes = Encoding.UTF8.GetBytes(plain);
int nonceSize = AesGcm.NonceByteSizes.MaxSize;
int tagSize = AesGcm.TagByteSizes.MaxSize;
int cipherSize = plainBytes.Length;
int encryptedDataLength = 4 + nonceSize + 4 + tagSize + cipherSize;
Span<byte> encryptedData = encryptedDataLength < 1024 ? stackalloc byte[encryptedDataLength] : new byte[encryptedDataLength].AsSpan();
BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(0, 4), nonceSize);
BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4), tagSize);
var nonce = encryptedData.Slice(4, nonceSize);
var tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);
RandomNumberGenerator.Fill(nonce);
_aes.Encrypt(nonce, plainBytes.AsSpan(), cipherBytes, tag);
return Convert.ToBase64String(encryptedData);
public string Decrypt(string cipher)
Span<byte> encryptedData = Convert.FromBase64String(cipher).AsSpan();
int nonceSize = BinaryPrimitives.ReadInt32LittleEndian(encryptedData.Slice(0, 4));
int tagSize = BinaryPrimitives.ReadInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4));
int cipherSize = encryptedData.Length - 4 - nonceSize - 4 - tagSize;
var nonce = encryptedData.Slice(4, nonceSize);
var tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);
Span<byte> plainBytes = cipherSize < 1024 ? stackalloc byte[cipherSize] : new byte[cipherSize];
_aes.Decrypt(nonce, cipherBytes, tag, plainBytes);
return Encoding.UTF8.GetString(plainBytes);