C# Tips | 文字列処理:SHA256生成

C# C#
スポンサーリンク

はじめに 「SHA256生成」は“文字列に指紋をつける”行為

SHA256 は、どんな長さのデータでも「256ビット(32バイト)の固定長のハッシュ値」に変換する仕組みです。
イメージとしては、

「中身は見せないけど、“同じものかどうか”だけは確実に判定できる指紋を作る」

という感じです。

業務では、例えば次のような用途で使われます。

ログIDやトラッキングIDを、元の値を隠したまま追跡したい
ファイルや文字列が改ざんされていないかチェックしたい
キャッシュキーや重複チェック用のキーを固定長にしたい

ここでは、「文字列からSHA256を生成するC#ユーティリティ」を、
初心者向けに、仕組みからコードまでかみ砕いて説明していきます。


SHA256生成の基本の流れを言葉でつかむ

3ステップで考える

文字列からSHA256を作る流れは、たった3ステップです。

1つ目は、「文字列をバイト配列に変換する」。
2つ目は、「そのバイト配列に対してSHA256を計算する」。
3つ目は、「結果のバイト配列を、人間が扱いやすい形(16進文字列など)に変換する」。

C#では、この3つをそれぞれ、

Encoding.UTF8.GetBytes(...)
SHA256.Create().ComputeHash(...)
バイト配列 → 16進文字列への変換

として実装していきます。


C#での基本実装:文字列 → SHA256(16進文字列)

まずは完成形のユーティリティを見てみる

いきなりですが、「業務でそのまま使えるレベル」のユーティリティを書いてみます。

using System;
using System.Security.Cryptography;
using System.Text;

public static class Sha256Util
{
    public static string ComputeSha256Hex(string? text)
    {
        if (string.IsNullOrEmpty(text))
        {
            return string.Empty;
        }

        byte[] bytes = Encoding.UTF8.GetBytes(text);

        using var sha = SHA256.Create();
        byte[] hashBytes = sha.ComputeHash(bytes);

        return ToHex(hashBytes);
    }

    private static string ToHex(byte[] bytes)
    {
        var sb = new StringBuilder(bytes.Length * 2);

        foreach (byte b in bytes)
        {
            sb.Append(b.ToString("x2"));
        }

        return sb.ToString();
    }
}
C#

これを一行ずつ、ちゃんと意味が分かるように分解していきます。


各ステップを丁寧に分解する

文字列をバイト配列に変換する

byte[] bytes = Encoding.UTF8.GetBytes(text);
C#

SHA256は「バイト列」に対して計算されます。
なので、まずは文字列をバイト配列に変換する必要があります。

ここで重要なのが「エンコーディングを固定する」ことです。
同じ "こんにちは" でも、UTF-8 と UTF-16 ではバイト列が変わり、ハッシュ値も変わります。

業務で「他システムと比較する」「ファイルに保存する」といった用途を考えると、
エンコーディングは UTF-8 に固定しておくのが安全です。

Encoding.UTF8.GetBytes(text); をユーティリティの中に埋め込んでしまうことで、
呼び出し側はエンコーディングを意識しなくて済むようになります。

SHA256を計算する

using var sha = SHA256.Create();
byte[] hashBytes = sha.ComputeHash(bytes);
C#

SHA256.Create() は、SHA256アルゴリズムのインスタンスを作る工場メソッドです。
using var を付けているのは、IDisposable なオブジェクトなので、
使い終わったら自動的に破棄してもらうためです。

ComputeHash(bytes) に、先ほどのバイト配列を渡すと、
長さ32バイト(256ビット)のハッシュ値が返ってきます。

この時点では「ただのバイト配列」なので、
そのままだとログに出したり、文字列として扱うのが不便です。

バイト配列を16進文字列に変換する

private static string ToHex(byte[] bytes)
{
    var sb = new StringBuilder(bytes.Length * 2);

    foreach (byte b in bytes)
    {
        sb.Append(b.ToString("x2"));
    }

    return sb.ToString();
}
C#

ここでは、1バイトを2桁の16進数(00ff)に変換しています。
例えば、バイト値 15"0f"255"ff" になります。

