web-dev-qa-db-ja.com

パスワードをハッシュする方法

ちょっと、電話にパスワードのハッシュを保存したいのですが、どうすればいいのかわかりません。暗号化方法しか見つけられないようです。パスワードをハッシュする最良の方法は何ですか?ありがとう

106
Skoder

UPDATEこの回答IS真剣に時代遅れ。代わりに https://stackoverflow.com/a/10402129/251311 の推奨事項を使用してください。

どちらかを使用できます

var md5 = new MD5CryptoServiceProvider();
var md5data = md5.ComputeHash(data);

または

var sha1 = new SHA1CryptoServiceProvider();
var sha1data = sha1.ComputeHash(data);

dataをバイト配列として取得するには、使用できます

var data = Encoding.ASCII.GetBytes(password);

md5dataまたはsha1dataから文字列を取得するには

var hashedPassword = ASCIIEncoding.GetString(md5data);
54
zerkms

ここでのその他の回答のほとんどは、今日のベストプラクティスとは多少古くなっています。このように、PBKDF2/Rfc2898DeriveBytesを使用してパスワードを保存および検証するアプリケーションです。次のコードは、この投稿のスタンドアロンクラスにあります。 ソルトパスワードハッシュの保存方法の別の例 。基本は本当に簡単なので、ここでは分類します。

STEP 1暗号PRNGでソルト値を作成します。

byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);

STEP 2Rfc2898DeriveBytesを作成し、ハッシュ値を取得します。

var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);

ステップ3後で使用するために、ソルトとパスワードのバイトを結合します。

byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);

ステップ4組み合わせたソルト+ハッシュを保存用の文字列に変換します

string savedPasswordHash = Convert.ToBase64String(hashBytes);
DBContext.AddUser(new User { ..., Password = savedPasswordHash });

ステップ5ユーザーが入力したパスワードを保存されたパスワードと照合します

/* Fetch the stored value */
string savedPasswordHash = DBContext.GetUser(u => u.UserName == user).Password;
/* Extract the bytes */
byte[] hashBytes = Convert.FromBase64String(savedPasswordHash);
/* Get the salt */
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
/* Compute the hash on the password the user entered */
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
/* Compare the results */
for (int i=0; i < 20; i++)
    if (hashBytes[i+16] != hash[i])
        throw new UnauthorizedAccessException();

注:特定のアプリケーションのパフォーマンス要件に応じて、値「10000」を減らすことができます。最小値は約1000です。

259
csharptest.net

csharptest.net's 素晴らしい答えに基づいて、私はこのためのクラスを書きました:

public static class SecurePasswordHasher
{
    /// <summary>
    /// Size of salt.
    /// </summary>
    private const int SaltSize = 16;

    /// <summary>
    /// Size of hash.
    /// </summary>
    private const int HashSize = 20;

    /// <summary>
    /// Creates a hash from a password.
    /// </summary>
    /// <param name="password">The password.</param>
    /// <param name="iterations">Number of iterations.</param>
    /// <returns>The hash.</returns>
    public static string Hash(string password, int iterations)
    {
        // Create salt
        byte[] salt;
        new RNGCryptoServiceProvider().GetBytes(salt = new byte[SaltSize]);

        // Create hash
        var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations);
        var hash = pbkdf2.GetBytes(HashSize);

        // Combine salt and hash
        var hashBytes = new byte[SaltSize + HashSize];
        Array.Copy(salt, 0, hashBytes, 0, SaltSize);
        Array.Copy(hash, 0, hashBytes, SaltSize, HashSize);

        // Convert to base64
        var base64Hash = Convert.ToBase64String(hashBytes);

