dotnet-aes-extra

The library leverages the AES implementation of .NET; it does not contain the AES primitive itself. Instead, it adds modes of AES that are not in available in .NET / .NET Core / .NET Framework.

The library exposes its objects modeled after default .NET classes, so its usage is straightforward.

The API includes both the classic byte[] as well as the modern Span<byte> overloads.

There are two builds of the library included in th package, one for .NET Standard 2.0 and one for .NET 8 (or higher). The public API is the same for both, but internally the builds slightly differ:

  • The .NET Standard build depends on Microsoft.Bcl.AsyncInterfaces and Microsoft.Bcl.Memory for ValueTask and Span support.

  • The .NET 8 build uses CryptographicOperations for ZeroMemory and FixedTimeEquals, whereas the .NET Standard build uses an internal implementation backported from the original .NET 8 code.

  • The .NET 8 build supports trimming.

Example

// SPDX-FileCopyrightText: 2025 Frans van Dorsselaer
//
// SPDX-License-Identifier: MIT

using System.Security.Cryptography;
using Dorssel.Security.Cryptography;

// example data
const int AesBlockSizeInBytes = 16;
var plaintext = new byte[] { 1, 2, 3 };
var key = RandomNumberGenerator.GetBytes(32);
var iv = RandomNumberGenerator.GetBytes(AesBlockSizeInBytes);
var salt = RandomNumberGenerator.GetBytes(8);
var associatedData = new byte[] { 4, 5 };

// AES-CTR (use like .NET's Aes)
using var aesCtr = new AesCtr(key);
var ciphertextCtr = aesCtr.TransformCtr(plaintext, iv);

// AES-CMAC (use like .NET's HMACSHA256)
using var aesCmac = new AesCmac(key);
var tagCmac = aesCmac.ComputeHash(plaintext);

// SIV-AES (use like .NET's AesGcm)
using var aesSiv = new AesSiv(key);
var ciphertextSiv = new byte[AesBlockSizeInBytes + plaintext.Length];
aesSiv.Encrypt(plaintext, ciphertextSiv, associatedData);

// AES-CMAC-PRF-128 (use like .NET's HKDF)
var derivedKey = AesCmacPrf128.DeriveKey(key, plaintext);

// PBKDF2-AES-CMAC-PRF-128 (use like .NET's Rfc2898DeriveBytes)
var passwordBasedDerivedKey = AesCmacPrf128.Pbkdf2("password", salt, 1000, 32);