bytes.Length * 2StringBuilder の初期容量を決めているのは、
「32バイト → 64文字」になることが分かっているからです。
こうしておくと、余計な再確保が減って、少しだけ効率が良くなります。

結果として、ComputeSha256Hex("Hello") のように呼ぶと、
64文字の16進文字列が返ってくる、というわけです。


実際に動かしてみるイメージ

いくつかの文字列で試してみる

Console.WriteLine(Sha256Util.ComputeSha256Hex("Hello"));
Console.WriteLine(Sha256Util.ComputeSha256Hex("hello"));
Console.WriteLine(Sha256Util.ComputeSha256Hex("こんにちは"));
Console.WriteLine(Sha256Util.ComputeSha256Hex(""));
Console.WriteLine(Sha256Util.ComputeSha256Hex(null));
C#

ポイントは次の通りです。

"Hello""hello" は、1文字違うだけですが、ハッシュ値はまったく違う
日本語("こんにちは")も問題なくハッシュ化できる(UTF-8でバイト列にしているため)
空文字や null は、ユーティリティ側で「空文字を返す」という方針にしている

この「nullや空文字をどう扱うか」は設計の好みですが、
業務ユーティリティとしては「例外を投げず、空文字を返す」ほうが呼び出し側が楽なことが多いです。


バイト配列のまま扱いたい場合のバリエーション

16進文字列ではなく、バイト配列で返す版

用途によっては、「16進文字列にせず、バイト配列のまま扱いたい」こともあります。
その場合は、こういうメソッドも用意できます。

public static byte[] ComputeSha256Bytes(string? text)
{
    if (string.IsNullOrEmpty(text))
    {
        return Array.Empty<byte>();
    }

    byte[] bytes = Encoding.UTF8.GetBytes(text);

    using var sha = SHA256.Create();
    return sha.ComputeHash(bytes);
}
C#

これを使えば、

ハッシュ値をそのままバイナリとしてファイルに書きたい
別の暗号処理や署名処理に渡したい

といった場面に対応できます。


SHA256ユーティリティを業務でどう使うか

「中身は見せたくないが、同じものかどうかは知りたい」場面

例えば、こんな使い方が考えられます。

ログにユーザーIDをそのまま残したくないので、SHA256にして保存する
外部から受け取ったファイルの内容をハッシュ化しておき、後で「同じファイルかどうか」を判定する
キャッシュのキーとして、「元のキー文字列のSHA256」を使う(キーを固定長にしたいとき)

どの場合も、「元の文字列は復元できないが、同じ入力なら同じハッシュになる」という性質を利用しています。

注意:パスワードには“そのままSHA256”を使わない

とても重要な注意点として、
ユーザーパスワードを扱うときに、

var hash = Sha256Util.ComputeSha256Hex(password);
C#

のように「そのままSHA256にかける」のは、セキュリティ的には不十分です。

パスワードには、ソルト・ストレッチング・専用アルゴリズム(PBKDF2, bcrypt, Argon2 など)が必要になります。
ここは「SHA256ユーティリティ」の範囲を超えるので深掘りしませんが、

「SHA256は“パスワード以外”の文字列に使う」

と覚えておいてください。


まとめ 「SHA256生成ユーティリティ」は“文字列に安全な指紋をつけるための定番ツール”

ここまでのポイントを整理すると、こうなります。

SHA256は「どんな長さの文字列でも、256ビットの固定長ハッシュにする」仕組みである。
C#では、Encoding.UTF8.GetBytesSHA256.Create().ComputeHash → 16進文字列化、という3ステップで実装する。
エンコーディング(UTF-8)とアルゴリズム(SHA-256)をユーティリティ側で固定しておくと、結果が安定し、呼び出し側が迷わない。
nullや空文字の扱いも、ユーティリティ側でルール化しておくと業務コードがすっきりする。
パスワードには“そのままSHA256”を使わず、専用の仕組みを使う。

ここまで理解できれば、「なんとなくハッシュを取っている」状態から一歩進んで、
“用途と安全性を意識したSHA256生成ユーティリティ”を、自分のC#コードの中に自然に組み込めるようになっていきます。

タイトルとURLをコピーしました