[[422468]]この記事はWeChatの公開アカウント「amazingdotnet」から転載したもので、著者はWeihanLiです。この記事を転載する場合は、amazingdotnet の公開アカウントにご連絡ください。 はじめにMicrosoft は、HMAC ハッシュ アルゴリズム (MD5/SHA1/SHA256/SHA384/SHA512) を使用するために、.NET 6 でいくつかのよりシンプルな API を導入しました。 Microsoft はこれを HMAC ワンショット方式と呼んでいます。HMAC アルゴリズムは、通常のハッシュ アルゴリズムにキーを追加することでセキュリティを向上させ、パスワードの漏洩やレインボー テーブルによる実際のパスワードの推測を効果的に防ぐことができます。RSA に加えて、JWT (Json Web Token) も HMAC の使用をサポートしています。 新しいAPI新しく追加された API 定義は次のとおりです。 - 名前空間 System.Security.Cryptography {
- 公共 部分クラス HMACMD5 {
- 公共 静的byte[] HashData(byte[]キー、byte[] ソース);
- 公共 静的byte[] HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース);
- 公共 静的 int HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先);
- 公共 static bool TryHashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先、出力 int書き込まれたバイト数);
- }
-
- 公共 部分クラス HMACSHA1 {
- 公共 静的byte[] HashData(byte[]キー、byte[] ソース);
- 公共 静的byte[] HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース);
- 公共 静的 int HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先);
- 公共 static bool TryHashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先、出力 int書き込まれたバイト数);
- }
-
- 公共 部分クラス HMACSHA256 {
- 公共 静的byte[] HashData(byte[]キー、byte[] ソース);
- 公共 静的byte[] HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース);
- 公共 静的 int HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先);
- 公共 static bool TryHashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先、出力 int書き込まれたバイト数);
- }
-
- 公共 部分クラス HMACSHA384 {
- 公共 静的byte[] HashData(byte[]キー、byte[] ソース);
- 公共 静的byte[] HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース);
- 公共 静的 int HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先);
- 公共 static bool TryHashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先、出力 int書き込まれたバイト数);
- }
-
- 公共 部分クラス HMACSHA512 {
- 公共 静的byte[] HashData(byte[]キー、byte[] ソース);
- 公共 静的byte[] HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース);
- 公共 静的 int HashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先);
- 公共 static bool TryHashData(ReadOnlySpan<byte>キー、ReadOnlySpan<byte> ソース、Span<byte> 宛先、出力 int書き込まれたバイト数);
- }
- }
サンプル前以前のバージョンでは、HMAC アルゴリズムの計算はより複雑でした。以前は、よく使用されるハッシュ アルゴリズムと HMAC アルゴリズムをカプセル化するために HashHelper が実装されていました。コードの HashHelper 部分は次のとおりで、完全なコードは Github から入手できます: https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Helpers/HashHelper.cs - /// <要約>
- /// ハッシュ後の文字列を取得する
- /// </要約>
- /// <param name = "type" >ハッシュ型</param>
- /// <param name = "source" >ソース</param>
- /// <param name = "key" >キー</param>
- /// <param name = "isLower" >小文字ですか?</param>
- /// <戻り値>ハッシュアルゴリズム処理後の文字列</戻り値>
- 公共 静的文字列 GetHashedString(HashType type、byte[] source、byte[]? key 、bool isLower = false )
- {
- Guard.NotNull(ソース、ソース名));
- (source.Length == 0)の場合
- {
- 文字列を返します。空です。
- }
- var hashedBytes = GetHashedBytes(型、ソース、キー);
- var sbText = 新しい StringBuilder();
- if (isLower)
- {
- foreach (ハッシュバイト内の変数 b )
- {
- sbText.Append(b.ToString( "x2" ));
- }
- }
- それ以外
- {
- foreach (ハッシュバイト内の変数 b )
- {
- sbText.Append(b.ToString( "X2" ));
- }
- }
- sbText.ToString()を返します。
- }
-
- /// <要約>
- /// 文字列ハッシュ値を計算する
- /// </要約>
- /// <param name = "type" >ハッシュ型</param>
- /// <param name = "str" >ハッシュする文字列</param>
- /// <戻り値>ハッシュされたバイト配列</戻り値>
- 公共 静的byte[] GetHashedBytes(HashType type, string str) => GetHashedBytes(type, str, Encoding.UTF8);
-
- /// <要約>
- /// 文字列ハッシュ値を計算する
- /// </要約>
- /// <param name = "type" >ハッシュ型</param>
- /// <param name = "str" >ハッシュする文字列</param>
- /// <param name = "encoding" >エンコーディングタイプ</param>
- /// <戻り値>ハッシュされたバイト配列</戻り値>
- 公共 静的byte[] GetHashedBytes(HashType type, string str, Encoding エンコーディング)
- {
- Guard.NotNull(str、nameof(str));
- if (str == string.Empty)
- {
- Array.Empty<byte>()を返します。
- }
- var bytes = encoding.GetBytes(str);
- GetHashedBytes(type, bytes) を返します。
- }
-
- /// <要約>
- /// ハッシュ後のバイト配列を取得する
- /// </要約>
- /// <param name = "type" >ハッシュ型</param>
- /// <param name = "bytes" >元のバイト配列</param>
- /// <戻り値></戻り値>
- 公共 静的byte[] GetHashedBytes(HashType type, byte[] bytes) => GetHashedBytes(type, bytes, null );
-
- /// <要約>
- /// ハッシュ後のバイト配列を取得する
- /// </要約>
- /// <param name = "type" >ハッシュ型</param>
- /// <param name = "key" >キー</param>
- /// <param name = "bytes" >元のバイト配列</param>
- /// <戻り値></戻り値>
- 公共 静的byte[] GetHashedBytes(HashType type, byte[] bytes, byte[]? key )
- {
- Guard.NotNull(バイト、バイト名));
- (バイト長 == 0)の場合
- {
- バイトを返します。
- }
-
- HashAlgorithm アルゴリズム = null !;
- 試す
- {
- if (キー== null )
- {
- アルゴリズム = タイプスイッチ
- {
- HashType.SHA1 => 新しい SHA1Managed()、
- HashType.SHA256 => 新しい SHA256Managed()、
- HashType.SHA384 => 新しい SHA384Managed()、
- HashType.SHA512 => 新しい SHA512Managed()、
- _ => MD5.Create ()
- };
- }
- それ以外
- {
- アルゴリズム = タイプスイッチ
- {
- HashType.SHA1 => 新しい HMACSHA1(キー)、
- HashType.SHA256 => 新しい HMACSHA256(キー)、
- HashType.SHA384 => 新しい HMACSHA384(キー)、
- HashType.SHA512 => 新しい HMACSHA512(キー)、
- _ => 新しい HMACMD5(キー)
- };
- }
- algorithm.ComputeHash(bytes)を返します。
- }
- ついに
- {
- アルゴリズム.Dispose();
- }
- }
以下に使用例をいくつか示します。 - HashHelper.GetHashedBytes(HashType.MD5、 "テスト" );
- HashHelper.GetHashedBytes(HashType.MD5、 "テスト" .GetBytes());
- HashHelper.GetHashedBytes(HashType.MD5、 "テスト" 、 "テストキー" );
- HashHelper.GetHashedBytes(HashType.MD5、 "test" .GetBytes()、 "testKey" .GetBytes());
-
- HashHelper.GetHashedString(HashType.MD5、 "テスト" );
- HashHelper.GetHashedString(HashType.SHA1、 "テスト" .GetBytes());
- HashHelper.GetHashedString(HashType.SHA256、 "テスト" 、 "テストキー" );
- HashHelper.GetHashedString(HashType.MD5、 "test" .GetBytes()、 "testKey" .GetBytes());
新しい API サンプル新しい API でどのように簡素化できるでしょうか? 次の例を見てみましょう。 - var bytes = "テスト" .GetBytes();
- var keyBytes = "テストキー" .GetBytes();
-
- // HMACMD5
- var hmd5V1 = HMACMD5.HashData(keyBytes, バイト);
- var hmd5V2 = HashHelper.GetHashedBytes(HashType.MD5、バイト、キーバイト);
- Console.WriteLine(hmd5V2.SequenceEqual(hmd5V1));
-
- // HMACSHA1
- var hsha1V1 = HMACSHA1.HashData(keyBytes, バイト);
- var hsha1V2 = HashHelper.GetHashedBytes(HashType.SHA1、バイト、キーバイト);
- コンソールに行を書き込む。
-
- // HMACSHA256
- var hsha256V1 = HMACSHA256.HashData(keyBytes, バイト);
- var hsha256V2 = HashHelper.GetHashedBytes(HashType.SHA256、バイト、キーバイト);
- コンソールに行を書き込む。
-
- // HMACSHA384
- var hsha384V1 = HMACSHA384.HashData(keyBytes, バイト);
- var hsha384V2 = HashHelper.GetHashedBytes(HashType.SHA384、バイト、キーバイト);
- コンソールに行を書き込む。
-
- // HMACSHA512
- var hsha512V1 = HMACSHA512.HashData(keyBytes, バイト);
- var hsha512V2 = HashHelper.GetHashedBytes(HashType.SHA512、バイト、キーバイト);
- コンソールに行を書き込む。
対応する HMAC ハッシュ アルゴリズムの HashData メソッドを使用し、対応するキーと元のコンテンツを渡すだけです。上記は、結果が一貫しているかどうかを確認するために、HashHelper カプセル化メソッドと比較したものです。一貫しています。出力結果は次のとおりです。 もっと一般的なハッシュ アルゴリズムについては、Microsoft は実際にすでに .NET 5 で上記の使用方法をサポートしています。次のコードを試すことができます。 - var bytes = "テスト" .GetBytes();
-
- //MD5
- var md5V1 = MD5.HashData(バイト);
- var md5V2 = HashHelper.GetHashedBytes(HashType.MD5、バイト);
- Console.WriteLine(md5V2.SequenceEqual(md5V1));
-
- // SHA1
- var sha1V1 = SHA1.HashData(バイト);
- var sha1V2 = HashHelper.GetHashedBytes(HashType.SHA1, バイト);
- Console.WriteLine(sha1V2.SequenceEqual(sha1V1));
-
- // SHA256
- var sha256V1 = SHA256.HashData(バイト);
- var sha256V2 = HashHelper.GetHashedBytes(HashType.SHA256、バイト);
- Console.WriteLine(sha256V2.SequenceEqual(sha256V1));
-
- // SHA384
- var sha384V1 = SHA384.HashData(バイト);
- var sha384V2 = HashHelper.GetHashedBytes(HashType.SHA384, バイト);
- Console.WriteLine(sha384V2.SequenceEqual(sha384V1));
-
- // SHA512
- var sha512V1 = SHA512.HashData(バイト);
- var sha512V2 = HashHelper.GetHashedBytes(HashType.SHA512, バイト);
- Console.WriteLine(sha512V2.SequenceEqual(sha512V1));
多くの場合、MD5 または SHA1 の後の文字列を使用する必要があります。Microsoft が文字列を直接取得する方法を提供しないのはなぜかわかりません。そのような方法があれば、より便利です。後者と比較すると、自己カプセル化された HashHelper を使用する方が快適です。ハハ、このような静的メソッドは抽象性が足りません。ハッシュ アルゴリズム コードを動的に置き換えたい場合は、少し... 参考文献 - https://github.com/dotnet/runtime/pull/53487
- https://github.com/dotnet/runtime/issues/40012
- https://github.com/dotnet/core/issues/6569#issuecomment-913876347
- https://baike.baidu.com/item/hmac/7307543?fr=アラジン
- https://github.com/WeihanLi/SamplesInPractice/blob/master/net6sample/HashSample/Program.cs
- https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Helpers/HashHelper.cs
|