Clean up some usage of SHA1 and SHA256 in the code base (#24696)
* AntiForgery: Use SHA256 one-shot * AuthN: Use SHA256 one-shot APIs * MVC/Razor: Cleanup SHA256 references * WebSockets: Use SHA1 one-shots * dotnet-openapi: Use preferred SHA256 factory * SignalR: Prefer RNG.Fill over RNG.GetBytes
This commit is contained in:
parent
adea6638cc
commit
bbf7c8780c
|
|
@ -2,7 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
|
|
@ -35,12 +35,8 @@ namespace Microsoft.AspNetCore.Antiforgery
|
||||||
|
|
||||||
private static string ComputeCookieName(string applicationId)
|
private static string ComputeCookieName(string applicationId)
|
||||||
{
|
{
|
||||||
using (var sha256 = CryptographyAlgorithms.CreateSHA256())
|
byte[] fullHash = SHA256.HashData(Encoding.UTF8.GetBytes(applicationId));
|
||||||
{
|
return WebEncoders.Base64UrlEncode(fullHash, 0, 8);
|
||||||
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(applicationId));
|
|
||||||
var subHash = hash.Take(8).ToArray();
|
|
||||||
return WebEncoders.Base64UrlEncode(subHash);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ namespace Microsoft.AspNetCore.Antiforgery
|
||||||
private MemoryStream? _stream;
|
private MemoryStream? _stream;
|
||||||
private BinaryReader? _reader;
|
private BinaryReader? _reader;
|
||||||
private BinaryWriter? _writer;
|
private BinaryWriter? _writer;
|
||||||
private SHA256? _sha256;
|
|
||||||
|
|
||||||
public MemoryStream Stream
|
public MemoryStream Stream
|
||||||
{
|
{
|
||||||
|
|
@ -82,23 +81,6 @@ namespace Microsoft.AspNetCore.Antiforgery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SHA256 Sha256
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_sha256 == null)
|
|
||||||
{
|
|
||||||
_sha256 = CryptographyAlgorithms.CreateSHA256();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _sha256;
|
|
||||||
}
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
_sha256 = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public char[] GetChars(int count)
|
public char[] GetChars(int count)
|
||||||
{
|
{
|
||||||
if (_chars == null || _chars.Length < count)
|
if (_chars == null || _chars.Length < count)
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Antiforgery
|
|
||||||
{
|
|
||||||
internal static class CryptographyAlgorithms
|
|
||||||
{
|
|
||||||
public static SHA256 CreateSHA256()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return SHA256.Create();
|
|
||||||
}
|
|
||||||
// SHA256.Create is documented to throw this exception on FIPS compliant machines.
|
|
||||||
// See: https://msdn.microsoft.com/en-us/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
|
|
||||||
catch (System.Reflection.TargetInvocationException)
|
|
||||||
{
|
|
||||||
// Fallback to a FIPS compliant SHA256 algorithm.
|
|
||||||
return new SHA256CryptoServiceProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Antiforgery
|
namespace Microsoft.AspNetCore.Antiforgery
|
||||||
|
|
@ -134,9 +135,13 @@ namespace Microsoft.AspNetCore.Antiforgery
|
||||||
|
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
|
|
||||||
var sha256 = serializationContext.Sha256;
|
bool success = serializationContext.Stream.TryGetBuffer(out ArraySegment<byte> buffer);
|
||||||
var stream = serializationContext.Stream;
|
if (!success)
|
||||||
var bytes = sha256.ComputeHash(stream.ToArray(), 0, checked((int)stream.Length));
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = SHA256.HashData(buffer);
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,23 +110,20 @@ namespace Microsoft.AspNetCore.WebSockets
|
||||||
// this concatenated value to obtain a 20-byte value and base64-encoding"
|
// this concatenated value to obtain a 20-byte value and base64-encoding"
|
||||||
// https://tools.ietf.org/html/rfc6455#section-4.2.2
|
// https://tools.ietf.org/html/rfc6455#section-4.2.2
|
||||||
|
|
||||||
using (var algorithm = SHA1.Create())
|
// requestKey is already verified to be small (24 bytes) by 'IsRequestKeyValid()' and everything is 1:1 mapping to UTF8 bytes
|
||||||
|
// so this can be hardcoded to 60 bytes for the requestKey + static websocket string
|
||||||
|
Span<byte> mergedBytes = stackalloc byte[60];
|
||||||
|
Encoding.UTF8.GetBytes(requestKey, mergedBytes);
|
||||||
|
EncodedWebSocketKey.CopyTo(mergedBytes.Slice(24));
|
||||||
|
|
||||||
|
Span<byte> hashedBytes = stackalloc byte[20];
|
||||||
|
var written = SHA1.HashData(mergedBytes, hashedBytes);
|
||||||
|
if (written != 20)
|
||||||
{
|
{
|
||||||
// requestKey is already verified to be small (24 bytes) by 'IsRequestKeyValid()' and everything is 1:1 mapping to UTF8 bytes
|
throw new InvalidOperationException("Could not compute the hash for the 'Sec-WebSocket-Accept' header.");
|
||||||
// so this can be hardcoded to 60 bytes for the requestKey + static websocket string
|
|
||||||
Span<byte> mergedBytes = stackalloc byte[60];
|
|
||||||
Encoding.UTF8.GetBytes(requestKey, mergedBytes);
|
|
||||||
EncodedWebSocketKey.CopyTo(mergedBytes.Slice(24));
|
|
||||||
|
|
||||||
Span<byte> hashedBytes = stackalloc byte[20];
|
|
||||||
var success = algorithm.TryComputeHash(mergedBytes, hashedBytes, out var written);
|
|
||||||
if (!success || written != 20)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Could not compute the hash for the 'Sec-WebSocket-Accept' header.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Convert.ToBase64String(hashedBytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Convert.ToBase64String(hashedBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor.Infrastructure
|
|
||||||
{
|
|
||||||
internal static class CryptographyAlgorithms
|
|
||||||
{
|
|
||||||
public static SHA256 CreateSHA256()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return SHA256.Create();
|
|
||||||
}
|
|
||||||
// SHA256.Create is documented to throw this exception on FIPS compliant machines.
|
|
||||||
// See: https://msdn.microsoft.com/en-us/library/z08hz7ad%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
|
|
||||||
catch (System.Reflection.TargetInvocationException)
|
|
||||||
{
|
|
||||||
// Fallback to a FIPS compliant SHA256 algorithm.
|
|
||||||
return new SHA256CryptoServiceProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
|
|
@ -97,7 +98,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Infrastructure
|
||||||
|
|
||||||
private static string GetHashForFile(IFileInfo fileInfo)
|
private static string GetHashForFile(IFileInfo fileInfo)
|
||||||
{
|
{
|
||||||
using (var sha256 = CryptographyAlgorithms.CreateSHA256())
|
using (var sha256 = SHA256.Create())
|
||||||
{
|
{
|
||||||
using (var readStream = fileInfo.CreateReadStream())
|
using (var readStream = fileInfo.CreateReadStream())
|
||||||
{
|
{
|
||||||
|
|
@ -107,4 +108,4 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Infrastructure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
|
||||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
|
namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
|
||||||
|
|
@ -180,12 +179,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
|
||||||
// The key is typically too long to be useful, so we use a cryptographic hash
|
// The key is typically too long to be useful, so we use a cryptographic hash
|
||||||
// as the actual key (better randomization and key distribution, so small vary
|
// as the actual key (better randomization and key distribution, so small vary
|
||||||
// values will generate dramatically different keys).
|
// values will generate dramatically different keys).
|
||||||
using (var sha256 = CryptographyAlgorithms.CreateSHA256())
|
var contentBytes = Encoding.UTF8.GetBytes(key);
|
||||||
{
|
var hashedBytes = SHA256.HashData(contentBytes);
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(key);
|
return Convert.ToBase64String(hashedBytes);
|
||||||
var hashedBytes = sha256.ComputeHash(contentBytes);
|
|
||||||
return Convert.ToBase64String(hashedBytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,7 @@ namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
||||||
// Store this for use during the code redemption.
|
// Store this for use during the code redemption.
|
||||||
properties.Items.Add(OAuthConstants.CodeVerifierKey, codeVerifier);
|
properties.Items.Add(OAuthConstants.CodeVerifierKey, codeVerifier);
|
||||||
|
|
||||||
using var sha256 = SHA256.Create();
|
var challengeBytes = SHA256.HashData(Encoding.UTF8.GetBytes(codeVerifier));
|
||||||
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
|
|
||||||
var codeChallenge = WebEncoders.Base64UrlEncode(challengeBytes);
|
var codeChallenge = WebEncoders.Base64UrlEncode(challengeBytes);
|
||||||
|
|
||||||
queryStrings[OAuthConstants.CodeChallengeKey] = codeChallenge;
|
queryStrings[OAuthConstants.CodeChallengeKey] = codeChallenge;
|
||||||
|
|
|
||||||
|
|
@ -280,8 +280,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
// Store this for use during the code redemption.
|
// Store this for use during the code redemption.
|
||||||
properties.Items.Add(OAuthConstants.CodeVerifierKey, codeVerifier);
|
properties.Items.Add(OAuthConstants.CodeVerifierKey, codeVerifier);
|
||||||
|
|
||||||
using var sha256 = SHA256.Create();
|
var challengeBytes = SHA256.HashData(Encoding.UTF8.GetBytes(codeVerifier));
|
||||||
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
|
|
||||||
var codeChallenge = WebEncoders.Base64UrlEncode(challengeBytes);
|
var codeChallenge = WebEncoders.Base64UrlEncode(challengeBytes);
|
||||||
|
|
||||||
parameters[OAuthConstants.CodeChallengeKey] = codeChallenge;
|
parameters[OAuthConstants.CodeChallengeKey] = codeChallenge;
|
||||||
|
|
|
||||||
|
|
@ -375,8 +375,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||||
// Store this for use during the code redemption. See RunAuthorizationCodeReceivedEventAsync.
|
// Store this for use during the code redemption. See RunAuthorizationCodeReceivedEventAsync.
|
||||||
properties.Items.Add(OAuthConstants.CodeVerifierKey, codeVerifier);
|
properties.Items.Add(OAuthConstants.CodeVerifierKey, codeVerifier);
|
||||||
|
|
||||||
using var sha256 = SHA256.Create();
|
var challengeBytes = SHA256.HashData(Encoding.UTF8.GetBytes(codeVerifier));
|
||||||
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
|
|
||||||
var codeChallenge = WebEncoders.Base64UrlEncode(challengeBytes);
|
var codeChallenge = WebEncoders.Base64UrlEncode(challengeBytes);
|
||||||
|
|
||||||
message.Parameters.Add(OAuthConstants.CodeChallengeKey, codeChallenge);
|
message.Parameters.Add(OAuthConstants.CodeChallengeKey, codeChallenge);
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
|
||||||
// TODO: Consider making this configurable? At least for testing?
|
// TODO: Consider making this configurable? At least for testing?
|
||||||
private static readonly TimeSpan _heartbeatTickRate = TimeSpan.FromSeconds(1);
|
private static readonly TimeSpan _heartbeatTickRate = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
private static readonly RNGCryptoServiceProvider _keyGenerator = new RNGCryptoServiceProvider();
|
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, (HttpConnectionContext Connection, ValueStopwatch Timer)> _connections =
|
private readonly ConcurrentDictionary<string, (HttpConnectionContext Connection, ValueStopwatch Timer)> _connections =
|
||||||
new ConcurrentDictionary<string, (HttpConnectionContext Connection, ValueStopwatch Timer)>(StringComparer.Ordinal);
|
new ConcurrentDictionary<string, (HttpConnectionContext Connection, ValueStopwatch Timer)>(StringComparer.Ordinal);
|
||||||
private readonly TimerAwaitable _nextHeartbeat;
|
private readonly TimerAwaitable _nextHeartbeat;
|
||||||
|
|
@ -113,7 +111,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
|
||||||
// 128 bit buffer / 8 bits per byte = 16 bytes
|
// 128 bit buffer / 8 bits per byte = 16 bytes
|
||||||
Span<byte> buffer = stackalloc byte[16];
|
Span<byte> buffer = stackalloc byte[16];
|
||||||
// Generate the id with RNGCrypto because we want a cryptographically random id, which GUID is not
|
// Generate the id with RNGCrypto because we want a cryptographically random id, which GUID is not
|
||||||
_keyGenerator.GetBytes(buffer);
|
RandomNumberGenerator.Fill(buffer);
|
||||||
return WebEncoders.Base64UrlEncode(buffer);
|
return WebEncoders.Base64UrlEncode(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -513,19 +513,7 @@ namespace Microsoft.DotNet.OpenApi.Commands
|
||||||
|
|
||||||
private static byte[] GetHash(Stream stream)
|
private static byte[] GetHash(Stream stream)
|
||||||
{
|
{
|
||||||
SHA256 algorithm;
|
using (var algorithm = SHA256.Create())
|
||||||
try
|
|
||||||
{
|
|
||||||
algorithm = SHA256.Create();
|
|
||||||
}
|
|
||||||
catch (TargetInvocationException)
|
|
||||||
{
|
|
||||||
// SHA256.Create is documented to throw this exception on FIPS-compliant machines. See
|
|
||||||
// https://msdn.microsoft.com/en-us/library/z08hz7ad Fall back to a FIPS-compliant SHA256 algorithm.
|
|
||||||
algorithm = new SHA256CryptoServiceProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
using (algorithm)
|
|
||||||
{
|
{
|
||||||
return algorithm.ComputeHash(stream);
|
return algorithm.ComputeHash(stream);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue