web-dev-qa-db-ja.com

Sha256で文字列をハッシュする

私はSHA256を使って文字列をハッシュしようとしています、私は次のコードを使っています:

using System;
using System.Security.Cryptography;
using System.Text;
 public class Hash
    {
    public static string getHashSha256(string text)
    {
        byte[] bytes = Encoding.Unicode.GetBytes(text);
        SHA256Managed hashstring = new SHA256Managed();
        byte[] hash = hashstring.ComputeHash(bytes);
        string hashString = string.Empty;
        foreach (byte x in hash)
        {
            hashString += String.Format("{0:x2}", x);
        }
        return hashString;
    }
}

しかし、このコードは私の友人のphpやオンラインのジェネレータ( This generator のような)とはかなり違う結果をもたらします。

誰がエラーが何であるかを知っていますか?別の基地ですか?

129
Nattfrosten

Encoding.Unicodeは、MicrosoftのUTF-16に対する誤解を招くような名前です(歴史的な理由からWindowsの世界で使用されていますが、他の誰にも使用されていない倍幅エンコード)。 http://msdn.Microsoft.com/en-us/library/system.text.encoding.unicode.aspx

bytes配列を調べると、2倍のバイトが0x00であることがわかります(倍幅エンコードのため)。

代わりにEncoding.UTF8.GetBytesを使用してください。

しかし、最後の'\0'バイトをハッシュしているデータの一部と見なすかどうかによって、結果が異なります。 2バイト"Hi"をハッシュすると、3バイトのバイト"Hi"をハッシュした場合とは結果が異なります。あなたはどちらをしたいのか決める必要があります。 (たぶんあなたはあなたの友人のPHPコードがしているものをやってみたいのです。)

ASCII textには、Encoding.UTF8が間違いなく適しています。もしあなたがあなたの友達のコードとの完璧な互換性を目指しているなら、たとえ非ASCII入力でさえも、あなたはもっと多くのテストケースを試したほうがいいです。 éなどのASCII文字を使用して、結果がまだ一致するかどうかを確認します。そうでなければ、あなたはあなたの友人が実際にどんなエンコーディングを使っているのかを考え出す必要があるでしょう。これは、Unicodeが発明される前に普及していた8ビットの「コードページ」の1つです。 (繰り返しになりますが、誰もが「コードページ」を心配する必要がある主な理由は、Windowsだと思います。)

145
Quuxplusone

私はまた別のスタイルの実装でこの問題を抱えていました、しかし私はそれが2年前だったので私がどこでそれを手に入れたか忘れていました。

static string sha256(string randomString)
{
    var crypt = new SHA256Managed();
    string hash = String.Empty;
    byte[] crypto = crypt.ComputeHash(Encoding.ASCII.GetBytes(randomString));
    foreach (byte theByte in crypto)
    {
        hash += theByte.ToString("x2");
    }
    return hash;
}

何らかの理由でabcdefghi2013のようなものを入力すると、結果が異なり、ログインモジュールでエラーが発生します。それから私はQuuxplusoneによって提案されたのと同じ方法でコードを修正しようとし、そしてASCIIからUTF8にエンコーディングを変更し、そしてそれはついにうまくいきました!

static string sha256(string randomString)
{
    var crypt = new System.Security.Cryptography.SHA256Managed();
    var hash = new System.Text.StringBuilder();
    byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomString));
    foreach (byte theByte in crypto)
    {
        hash.Append(theByte.ToString("x2"));
    }
    return hash.ToString();
}

Quuxplusoneに素晴らしい詳細な回答をいただきありがとうございます。

92
Nico Dumdum

PHPバージョンでは、最後のパラメータに 'true'を送信できますが、デフォルトは 'false'です。次のアルゴリズムは、最初のパラメータとして 'sha256'を渡すときのデフォルトのPHPのハッシュ関数と同じです。

public static string GetSha256FromString(string strData)
    {
        var message = Encoding.ASCII.GetBytes(strData);
        SHA256Managed hashString = new SHA256Managed();
        string hex = "";

        var hashValue = hashString.ComputeHash(message);
        foreach (byte x in hashValue)
        {
            hex += String.Format("{0:x2}", x);
        }
        return hex;
    }
4
Rachel