@@ -19,6 +19,16 @@ public static class HMACUtilities
1919 /// </summary>
2020 public const string TokenCommand = "hmac" ;
2121
22+ /// <summary>
23+ /// HMAC hash algorithms and their respective hash sizes in bytes.
24+ /// </summary>
25+ private enum HashAlgorithmSizes
26+ {
27+ HMACSHA256 = 32 ,
28+ HMACSHA384 = 48 ,
29+ HMACSHA512 = 64
30+ }
31+
2232 /// <summary>
2333 /// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA256 hash function.
2434 /// </summary>
@@ -30,8 +40,7 @@ public static class HMACUtilities
3040 /// <returns>The hashed <see cref="string"/>.</returns>
3141 public static unsafe string ComputeHMACSHA256 ( string value , byte [ ] secret )
3242 {
33- using HMACSHA256 hmac = new ( secret ) ;
34- return CreateHMAC ( value , hmac ) ;
43+ return CreateHMAC ( value , secret , HashAlgorithmSizes . HMACSHA256 ) ;
3544 }
3645
3746 /// <summary>
@@ -45,8 +54,7 @@ public static unsafe string ComputeHMACSHA256(string value, byte[] secret)
4554 /// <returns>The hashed <see cref="string"/>.</returns>
4655 public static unsafe string ComputeHMACSHA384 ( string value , byte [ ] secret )
4756 {
48- using HMACSHA384 hmac = new ( secret ) ;
49- return CreateHMAC ( value , hmac ) ;
57+ return CreateHMAC ( value , secret , HashAlgorithmSizes . HMACSHA384 ) ;
5058 }
5159
5260 /// <summary>
@@ -60,12 +68,11 @@ public static unsafe string ComputeHMACSHA384(string value, byte[] secret)
6068 /// <returns>The hashed <see cref="string"/>.</returns>
6169 public static unsafe string ComputeHMACSHA512 ( string value , byte [ ] secret )
6270 {
63- using HMACSHA512 hmac = new ( secret ) ;
64- return CreateHMAC ( value , hmac ) ;
71+ return CreateHMAC ( value , secret , HashAlgorithmSizes . HMACSHA512 ) ;
6572 }
6673
6774 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
68- private static unsafe string CreateHMAC ( string value , HMAC hmac )
75+ private static unsafe string CreateHMAC ( string value , ReadOnlySpan < byte > secret , HashAlgorithmSizes hashSize )
6976 {
7077 int byteCount = Encoding . ASCII . GetByteCount ( value ) ;
7178 byte [ ] ? buffer = null ;
@@ -80,8 +87,20 @@ private static unsafe string CreateHMAC(string value, HMAC hmac)
8087 Encoding . ASCII . GetBytes ( value , bytes ) ;
8188
8289 // Safe to always stackalloc here. We max out at 64 bytes.
83- Span < byte > hash = stackalloc byte [ hmac . HashSize / 8 ] ;
84- hmac . TryComputeHash ( bytes , hash , out int _ ) ;
90+ Span < byte > hash = stackalloc byte [ ( int ) hashSize ] ;
91+ switch ( hashSize )
92+ {
93+ default :
94+ case HashAlgorithmSizes . HMACSHA256 :
95+ HMACSHA256 . TryHashData ( secret , bytes , hash , out _ ) ;
96+ break ;
97+ case HashAlgorithmSizes . HMACSHA384 :
98+ HMACSHA384 . TryHashData ( secret , bytes , hash , out _ ) ;
99+ break ;
100+ case HashAlgorithmSizes . HMACSHA512 :
101+ HMACSHA512 . TryHashData ( secret , bytes , hash , out _ ) ;
102+ break ;
103+ }
85104
86105 // Finally encode the hash to make it web safe.
87106 return HexEncoder . Encode ( hash ) ;
0 commit comments