<PackageReference Include="Azure.Storage.Blobs" Version="12.25.0" />

AesGcmWindows

sealed class AesGcmWindows : IDisposable
Taken from https://github.com/dotnet/runtime/blob/main/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/AeadCommon.Windows.cs SHOULD NOT BE CHANGED WITHOUT COORDINATING WITH BCL TEAM
using System; using System.Security.Cryptography; namespace Azure.Storage.Shared.AesGcm { internal sealed class AesGcmWindows : IDisposable { private const int NonceSize = 12; private Interop.BCrypt.SafeKeyHandle _keyHandle; internal static KeySizes NonceByteSizes { get; } = new KeySizes(12, 12, 1); internal static KeySizes TagByteSizes { get; } = new KeySizes(12, 16, 1); internal static bool IsSupported => true; internal AesGcmWindows(ReadOnlySpan<byte> key) { ThrowIfNotSupported(); Errors.CheckCryptKeySize(key.Length); ImportKey(key); } internal AesGcmWindows(byte[] key) { ThrowIfNotSupported(); Errors.ThrowIfParamNull(key, "key"); Errors.CheckCryptKeySize(key.Length); ImportKey(key); } internal void Encrypt(byte[] nonce, byte[] plaintext, byte[] ciphertext, byte[] tag, byte[] associatedData = null) { Errors.ThrowIfParamNull(nonce, "nonce"); Errors.ThrowIfParamNull(plaintext, "plaintext"); Errors.ThrowIfParamNull(ciphertext, "ciphertext"); Errors.ThrowIfParamNull(tag, "tag"); Encrypt((ReadOnlySpan<byte>)nonce, (ReadOnlySpan<byte>)plaintext, (Span<byte>)ciphertext, (Span<byte>)tag, (ReadOnlySpan<byte>)associatedData); } internal void Encrypt(ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> plaintext, Span<byte> ciphertext, Span<byte> tag, ReadOnlySpan<byte> associatedData = default(ReadOnlySpan<byte>)) { CheckParameters(plaintext, ciphertext, nonce, tag); EncryptCore(nonce, plaintext, ciphertext, tag, associatedData); } internal void Decrypt(byte[] nonce, byte[] ciphertext, byte[] tag, byte[] plaintext, byte[] associatedData = null) { Errors.ThrowIfParamNull(nonce, "nonce"); Errors.ThrowIfParamNull(ciphertext, "ciphertext"); Errors.ThrowIfParamNull(tag, "tag"); Errors.ThrowIfParamNull(plaintext, "plaintext"); Decrypt((ReadOnlySpan<byte>)nonce, (ReadOnlySpan<byte>)ciphertext, (ReadOnlySpan<byte>)tag, (Span<byte>)plaintext, (ReadOnlySpan<byte>)associatedData); } internal void Decrypt(ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> ciphertext, ReadOnlySpan<byte> tag, Span<byte> plaintext, ReadOnlySpan<byte> associatedData = default(ReadOnlySpan<byte>)) { CheckParameters(plaintext, ciphertext, nonce, tag); DecryptCore(nonce, ciphertext, tag, plaintext, associatedData); } private static void CheckParameters(ReadOnlySpan<byte> plaintext, ReadOnlySpan<byte> ciphertext, ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> tag) { if (plaintext.Length != ciphertext.Length) Errors.CryptographyPlaintextCiphertextLengthMismatch(); if (!nonce.Length.IsLegalSize(NonceByteSizes)) Errors.CryptographyInvalidNonceLength(); if (!tag.Length.IsLegalSize(TagByteSizes)) Errors.CryptographyInvalidTagLength(); } private static void ThrowIfNotSupported() { } private void ImportKey(ReadOnlySpan<byte> key) { _keyHandle = Interop.BCrypt.BCryptImportKey(Interop.BCrypt.BCryptAeadHandleCache.AesGcm, key); } private void EncryptCore(ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> plaintext, Span<byte> ciphertext, Span<byte> tag, ReadOnlySpan<byte> associatedData = default(ReadOnlySpan<byte>)) { AeadCommon.Encrypt(_keyHandle, nonce, associatedData, plaintext, ciphertext, tag); } private void DecryptCore(ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> ciphertext, ReadOnlySpan<byte> tag, Span<byte> plaintext, ReadOnlySpan<byte> associatedData = default(ReadOnlySpan<byte>)) { AeadCommon.Decrypt(_keyHandle, nonce, associatedData, ciphertext, tag, plaintext, true); } public void Dispose() { _keyHandle.Dispose(); } } }