4

Okiだから、.Netにランダムなソルトを追加してパスワードをハッシュしたいと思います。この目的で使用している組み込みクラスは、ランダムソルトを生成するためのRNGCryptoServiceProviderと、実際のパスワードをハッシュするためのRfc2898DeriveBytesです。

しかし、passwordString、SaltBytes、およびIteration countの同じ組み合わせに対してRfc2898DeriveBytesのGetBytes()関数を呼び出すと、結果が異なります。参照用にコードを貼り付けています

    public class PBKDF2Implementation
    {
        int minSaltSize = 32;
        int maxSaltSize = 64;


        public string CreateHash(string plainText , out string  salt)
        {
            Random random = new Random();
            int saltSize = random.Next(minSaltSize, maxSaltSize);

            // Allocate a byte array, which will hold the salt.
            byte[] saltBytes = new byte[saltSize];

            // Initialize a random number generator.
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            // Fill the salt with cryptographically strong byte values.
            rng.GetNonZeroBytes(saltBytes);

            string strSalt = System.Text.Encoding.ASCII.GetString(saltBytes);
            //string strSalt = System.Convert.ToBase64String(saltBytes);
            salt = strSalt;

            Console.WriteLine(saltBytes.Count());
            Console.WriteLine(strSalt);

            Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes(plainText, saltBytes, 1000);

            // generate an RC2 key
            byte[] key = pwdGen.GetBytes(32);

            Console.WriteLine(System.Convert.ToBase64String(key));
            return System.Convert.ToBase64String(key);
        }

        public bool CompareHash(string plainText, string salt, string hashValue)
        {

            byte[] saltBytes = System.Text.Encoding.ASCII.GetBytes(salt);
            //byte[] saltBytes = System.Convert.FromBase64String(salt);

            Console.WriteLine(saltBytes.Count());
            Console.WriteLine(System.Text.Encoding.ASCII.GetString(saltBytes));

            Rfc2898DeriveBytes pwdGen = new Rfc2898DeriveBytes(plainText, saltBytes, 1000);

            // generate an RC2 key
            byte[] key = pwdGen.GetBytes(32);

            Console.WriteLine(System.Convert.ToBase64String(key));
            return System.Convert.ToBase64String(key) == hashValue;
        }
    }

そして私のテストクラスでは、私はこの関数を持っています

    [Test]
    public void shouldGenerateConsistentHash()
    {
        PBKDF2Implementation cPbkdf2Implementation = new PBKDF2Implementation();
        string salt;
        string hashValue = cPbkdf2Implementation.CreateHash("password", out salt);

        bool result = cPbkdf2Implementation.CompareHash("password", salt, hashValue);
        Assert.IsTrue(result) ;
    }

テストは失敗します。
ただし、上記のクラスの場合、PBKDF2Implementationの行をSystem.Text.Encoding.ASCII.GetStringからSystem.Text.Encoding.Unicode.GetStringに、System.Text.Encoding.ASCII.GetBytesをSystem.Text.Encoding.Unicodeに置き換えます。 GetBytes

テストに合格します。なぜこれが起こっているのか考えていますか?ASCIIエンコーディングで動作させたい理由は、このハッシュ値が格納されているのと同じDBがPHPアプリケーションでも使用され、PHPのPBKDF2実装によって生成されたハッシュ値がRfc2898DeriveBytesのハッシュ値と一致するのはソルトエンコーディングがASCII。

これは、同じhttp://www.php.net/manual/en/function.hash-hmac.php#101540のPHP実装です 。

4

1 に答える 1

6
  1. 暗号で文字列を使用しないでください。バイト配列を使用します。byte[]
  2. 文字列を使用する必要がある場合は、エンコーディングに細心の注意を払ってください。彼らはあなたを10回中9回噛むでしょう。

例えば

byte [] data = new byte [] { 65, 0, 65 };
var s = System.Text.Encoding.ASCII.GetString (data);

価値とはs

答え:「あ」

同じ文字列からを求めると、次のようになりbyte[]ます。byte [1] { 65 }これは元のものと同じではなく、ほとんどの暗号化の使用法では機能しません。

Base64 は、すべてのバイトがそのまま保持されるため、より安全です。

于 2012-04-04T15:46:35.257 に答える