// src/GeoVLog.Core/Crypto/AesGcmHelper.cs // // Thin wrapper over that // enforces the GeoVLog crypto parameters: // // • 256-bit key (32 bytes) // • 96-bit IV (12 bytes, NIST-recommended for GCM) // • 128-bit authentication tag (16 bytes) // // Starting with .NET 8 the ctor new AesGcm(key) is **obsolete**; the // tag size must be specified explicitly. This helper hides that detail and // provides span-based Encrypt / Decrypt utilities with runtime checks. using System; using System.Security.Cryptography; namespace GeoVLog.Core.Crypto; /// /// AES-256-GCM encryption / decryption helpers with fixed IV and tag sizes. /// public static class AesGcmHelper { /// Required key length in bytes (256 bit). public const int KeySize = 32; /// Required nonce / IV length in bytes (96 bit). public const int IvSize = 12; /// Authentication-tag length in bytes (128 bit). public const int TagSize = 16; /// /// Encrypts with AES-256-GCM. /// /// Plaintext to encrypt. /// 32-byte AES key. /// /// Tuple containing a freshly generated IV, authentication tag, and /// ciphertext (same length as ). /// /// /// Thrown when length ≠ . /// public static (byte[] iv, byte[] tag, byte[] cipher) Encrypt( ReadOnlySpan plain, ReadOnlySpan key) { if (key.Length != KeySize) throw new ArgumentException("AES-256 key must be 32 bytes.", nameof(key)); byte[] iv = RandomNumberGenerator.GetBytes(IvSize); byte[] tag = new byte[TagSize]; byte[] cipher = new byte[plain.Length]; // Specify tag size to silence .NET 8 obsoletion warning using var aes = new AesGcm(key, TagSize); aes.Encrypt(iv, plain, cipher, tag); return (iv, tag, cipher); } /// /// Decrypts a GCM payload and verifies its authentication tag. /// /// Ciphertext bytes. /// 32-byte AES key. /// 12-byte nonce used during encryption. /// 16-byte authentication tag. /// Plaintext bytes. /// /// Thrown when tag verification fails. /// /// /// Thrown when any input buffer does not match expected size. /// public static byte[] Decrypt( ReadOnlySpan cipher, ReadOnlySpan key, ReadOnlySpan iv, ReadOnlySpan tag) { if (key.Length != KeySize) throw new ArgumentException("Key must be 32 bytes."); if (iv.Length != IvSize) throw new ArgumentException("IV must be 12 bytes."); if (tag.Length != TagSize) throw new ArgumentException("Tag must be 16 bytes."); byte[] plain = new byte[cipher.Length]; using var aes = new AesGcm(key, TagSize); aes.Decrypt(iv, cipher, tag, plain); return plain; } }