| File: CryptoUtil.cs | Web Access |
| Project: src\aspnetcore\src\DataProtection\Cryptography.Internal\src\Microsoft.AspNetCore.Cryptography.Internal.csproj (Microsoft.AspNetCore.Cryptography.Internal) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security.Cryptography; using Microsoft.AspNetCore.Cryptography.Cng; using Microsoft.AspNetCore.Cryptography.Internal; namespace Microsoft.AspNetCore.Cryptography; internal static unsafe class CryptoUtil { // This isn't a typical Debug.Assert; the check is always performed, even in retail builds. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Assert([DoesNotReturnIf(false)] bool condition, string message) { if (!condition) { Fail(message); } } // This isn't a typical Debug.Assert; the check is always performed, even in retail builds. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void AssertSafeHandleIsValid(SafeHandle safeHandle) { Assert(safeHandle != null && !safeHandle.IsInvalid, "Safe handle is invalid."); } // Asserts that the current platform is Windows; throws PlatformNotSupportedException otherwise. public static void AssertPlatformIsWindows() { if (!OSVersionUtil.IsWindows()) { throw new PlatformNotSupportedException(Resources.Platform_Windows7Required); } } // Asserts that the current platform is Windows 8 or above; throws PlatformNotSupportedException otherwise. public static void AssertPlatformIsWindows8OrLater() { if (!OSVersionUtil.IsWindows8OrLater()) { throw new PlatformNotSupportedException(Resources.Platform_Windows8Required); } } // This isn't a typical Debug.Fail; an error always occurs, even in retail builds. // This method doesn't return, but since the CLR doesn't allow specifying a 'never' // return type, we mimic it by specifying our return type as Exception. That way // callers can write 'throw Fail(...);' to make the C# compiler happy, as the // throw keyword is implicitly of type O. [MethodImpl(MethodImplOptions.NoInlining)] public static Exception Fail(string message) { Debug.Fail(message); throw new CryptographicException("Assertion failed: " + message); } // Allows callers to write "var x = Method() ?? Fail<T>(message);" as a convenience to guard // against a method returning null unexpectedly. [MethodImpl(MethodImplOptions.NoInlining)] public static T Fail<T>(string message) where T : class { throw Fail(message); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] #if NETSTANDARD2_0 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] #endif public static bool TimeConstantBuffersAreEqual(byte* bufA, byte* bufB, uint count) { #if NETCOREAPP var byteCount = Convert.ToInt32(count); var bytesA = new ReadOnlySpan<byte>(bufA, byteCount); var bytesB = new ReadOnlySpan<byte>(bufB, byteCount); return CryptographicOperations.FixedTimeEquals(bytesA, bytesB); #else bool areEqual = true; for (uint i = 0; i < count; i++) { areEqual &= (bufA[i] == bufB[i]); } return areEqual; #endif } #if NET || NETSTANDARD2_1_OR_GREATER // CryptographicOperations.ZeroMemory is itself [NoInlining | NoOptimization]; // inlining this wrapper just leaves a direct call [MethodImpl(MethodImplOptions.AggressiveInlining)] #else [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] #endif public static void ZeroMemory(byte[] buffer) { #if NET || NETSTANDARD2_1_OR_GREATER CryptographicOperations.ZeroMemory(buffer); #else Array.Clear(buffer, 0, buffer.Length); #endif } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static bool TimeConstantBuffersAreEqual(ReadOnlySpan<byte> bufA, ReadOnlySpan<byte> bufB) { // This early exit handles unexpected input without introducing timing vulnerabilities. Assert(bufA.Length == bufB.Length, "countA == countB"); #if NETCOREAPP return CryptographicOperations.FixedTimeEquals(bufA, bufB); #else bool areEqual = true; for (int i = 0; i < bufA.Length; i++) { areEqual &= (bufA[i] == bufB[i]); } return areEqual; #endif } }