C# 使用MD5或sha-256 C哈希密码#
我正在为一份申请写一份登记表,但作为c#的新手,我仍然有一些问题 我希望将密码加密/散列到md5或sha-256,最好是sha-256C# 使用MD5或sha-256 C哈希密码#,c#,hash,sha256,C#,Hash,Sha256,我正在为一份申请写一份登记表,但作为c#的新手,我仍然有一些问题 我希望将密码加密/散列到md5或sha-256,最好是sha-256 有好的例子吗?我希望它能够从“stringpassword;”获取信息,然后将其散列并存储在变量“stringhpassword;”中。有什么想法吗?您需要使用名称空间;具体地说,是或 从上面的代码中提取一些信息,并且知道两个类都有相同的基类(),您可以使用如下函数: public string ComputeHash(string input, HashAlg
有好的例子吗?我希望它能够从“stringpassword;”获取信息,然后将其散列并存储在变量“stringhpassword;”中。有什么想法吗?您需要使用名称空间;具体地说,是或 从上面的代码中提取一些信息,并且知道两个类都有相同的基类(),您可以使用如下函数:
public string ComputeHash(string input, HashAlgorithm algorithm)
{
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);
return BitConverter.ToString(hashedBytes);
}
然后您可以这样称呼它(对于MD5):
或者对于SHA256:
string hPassword = ComputeHash(password, new SHA256CryptoServiceProvider());
编辑:添加盐支持
正如dtb在评论中指出的那样,如果该代码包含添加的功能,那么它将更加强大。如果您不熟悉它,salt是一组随机位,作为哈希函数的输入包含在其中,这对于阻止针对哈希密码的字典攻击(例如,使用密码)有很大帮助。下面是支持salt的
ComputeHash
函数的修改版本:
public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt)
{
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
// Combine salt and input bytes
Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length];
salt.CopyTo(saltedInput, 0);
inputBytes.CopyTo(saltedInput, salt.Length);
Byte[] hashedBytes = algorithm.ComputeHash(saltedInput);
return BitConverter.ToString(hashedBytes);
}
希望这有帮助 System.Security.Cryptography.SHA256类应该完成以下任务:
如果要存储哈希密码,请使用SHA-256而不是。问题在于,SHA-256针对速度进行了优化,这使得在有人访问您的数据库时更容易对密码进行暴力攻击 阅读这篇文章:这是一个前一个问题 文章中的一些引语: 问题是MD5速度很快。它的现代竞争对手也是如此,比如SHA1和SH256。速度是现代安全散列的一个设计目标,因为散列是几乎所有密码系统的一个构建块,通常在每个数据包或每个消息的基础上执行请求 速度正是您在密码哈希函数中不想要的。
最后,我们了解到,如果我们想要安全地存储密码,我们有三个合理的选择:PHK的MD5方案、Provos Maziere的Bcrypt方案和SRP。我们知道正确的选择是Bcrypt
不要使用简单的杂烩,甚至盐杂烩。使用一些关键强化技术,如(使用a)或(使用a) 下面是一个使用PBKDF2的示例 要从密码生成密钥
string password = GetPasswordFromUserInput();
// specify that we want to randomly generate a 20-byte salt
using (var deriveBytes = new Rfc2898DeriveBytes(password, 20))
{
byte[] salt = deriveBytes.Salt;
byte[] key = deriveBytes.GetBytes(20); // derive a 20-byte key
// save salt and key to database
}
然后测试密码是否有效
string password = GetPasswordFromUserInput();
byte[] salt, key;
// load salt and key from database
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
byte[] newKey = deriveBytes.GetBytes(20); // derive a 20-byte key
if (!newKey.SequenceEqual(key))
throw new InvalidOperationException("Password is invalid!");
}
在将密码存储到数据库中时,在对其进行哈希运算之前,应始终对其进行加密。 建议的数据库列:
- 密码salt:int
- 密码哈希:二进制(20)
private int GenerateSaltForPassword()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] saltBytes = new byte[4];
rng.GetNonZeroBytes(saltBytes);
return (((int)saltBytes[0]) << 24) + (((int)saltBytes[1]) << 16) + (((int)saltBytes[2]) << 8) + ((int)saltBytes[3]);
}
检查密码只需计算哈希值,然后将其与预期的哈希值进行比较即可
private bool IsPasswordValid(string passwordToValidate, int salt, byte[] correctPasswordHash)
{
byte[] hashedPassword = ComputePasswordHash(passwordToValidate, salt);
return hashedPassword.SequenceEqual(correctPasswordHash);
}
PBKDF2正在使用HMACSHA1……。如果您想要更现代的HMACSHA256或HMACSHA512实现,并且仍然希望通过键拉伸来降低算法的速度,我建议您使用以下API:以下是持久性不敏感的SecuredPassword类的完整实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public class SecuredPassword
{
private const int saltSize = 256;
private readonly byte[] hash;
private readonly byte[] salt;
public byte[] Hash
{
get { return hash; }
}
public byte[] Salt
{
get { return salt; }
}
public SecuredPassword(string plainPassword)
{
if (string.IsNullOrWhiteSpace(plainPassword))
return;
using (var deriveBytes = new Rfc2898DeriveBytes(plainPassword, saltSize))
{
salt = deriveBytes.Salt;
hash = deriveBytes.GetBytes(saltSize);
}
}
public SecuredPassword(byte[] hash, byte[] salt)
{
this.hash = hash;
this.salt = salt;
}
public bool Verify(string password)
{
if (string.IsNullOrWhiteSpace(password))
return false;
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
byte[] newKey = deriveBytes.GetBytes(saltSize);
return newKey.SequenceEqual(hash);
}
}
}
和测试:
public class SecuredPasswordTests
{
[Test]
public void IsHashed_AsExpected()
{
var securedPassword = new SecuredPassword("password");
Assert.That(securedPassword.Hash, Is.Not.EqualTo("password"));
Assert.That(securedPassword.Hash.Length, Is.EqualTo(256));
}
[Test]
public void Generates_Unique_Salt()
{
var securedPassword = new SecuredPassword("password");
var securedPassword2 = new SecuredPassword("password");
Assert.That(securedPassword.Salt, Is.Not.Null);
Assert.That(securedPassword2.Salt, Is.Not.Null);
Assert.That(securedPassword.Salt, Is.Not.EqualTo(securedPassword2.Salt));
}
[Test]
public void Generates_Unique_Hash()
{
var securedPassword = new SecuredPassword("password");
var securedPassword2 = new SecuredPassword("password");
Assert.That(securedPassword.Hash, Is.Not.Null);
Assert.That(securedPassword2.Hash, Is.Not.Null);
Assert.That(securedPassword.Hash, Is.Not.EqualTo(securedPassword2.Hash));
}
[Test]
public void Verify_WhenMatching_ReturnsTrue()
{
var securedPassword = new SecuredPassword("password");
var result = securedPassword.Verify("password");
Assert.That(result, Is.True);
}
[Test]
public void Verify_WhenDifferent_ReturnsFalse()
{
var securedPassword = new SecuredPassword("password");
var result = securedPassword.Verify("Password");
Assert.That(result, Is.False);
}
[Test]
public void Verify_WhenRehydrated_AndMatching_ReturnsTrue()
{
var securedPassword = new SecuredPassword("password123");
var rehydrated = new SecuredPassword(securedPassword.Hash, securedPassword.Salt);
var result = rehydrated.Verify("password123");
Assert.That(result, Is.True);
}
[Test]
public void Constructor_Handles_Null_Password()
{
Assert.DoesNotThrow(() => new SecuredPassword(null));
}
[Test]
public void Constructor_Handles_Empty_Password()
{
Assert.DoesNotThrow(() => new SecuredPassword(string.Empty));
}
[Test]
public void Verify_Handles_Null_Password()
{
Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(null));
}
[Test]
public void Verify_Handles_Empty_Password()
{
Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(string.Empty));
}
[Test]
public void Verify_When_Null_Password_ReturnsFalse()
{
Assert.That(new SecuredPassword("password").Verify(null), Is.False);
}
}
请使用这个,因为我以前也有同样的问题,但可以通过litle代码片段解决它
public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt)
{
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
// Combine salt and input bytes
Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length];
salt.CopyTo(saltedInput, 0);
inputBytes.CopyTo(saltedInput, salt.Length);
Byte[] hashedBytes = algorithm.ComputeHash(saltedInput);
StringBuilder hex = new StringBuilder(hashedBytes.Length * 2);
foreach (byte b in hashedBytes)
hex.AppendFormat("{0:X2}", b);
return hex.ToString();
}
TL;DR使用,使用SHA-512实现PBKDF2
开始使用密码哈希的好主意是看看你说了什么。推荐的算法列表包括Argon2、PBKDF2、scrypt和bcrypt。所有这些算法都可以调整,以调整散列密码所需的时间,以及相应地,通过蛮力破解密码所需的时间。所有这些算法都利用salt来防止彩虹表攻击
这两种算法都不是很弱,但有一些区别:
- bcrypt已存在近20年,得到了广泛的应用和推广 经受了时间的考验。它对GPU有很强的抵抗力 攻击,但不针对FPGA
- Argon2是最新加入的,是2015年密码哈希竞赛的获胜者。它对GPU和FPGA攻击有更好的保护,但对我来说有点太新了
- 我对斯克里普了解不多。它被设计用来阻止GPU和FPGA加速的攻击,但我听说它并不像最初宣称的那样强大
- PBKDF2是一系列由不同哈希参数化的算法 功能。它不提供针对GPU或ASIC攻击的特定保护,特别是在使用SHA-1等较弱的哈希函数的情况下,但是,如果它对您很重要,它是经过FIPS认证的,并且如果迭代次数足够大,它仍然是可以接受的
- Bcrypt可通过以下途径获得:。他们说该实现基于JavaJBCrypt。目前github上有6个贡献者和8个问题(全部关闭)。总的来说,它看起来不错,但是,我不知道是否有人对代码进行了审核,如果发现漏洞,很难判断是否会很快提供更新版本
public class SecuredPasswordTests { [Test] public void IsHashed_AsExpected() { var securedPassword = new SecuredPassword("password"); Assert.That(securedPassword.Hash, Is.Not.EqualTo("password")); Assert.That(securedPassword.Hash.Length, Is.EqualTo(256)); } [Test] public void Generates_Unique_Salt() { var securedPassword = new SecuredPassword("password"); var securedPassword2 = new SecuredPassword("password"); Assert.That(securedPassword.Salt, Is.Not.Null); Assert.That(securedPassword2.Salt, Is.Not.Null); Assert.That(securedPassword.Salt, Is.Not.EqualTo(securedPassword2.Salt)); } [Test] public void Generates_Unique_Hash() { var securedPassword = new SecuredPassword("password"); var securedPassword2 = new SecuredPassword("password"); Assert.That(securedPassword.Hash, Is.Not.Null); Assert.That(securedPassword2.Hash, Is.Not.Null); Assert.That(securedPassword.Hash, Is.Not.EqualTo(securedPassword2.Hash)); } [Test] public void Verify_WhenMatching_ReturnsTrue() { var securedPassword = new SecuredPassword("password"); var result = securedPassword.Verify("password"); Assert.That(result, Is.True); } [Test] public void Verify_WhenDifferent_ReturnsFalse() { var securedPassword = new SecuredPassword("password"); var result = securedPassword.Verify("Password"); Assert.That(result, Is.False); } [Test] public void Verify_WhenRehydrated_AndMatching_ReturnsTrue() { var securedPassword = new SecuredPassword("password123"); var rehydrated = new SecuredPassword(securedPassword.Hash, securedPassword.Salt); var result = rehydrated.Verify("password123"); Assert.That(result, Is.True); } [Test] public void Constructor_Handles_Null_Password() { Assert.DoesNotThrow(() => new SecuredPassword(null)); } [Test] public void Constructor_Handles_Empty_Password() { Assert.DoesNotThrow(() => new SecuredPassword(string.Empty)); } [Test] public void Verify_Handles_Null_Password() { Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(null)); } [Test] public void Verify_Handles_Empty_Password() { Assert.DoesNotThrow(() => new SecuredPassword("password").Verify(string.Empty)); } [Test] public void Verify_When_Null_Password_ReturnsFalse() { Assert.That(new SecuredPassword("password").Verify(null), Is.False); } }
public static string ComputeHash(string input, HashAlgorithm algorithm, Byte[] salt) { Byte[] inputBytes = Encoding.UTF8.GetBytes(input); // Combine salt and input bytes Byte[] saltedInput = new Byte[salt.Length + inputBytes.Length]; salt.CopyTo(saltedInput, 0); inputBytes.CopyTo(saltedInput, salt.Length); Byte[] hashedBytes = algorithm.ComputeHash(saltedInput); StringBuilder hex = new StringBuilder(hashedBytes.Length * 2); foreach (byte b in hashedBytes) hex.AppendFormat("{0:X2}", b); return hex.ToString(); }