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

Interop

static class Interop
From https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptEncryptDecrypt.cs SHOULD NOT BE CHANGED WITHOUT COORDINATING WITH BCL TEAM
using System; using System.Runtime.InteropServices; using System.Security.Cryptography; namespace Azure.Storage.Shared.AesGcm { internal static class Interop { internal static class BCrypt { internal struct BCRYPT_KEY_DATA_BLOB_HEADER { public uint dwMagic; public uint dwVersion; public uint cbKeyData; public const uint BCRYPT_KEY_DATA_BLOB_MAGIC = 1296188491; public const uint BCRYPT_KEY_DATA_BLOB_VERSION1 = 1; } internal struct BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO { private int cbSize; private uint dwInfoVersion; internal unsafe byte* pbNonce; internal int cbNonce; internal unsafe byte* pbAuthData; internal int cbAuthData; internal unsafe byte* pbTag; internal int cbTag; internal unsafe byte* pbMacContext; internal int cbMacContext; internal int cbAAD; internal ulong cbData; internal uint dwFlags; public unsafe static BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO Create() { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO result = default(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO); result.cbSize = sizeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO); result.dwInfoVersion = 1; return result; } } internal static class BCryptAeadHandleCache { internal static SafeAlgorithmHandle AesGcm { get; } = OpenAlgorithm("AES", "ChainingModeGCM"); private static SafeAlgorithmHandle OpenAlgorithm(string algId, string chainingMode = null) { SafeAlgorithmHandle safeAlgorithmHandle = BCryptOpenAlgorithmProvider(algId, null, 0); if (chainingMode != null) SetCipherMode(safeAlgorithmHandle, chainingMode); return safeAlgorithmHandle; } } internal enum NTSTATUS : uint { STATUS_SUCCESS = 0, STATUS_NOT_FOUND = 3221226021, STATUS_INVALID_PARAMETER = 3221225485, STATUS_NO_MEMORY = 3221225495, STATUS_AUTH_TAG_MISMATCH = 3221266434 } internal sealed class SafeAlgorithmHandle : SafeBCryptHandle { protected sealed override bool ReleaseHandle() { return BCryptCloseAlgorithmProvider(handle, 0) == 0; } [DllImport("BCrypt.dll")] private static extern uint BCryptCloseAlgorithmProvider(IntPtr hAlgorithm, int dwFlags); } internal sealed class SafeKeyHandle : SafeBCryptHandle { private SafeAlgorithmHandle _parentHandle; public void SetParentHandle(SafeAlgorithmHandle parentHandle) { bool success = false; parentHandle.DangerousAddRef(ref success); _parentHandle = parentHandle; } protected sealed override bool ReleaseHandle() { if (_parentHandle != null) { _parentHandle.DangerousRelease(); _parentHandle = null; } return BCryptDestroyKey(handle) == 0; } [DllImport("BCrypt.dll")] private static extern uint BCryptDestroyKey(IntPtr hKey); } internal unsafe static int BCryptEncrypt(SafeKeyHandle hKey, ReadOnlySpan<byte> input, byte[] iv, Span<byte> output) { fixed (byte* pbInput = &input.GetPinnableReference()) { fixed (byte* pbOutput = &output.GetPinnableReference()) { int cbResult; NTSTATUS nTSTATUS = BCryptEncrypt(hKey, pbInput, input.Length, IntPtr.Zero, iv, (iv != null) ? iv.Length : 0, pbOutput, output.Length, out cbResult, 0); if (nTSTATUS != 0) throw CreateCryptographicException(nTSTATUS); return cbResult; } } } internal unsafe static int BCryptDecrypt(SafeKeyHandle hKey, ReadOnlySpan<byte> input, byte[] iv, Span<byte> output) { fixed (byte* pbInput = &input.GetPinnableReference()) { fixed (byte* pbOutput = &output.GetPinnableReference()) { int cbResult; NTSTATUS nTSTATUS = BCryptDecrypt(hKey, pbInput, input.Length, IntPtr.Zero, iv, (iv != null) ? iv.Length : 0, pbOutput, output.Length, out cbResult, 0); if (nTSTATUS != 0) throw CreateCryptographicException(nTSTATUS); return cbResult; } } } [DllImport("BCrypt.dll")] internal unsafe static extern NTSTATUS BCryptEncrypt(SafeKeyHandle hKey, byte* pbInput, int cbInput, IntPtr paddingInfo, byte[] pbIV, int cbIV, byte* pbOutput, int cbOutput, out int cbResult, int dwFlags); [DllImport("BCrypt.dll")] internal unsafe static extern NTSTATUS BCryptDecrypt(SafeKeyHandle hKey, byte* pbInput, int cbInput, IntPtr paddingInfo, byte[] pbIV, int cbIV, byte* pbOutput, int cbOutput, out int cbResult, int dwFlags); internal unsafe static SafeKeyHandle BCryptImportKey(SafeAlgorithmHandle hAlg, ReadOnlySpan<byte> key) { int length = key.Length; int num = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + length; int num2 = 64; int num3 = num2; Span<byte> span = new Span<byte>(stackalloc byte[(int)(uint)num3], num3); if (num > num2) span = new byte[num]; else span.Clear(); fixed (byte* ptr = &span.GetPinnableReference()) { BCRYPT_KEY_DATA_BLOB_HEADER* ptr2 = (BCRYPT_KEY_DATA_BLOB_HEADER*)ptr; ptr2->dwMagic = 1296188491; ptr2->dwVersion = 1; ptr2->cbKeyData = (uint)length; key.CopyTo(span.Slice(sizeof(BCRYPT_KEY_DATA_BLOB_HEADER))); SafeKeyHandle hKey; NTSTATUS nTSTATUS = BCryptImportKey(hAlg, IntPtr.Zero, "KeyDataBlob", out hKey, IntPtr.Zero, 0, ptr, num, 0); if (nTSTATUS != 0) throw CreateCryptographicException(nTSTATUS); return hKey; } } [DllImport("BCrypt.dll", CharSet = CharSet.Unicode)] private unsafe static extern NTSTATUS BCryptImportKey(SafeAlgorithmHandle hAlgorithm, IntPtr hImportKey, string pszBlobType, out SafeKeyHandle hKey, IntPtr pbKeyObject, int cbKeyObject, byte* pbInput, int cbInput, int dwFlags); internal static CryptographicException CreateCryptographicException(NTSTATUS ntstatus) { return CreateCryptographicException((int)ntstatus); } internal static CryptographicException CreateCryptographicException(int hr) { return new CryptographicException(hr); } private static void SetCipherMode(SafeAlgorithmHandle hAlg, string cipherMode) { NTSTATUS nTSTATUS = BCryptSetProperty(hAlg, "ChainingMode", cipherMode, (cipherMode.Length + 1) * 2, 0); if (nTSTATUS != 0) throw CreateCryptographicException(nTSTATUS); } private static SafeAlgorithmHandle BCryptOpenAlgorithmProvider(string pszAlgId, string pszImplementation, int dwFlags) { SafeAlgorithmHandle phAlgorithm; NTSTATUS nTSTATUS = BCryptOpenAlgorithmProvider(out phAlgorithm, pszAlgId, pszImplementation, dwFlags); if (nTSTATUS != 0) throw CreateCryptographicException(nTSTATUS); return phAlgorithm; } [DllImport("BCrypt.dll", CharSet = CharSet.Unicode)] private static extern NTSTATUS BCryptOpenAlgorithmProvider(out SafeAlgorithmHandle phAlgorithm, string pszAlgId, string pszImplementation, int dwFlags); [DllImport("BCrypt.dll", CharSet = CharSet.Unicode)] private static extern NTSTATUS BCryptSetProperty(SafeAlgorithmHandle hObject, string pszProperty, string pbInput, int cbInput, int dwFlags); } } }