        // Format hash with extra information
        return string.Format("$MYHASH$V1${0}${1}", iterations, base64Hash);
    }

    /// <summary>
    /// Creates a hash from a password with 10000 iterations
    /// </summary>
    /// <param name="password">The password.</param>
    /// <returns>The hash.</returns>
    public static string Hash(string password)
    {
        return Hash(password, 10000);
    }

    /// <summary>
    /// Checks if hash is supported.
    /// </summary>
    /// <param name="hashString">The hash.</param>
    /// <returns>Is supported?</returns>
    public static bool IsHashSupported(string hashString)
    {
        return hashString.Contains("$MYHASH$V1$");
    }

    /// <summary>
    /// Verifies a password against a hash.
    /// </summary>
    /// <param name="password">The password.</param>
    /// <param name="hashedPassword">The hash.</param>
    /// <returns>Could be verified?</returns>
    public static bool Verify(string password, string hashedPassword)
    {
        // Check hash
        if (!IsHashSupported(hashedPassword))
        {
            throw new NotSupportedException("The hashtype is not supported");
        }

        // Extract iteration and Base64 string
        var splittedHashString = hashedPassword.Replace("$MYHASH$V1$", "").Split('$');
        var iterations = int.Parse(splittedHashString[0]);
        var base64Hash = splittedHashString[1];

        // Get hash bytes
        var hashBytes = Convert.FromBase64String(base64Hash);

        // Get salt
        var salt = new byte[SaltSize];
        Array.Copy(hashBytes, 0, salt, 0, SaltSize);

        // Create hash with given salt
        var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations);
        byte[] hash = pbkdf2.GetBytes(HashSize);

        // Get result
        for (var i = 0; i < HashSize; i++)
        {
            if (hashBytes[i + SaltSize] != hash[i])
            {
                return false;
            }
        }
        return true;
    }
}

使用法:

// Hash
var hash = SecurePasswordHasher.Hash("mypassword");

// Verify
var result = SecurePasswordHasher.Verify("mypassword", hash);

サンプルハッシュは次のようになります。

$MYHASH$V1$10000$Qhxzi6GNu/Lpy3iUqkeqR/J1hh8y/h5KPDjrv89KzfCVrubn

ご覧のように、簡単に使用できるようにハッシュに反復を含め、アップグレードが必要な場合はこれをアップグレードできるようにしました。


.netコアに興味がある場合は、 Code Review に.netコアバージョンもあります。

58

パスワードの暗号化にハッシュとソルトを使用します(Asp.Net Membershipが使用するものと同じハッシュです):

private string PasswordSalt
{
   get
   {
      var rng = new RNGCryptoServiceProvider();
      var buff = new byte[32];
      rng.GetBytes(buff);
      return Convert.ToBase64String(buff);
   }
}

private string EncodePassword(string password, string salt)
{
   byte[] bytes = Encoding.Unicode.GetBytes(password);
   byte[] src = Encoding.Unicode.GetBytes(salt);
   byte[] dst = new byte[src.Length + bytes.Length];
   Buffer.BlockCopy(src, 0, dst, 0, src.Length);
   Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
   HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
   byte[] inarray = algorithm.ComputeHash(dst);
   return Convert.ToBase64String(inarray);
}
13
Martin
  1. 塩を作り、
  2. Saltを使用してハッシュパスワードを作成する
  3. ハッシュとソルトの両方を保存します
  4. パスワードとソルトで復号化する...開発者はパスワードを復号化できない
public class CryptographyProcessor
{
    public string CreateSalt(int size)
    {
        //Generate a cryptographic random number.
          RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
         byte[] buff = new byte[size];
         rng.GetBytes(buff);
         return Convert.ToBase64String(buff);
    }


      public string GenerateHash(string input, string salt)
      { 
         byte[] bytes = Encoding.UTF8.GetBytes(input + salt);
         SHA256Managed sHA256ManagedString = new SHA256Managed();
         byte[] hash = sHA256ManagedString.ComputeHash(bytes);
         return Convert.ToBase64String(hash);
      }

      public bool AreEqual(string plainTextInput, string hashedInput, string salt)
      {
           string newHashedPin = GenerateHash(plainTextInput, salt);
           return newHashedPin.Equals(hashedInput); 
      }
 }
0
Bamidele Alegbe