Skip to content

Commit

Permalink
Use HMAC one-shot methods instead of instances
Browse files Browse the repository at this point in the history
  • Loading branch information
jevgenigeurtsen committed Jun 23, 2023
1 parent 93d73f0 commit a32e159
Showing 1 changed file with 28 additions and 9 deletions.
37 changes: 28 additions & 9 deletions src/ImageSharp.Web/HMACUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ public static class HMACUtilities
/// </summary>
public const string TokenCommand = "hmac";

/// <summary>
/// HMAC hash algorithms and their respective hash sizes in bytes.
/// </summary>
private enum HashAlgorithmSizes
{
HMACSHA256 = 32,
HMACSHA384 = 48,
HMACSHA512 = 64
}

/// <summary>
/// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA256 hash function.
/// </summary>
Expand All @@ -30,8 +40,7 @@ public static class HMACUtilities
/// <returns>The hashed <see cref="string"/>.</returns>
public static unsafe string ComputeHMACSHA256(string value, byte[] secret)
{
using HMACSHA256 hmac = new(secret);
return CreateHMAC(value, hmac);
return CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA256);
}

/// <summary>
Expand All @@ -45,8 +54,7 @@ public static unsafe string ComputeHMACSHA256(string value, byte[] secret)
/// <returns>The hashed <see cref="string"/>.</returns>
public static unsafe string ComputeHMACSHA384(string value, byte[] secret)
{
using HMACSHA384 hmac = new(secret);
return CreateHMAC(value, hmac);
return CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA384);
}

/// <summary>
Expand All @@ -60,12 +68,11 @@ public static unsafe string ComputeHMACSHA384(string value, byte[] secret)
/// <returns>The hashed <see cref="string"/>.</returns>
public static unsafe string ComputeHMACSHA512(string value, byte[] secret)
{
using HMACSHA512 hmac = new(secret);
return CreateHMAC(value, hmac);
return CreateHMAC(value, secret, HashAlgorithmSizes.HMACSHA512);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe string CreateHMAC(string value, HMAC hmac)
private static unsafe string CreateHMAC(string value, ReadOnlySpan<byte> secret, HashAlgorithmSizes hashSize)
{
int byteCount = Encoding.ASCII.GetByteCount(value);
byte[]? buffer = null;
Expand All @@ -80,8 +87,20 @@ private static unsafe string CreateHMAC(string value, HMAC hmac)
Encoding.ASCII.GetBytes(value, bytes);

// Safe to always stackalloc here. We max out at 64 bytes.
Span<byte> hash = stackalloc byte[hmac.HashSize / 8];
hmac.TryComputeHash(bytes, hash, out int _);
Span<byte> hash = stackalloc byte[(int)hashSize];
switch (hashSize)
{
default:
case HashAlgorithmSizes.HMACSHA256:
HMACSHA256.TryHashData(secret, bytes, hash, out _);
break;
case HashAlgorithmSizes.HMACSHA384:
HMACSHA384.TryHashData(secret, bytes, hash, out _);
break;
case HashAlgorithmSizes.HMACSHA512:
HMACSHA512.TryHashData(secret, bytes, hash, out _);
break;
}

// Finally encode the hash to make it web safe.
return HexEncoder.Encode(hash);
Expand Down

0 comments on commit a32e159

Please sign in to comment.