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


141

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ジェネレーターなど)と比較して、大幅に異なる結果をもたらします。

誰がエラーが何であるか知っていますか?別の拠点?


17
トピック外ですが、StringBuilderを作成し、foreachループでString.Formatの代わりにAppendFormatを使用すると、コードが不必要に多くの文字列オブジェクトを作成するのを防ぐことができることに注意してください。
Marcel Lamothe 2014年

回答:


154

Encoding.UnicodeMicrosoftの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テキストの場合、Encoding.UTF8間違いなく適しています。あなたが目指している場合は完璧であっても非ASCII入力に、あなたの友人のコードとの互換性、あなた方のような非ASCII文字を含むいくつかのテストケースを試してみたéし、あなたの結果がまだ一致するかどうかを参照してください。そうでない場合は、友達が実際に使用しているエンコーディングを把握する必要があります。これは、Unicodeが発明される前に一般的に使用されていた8ビットの「コードページ」の1つかもしれません。(繰り返しになりますが、「コードページ」についてまだ誰もが心配する必要がある主な理由はWindowsだと思います。)


3
@Elmueさん、「UTF8でエンコードされたバイトによるソート」と「Unicodeコードポイントによるソート」は同等であることを知って喜んでいるでしょう。(としては、「UTF16でエンコードされたことにより、ソートされたshortS」、しかしないあなたがWindowsのではないビッグエンディアンのシステム、にしている場合を除き「UTF16でエンコードされたバイトでソート」。)しかし、Unicodeで「仕分け」されて、本当に別の日に保存しておくべき複雑なトピック。
Quuxplusone 2014年

2
@エルメはあなたの間違った答えにそれほど自信を持っていません。やってみよう; あなたは驚かれることでしょう。驚きが楽しいか不快かは完全にあなた次第です。:)
Quuxplusone 2014年

2
@Elmue、「大文字と小文字を区別しない比較を行う場合はどうなりますか?このようなことをしたい場合は、バイトをUTF-16に変換する必要もあります。固定長であるという事実は1ビットには役立ちません。
Arturo TorresSánchez2014

2
Javaは内部的に...また、UTF-16などの文字列を扱うことから、非常に興味深い主張がある「誰が使用していない」
サミKuhmonenを

4
@Elmue「あなたのコメントは正しくありません:UTF16はUnicodeです。」あなたは間違っている。「Unicode」は、グリフに番号(コードポイント)を割り当てる規格です。サロゲートペアを除き、これらの数値をバイトとして表す方法は記載されていません。UTF16は、コードポイント<->バイトを指定します。Unicodeは、グリフ<->コードポイントを指定します。
antiduh 2015

103

また、別のスタイルの実装でもこの問題がありましたが、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に再度感謝します。:)


あなたの解決策は私のために働いた。しかし、私は別のケースがあります。それはsha512であり、私の問題を解決したコード行はhash += bit.ToString("x2");私がここで質問です:私はConvert.ToBase64String(byte[] encryptedBytes)バイトから文字列に変換するために使用していました。それは私に異なる結果を与えていました。バイトから文字列に変換するこれらの2つの方法の違いは何ですか?
Keval Langalia 2015年

ここでいくつかのカスタマイズを使用することは可能ですか(私の独自の初期化ベクトルのように)、またはランダムな文字列のみのオプションを追加/追加しますか?
FrenkyB

どういう意味かよくわかりません。これは非常に単純なハッシュ関数であり、いつでも好きなように追加/カスタマイズできます。ランダムな文字列を追加/追加するということは、ソルトするということですか?これは、セキュリティを強化するためにカスタマイズする良い方法の1つです。
Nico Dumdum 16

パスワードを格納するための作業要素なしでSHAハッシュのみを使用することは推奨されません。言い換えると、ハッカーがすばやく推測できないように、パスワードのハッシュプロセスを大幅に遅くする必要があります。セキュリティを強化するには、BcryptまたはScryptを使用します。
Ton Snoei 2017年

@TonSnoeiはい、そうです。ただし、これは大学時代の古い内部システムアプリケーションの古いコードであり、誰も使用していないため、私自身はこれをお勧めしません。さらに、このスレッドは特にSHA256エンコーディングに関するものであり、直接パスワードに関するものではありません。でも、それがあなたの空想をくすぐるなら、パスワードへの参照を削除するためにそれを編集することを気にしません。
Nico Dumdum 2017年

6
public static string ComputeSHA256Hash(string text)
{
    using (var sha256 = new SHA256Managed())
    {
        return BitConverter.ToString(sha256.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "");
    }                
}

異なる結果が得られる理由は、同じ文字列エンコーディングを使用しないためです。SHA256を計算するオンラインWebサイトに配置したリンクはUTF8エンコーディングを使用していますが、この例ではUnicodeエンコーディングを使用しています。これらは2つの異なるエンコーディングであるため、同じ結果は得られません。上記の例では、リンクされたWebサイトと同じSHA256ハッシュを取得します。PHPでも同じエンコーディングを使用する必要があります。

すべてのソフトウェア開発者の絶対最小値絶対に、確実にUnicodeと文字セットについて知っておく必要があります(言い訳はありません!)

https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/


4

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
代わりに使用ASCIIしていないでしょうbyte[] arrBytes = System.Text.Encoding.UTF8.GetBytes(strData)
c00000fd 2015

3
public string EncryptPassword(string password, string saltorusername)
        {
            using (var sha256 = SHA256.Create())
            {
                var saltedPassword = string.Format("{0}{1}", salt, password);
                byte[] saltedPasswordAsBytes = Encoding.UTF8.GetBytes(saltedPassword);
                return Convert.ToBase64String(sha256.ComputeHash(saltedPasswordAsBytes));
            }
        }

1
あなたが塩を加えたという事実が好きです^^
Fabian

1

これまでで最短かつ最速の方法。1行だけ!

public static string StringSha256Hash(string text) =>
    string.IsNullOrEmpty(text) ? string.Empty : BitConverter.ToString(new System.Security.Cryptography.SHA256Managed().ComputeHash(System.Text.Encoding.UTF8.GetBytes(text))).Replace("-", string.Empty);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.