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

GcmAuthenticatedCryptographicTransform

using Azure.Storage.Cryptography.Models; using System; using System.Security.Cryptography; namespace Azure.Storage.Cryptography { internal class GcmAuthenticatedCryptographicTransform : IAuthenticatedCryptographicTransform, IDisposable { private AesGcm _gcm; private long _nonceCounter = 1; public TransformMode TransformMode { get; } public int NonceLength => 12; public int TagLength => 16; public GcmAuthenticatedCryptographicTransform(byte[] key, TransformMode mode) { TransformMode = mode; _gcm = new AesGcm(key); } public int TransformAuthenticationBlock(ReadOnlySpan<byte> input, Span<byte> output) { switch (TransformMode) { case TransformMode.Encrypt: { ReadOnlySpan<byte> newNonce = GetNewNonce(); Span<byte> tag = new Span<byte>(new byte[TagLength]); newNonce.CopyTo(output.Slice(0, NonceLength)); _gcm.Encrypt(newNonce, input, output.Slice(NonceLength, input.Length), tag, default(ReadOnlySpan<byte>)); tag.CopyTo(output.Slice(NonceLength + input.Length, TagLength)); return NonceLength + input.Length + TagLength; } case TransformMode.Decrypt: { int length = input.Length - NonceLength - TagLength; _gcm.Decrypt(input.Slice(0, NonceLength), input.Slice(NonceLength, length), input.Slice(input.Length - TagLength, TagLength), output.Slice(0, length), default(ReadOnlySpan<byte>)); return input.Length - NonceLength - TagLength; } default: throw new InvalidOperationException("TransformMode invalid for this operation."); } } public void Dispose() { _gcm.Dispose(); } private ReadOnlySpan<byte> GetNewNonce() { Span<byte> span = new Span<byte>(new byte[NonceLength]); int num = NonceLength - 8; new byte[4].CopyTo(span.Slice(0, num)); BitConverter.GetBytes(_nonceCounter++).CopyTo(span.Slice(num, 8)); return span; } } }