hej, Chciałbym zapisać hash hasła w telefonie, ale nie jestem pewien, jak to zrobić. Mogę tylko znaleźć metody szyfrowania. Jaki jest najlepszy sposób na zaszyfrowanie hasła? dziękiJak hash hasło
Odpowiedz
UPDATE: ta odpowiedź jest poważnie OUTDATED. Zamiast tego użyj zaleceń z https://stackoverflow.com/a/10402129/251311.
Można użyć
var md5 = new MD5CryptoServiceProvider();
var md5data = md5.ComputeHash(data);
lub
var sha1 = new SHA1CryptoServiceProvider();
var sha1data = sha1.ComputeHash(data);
Aby uzyskać data
jako tablicy bajtów można użyć
var data = Encoding.ASCII.GetBytes(password);
i wrócić ciąg od md5data
lub sha1data
var hashedPassword = ASCIIEncoding.GetString(md5data);
używam hash i sól dla mojego szyfrowania hasła (jest to ten sam hash który wykorzystuje 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);
}
-1 za używanie zwykłego SHA-1, który jest szybki. Użyj funkcji pochodnej wolnego klucza, takiej jak PBKDF2, bcrypt lub scrypt. – CodesInChaos
Większość innych odpowiedzi tutaj są nieco out-of-date dzięki dzisiejszym najlepszym praktykom. W związku z tym jest tutaj zastosowanie używania PBKDF2/Rfc2898DeriveBytes do przechowywania i weryfikacji haseł. Poniższy kod znajduje się w samodzielnej klasie w tym wpisie: Another example of how to store a salted password hash. Podstawy są naprawdę łatwe, więc tutaj to jest w podziale:
KROK 1 Tworzenie wartości soli z kryptograficznego PRNG:
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
KROK 2 utworzyć Rfc2898DeriveBytes i uzyskać wartość hash:
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
KROK 3 Połączyć sól i hasło bajtów do późniejszego wykorzystania:
byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
ETAP 4 Obracając połączeniu soli + mieszania w ciągu przechowywania
string savedPasswordHash = Convert.ToBase64String(hashBytes);
DBContext.AddUser(new User { ..., Password = savedPasswordHash });
ETAP 5 Sprawdź, czy hasło wprowadzone przez użytkownika na przechowywane hasło
/* 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();
Uwaga : W zależności od wymagań wydajnościowych danej aplikacji można zmniejszyć wartość "10000". Minimalna wartość powinna wynosić około 1000.
Dziękujemy za aktualizację i szczegółowe komentarze do kodu, duża pomoc! –
To jest bardziej jak pytanie, nie jest łatwiejsze, sprawdzanie hasła, haszowanie podanego hasła i porównywanie zapisanego ciągu z tym podanym przez użytkownika i mieszane ponownie? – Daniel
@ Daniel zasadniczo chodzi o użycie czegoś bardziej bezpiecznego niż sam skrót. Jeśli po prostu hash hash, nawet z solą, hasła użytkowników zostaną naruszone (i prawdopodobnie sprzedane/opublikowane), zanim będziesz miał szansę powiedzieć im, aby to zmienić. Użyj powyższego kodu, aby utrudnić atakującemu, nie jest to łatwe dla programisty. –
podstawie csharptest.net's wielką odpowiedź, napisałem klasę na to:
public sealed 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>
/// Check 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>
/// verify 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 hashbytes
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;
}
}
Zastosowanie:
//Hash
var hash = SecurePasswordHasher.Hash("mypassword");
//Verify
var result = SecurePasswordHasher.Verify("mypassword", hash);
Próbkę hash może być to:
$MYHASH$V1$10000$Qhxzi6GNu/Lpy3iUqkeqR/J1hh8y/h5KPDjrv89KzfCVrubn
jak ty widzę, dodałem również iteracje w haszcie dla łatwego użycia i możliwość uaktualnienia tego, jeśli musimy uaktualnić.
Tylko w celu sprawdzenia, czy zmodernizujesz silnik mieszający, który zwiększysz sekcję V1 twojego skrótu i od tego? –
Tak, to jest plan. Wówczas zdecydowałbyś się na podstawie "V1" i "V2", której potrzebujesz. –
Dzięki za odpowiedź i klasę. Wdrażam to, gdy mówimy. –
NAPRAWDĘ zalecałbym używanie SHA1. MD5 jest nie-nie, chyba że zachowujesz zgodność wsteczną z istniejącym systemem. Ponadto upewnij się, że umieściłeś go w instrukcji 'using' lub wywołałeś na nim' Clear() ', gdy skończysz używać implementacji. – vcsjones
@vcsjones: Nie chcę tu świętej wojny, ale 'md5' jest wystarczająco dobre dla prawie wszystkich zadań. Jego luki w zabezpieczeniach odnoszą się również do bardzo specyficznych sytuacji i niemal wymaga od atakującego, aby wiedział dużo o kryptografii. – zerkms
@zerkms punkt wzięty, ale jeśli nie ma powodu dla kompatybilności wstecznej, nie ma powodu używać MD5. "Lepiej dmuchać na zimne". – vcsjones