プログラミングBlog

プログラミング学習用

ちょいちょい書いてます

ハッシュについて

ハッシュとは?

ハッシュとは、英語で細切れにするという意味。
ハッシュ関数から得られた値のことをハッシュ値という。
例えばこんな値みたことありませんか? ハッシュ関数から得られたハッシュ値の例です。

4DFF4EA340F0A823F15D3F4F01AB62EAE0E5DA579CCB851F8DB9DFE84C58B2B37B89903A740E1EE172DA793A6E79D560E5F7F9BD058A12A280433ED6FA46510A

どんな時に用いられるかというと、検索の高速化、データ比較処理の高速化、改竄の検出などしたい時に使われる。 ハッシュ値を比較して同じ値であれば、同一のデータと考えられますね。

なぜパスワード保護に用いられるのか?

ハッシュ関数とは非可逆変換であるため、ハッシュ値から元の値の値を容易に復元できないという特徴がある。
非可逆変換とは元のデータと変換後のデータが完全に一致しないこと。
つまり、パスワードに用いることで容易に元のデータを割り出されないようハッシュ関数が用いられる。
さらに元のデータが同じであれば同じハッシュ値が生成される特徴がある。

なぜハッシュ化が用いられるのかログイン機能で考える

まずパスワードをハッシュ化せずに、素の状態だと誰にでもわかるパスワードですし、流出したらどうしようもないです。
そこで考えられるのが元のデータをハッシュ化してハッシュ値をパスワードとして利用する方法。

1. ユーザーがパスワードを登録する。
2. 登録時にパスワードをハッシュ化してあげると元のデータはユーザーにしかわからない。
3. 仮にハッシュ化したパスワードが流出したとしても非可逆変換な(戻せない)ため、元のデータはわからない。

よく考えてみるとパスワードを忘れた場合に問い合わせを行うと、元のパスワードを教えるのではなく、再登録になりますよね?
パスワードをハッシュ化することで管理者側もわからないのでしょう。(たぶん
※間違えてたらすいません

ハッシュ化するうえで起こる衝突とは?

異なるデータから同じハッシュ値が生成されてしまうこと。
ハッシュ値が短いほど、衝突がおこりやすいため、できるだけ長いものを使用する。
衝突が多いほど元のデータを割り出される可能性も高まるため、衝突を避けたい。
何度もハッシュ化を重ねることでデータの秘匿性を高めることができる。

ハッシュ化してみよう!

ハッシュ化

    public class HashCode
    {
        public string HashConvert(string password) 
        {
            // 文字コードを指定して、文字列からバイナリへの変換を行う。
            byte[] bytes = Encoding.UTF8.GetBytes(password);

            // バイナリからハッシュへと変換を行う。
            var hash = SHA512.Create().ComputeHash(bytes) ;
       
            return ByteArrayToString(hash);
        }

        static string ByteArrayToString(byte[] arrInput) 
        {
            int i;
            StringBuilder sOutput = new StringBuilder(arrInput.Length);
            for (i = 0; i < arrInput.Length; i++) 
            {
                // ハッシュから16進数に変換する。
                sOutput.Append(arrInput[i].ToString("X2"));
            }
            return sOutput.ToString();
        }
    }

文字コード

文字コード 説明
ASCII アメリカ規格協会が定めた世界中で使用されている文字コード。ほぼすべてのPCで扱うことができる
Unicode 世界で使われるすべての文字を共通の文字集合とするために作られた。UTF-8UTF-16UTF-32などがある。
UTF-8 ASCIIと互換性があるため、ASCIIで定義されている文字をそのまま使用することを目的として作られた。

進数変換

記号 説明
D2 10進数2桁
X2 16進数2桁

覚えておきたい用語

  • バイナリ  2進数で表されるデータのこと
  • 1byte = 8bit  データ量、情報量の単位のこと
  • 2進数 0と1の2種類の数字の組み合わせによって表現する形式のこと

    実行

    class Program
    {
        static void Main(string[] args)
        {
            var password = new HashCode().HashConvert("1");

            Console.WriteLine(password);

            int byteCount = Encoding.GetEncoding("UTF-8").GetByteCount(password);

            Console.WriteLine(byteCount);
        }
    }

結果

// ハッシュコード
4DFF4EA340F0A823F15D3F4F01AB62EAE0E5DA579CCB851F8DB9DFE84C58B2B37B89903A740E1EE172DA793A6E79D560E5F7F9BD058A12A280433ED6FA46510A

// byte数
128

ログイン機能

秘匿性をさらに高めるためにハッシュ値に変換したものをさらに変換する。
その後に値を比較する。 値が一致すればログイン成功、一致しなければログイン失敗。

    class Program
    {
        static void Main(string[] args)
        {
            var password = new HashCode().HashConvert("1");

            var password2 = new HashCode().HashConvert(password);

            Console.WriteLine(password);

            if (password2 == "A0E65FEADC0BAE63AE088C3D8D648C3BBE145442E1D399618404042EE6785495DFA95844AB23CBE082A33467A96A50544DD42329CA55ADA7DF9E8CE7E0D1C740")
            {
                Console.WriteLine("ログイン成功");
            }
            else 
            {
                Console.WriteLine("ログイン失敗");
            }
        }
    }

結果

4DFF4EA340F0A823F15D3F4F01AB62EAE0E5DA579CCB851F8DB9DFE84C58B2B37B89903A740E1EE172DA793A6E79D560E5F7F9BD058A12A280433ED6FA46510A

ログイン成功

docs.microsoft.com

参考にしたサイト

ハッシュの種類やアルゴリズムについて参考にしました。
SHA512以外にもたくさん種類があります。
qiita.com
ハッシュ関数とハッシュアルゴリズム ~PKI基礎④~ | マイクロソフ党ブログmicrosoftou.com ウィキペディア - Wikipedia

脆弱性の記事

古いアルゴリズムだと既に解析が終了しており、脆弱性が高まるため、 まだ解析されていない最新のアルゴリズムを選択したほうが良い。
internet.watch.impress.co.jp 73spica.tech