[英]Hash Password in C#? Bcrypt/PBKDF2
我查询了msdn和其他资源如何做到这一点,但我想出了没有明确的解决方案。 这是我找到的最好的http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx?Redirected=true
我想使用bcrypt或PBKDF2(看起来与bcrypt相关)在C#中散列密码。 我想试验一下我的计算机散列密码需要多少轮。 然而,一切似乎都是关于加密,而每个人都谈论哈希。 我无法弄清楚。 我如何哈希密码? 它看起来更像PBKDF2(Rfc2898?)是一个随机数生成器,我使用GetBytes(金额)来选择我的散列大小有多大。
我糊涂了。 我究竟如何用bcrypt / PBKDF哈希密码?
你真的很亲密。 您给出的链接向您展示了如何调用Rfc2898DeriveBytes函数来获取PBKDF2哈希结果。 但是,由于示例使用派生密钥进行加密(PBKDF1和2的原始动机是创建适合用作加密密钥的“密钥”派生函数),因此您被抛弃了。 当然,我们不希望将输出用于加密,而是将其作为哈希本身。
如果你想要PBKDF2,你可以尝试为此目的编写的SimpleCrypto.Net库。 如果你看看实现 ,你可以看到它实际上只是一个薄的包装(你猜对了) Rfc2898DeriveBytes 。
如果你想试验这个变种,可以试试名为(还有什么) BCrypt.NET的C#实现。
免责声明:我没有使用或测试过我链接过的任何库... YMMV
我花了很长时间 (需要几天的时间)才能找到实际编码的代码来获取散列密码! 所以我把它放在这里是为了方便。
你需要阅读文档和理论1 理论2 ,然后一些或你可能对安全漏洞开放。 安全是一个非常大的话题! 买家要小心!
将NuGet包BCrypt.Net添加到解决方案中
const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor);
您应该将WorkFactor调整为适当的参见讨论 。 它是一个log2函数
“这个数字是log2,因此每次计算机速度加倍时,请将默认数字加1。”
然后将散列密码作为passwordFromLocalDB
存储在数据库中,并测试传入password
如下所示:
if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)
祝好运!
今年早些时候,我正在研究为ASP.NET Web Forms项目创建哈希的相同事情,我想以与MVC项目开箱即用的方式相同的方式进行。
我偶然发现了这个问题=> ASP.NET Identity默认密码Hasher,它是如何工作的并且它是否安全? 然后我在这里找到了带有ByteArraysEqual方法的源=> http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-rtm-140327/Release/Default/ Microsoft.AspNet.Identity.Core / Microsoft.AspNet.Identity.Core / Crypto.cs?ImageName = Microsoft.AspNet.Identity.Core
首先,我敦促大家使用平台本身附带的加密验证参考算法 。
请勿使用第三方软件包和未经验证的OSS组件或您刚刚从Internet复制粘贴的任何其他代码。
对于.NET, 使用PBKDF2而不是bCrypt,因为没有经过认证的bCrypt for .NET实现
我并不是说对任何高尚的开源开发者(我自己)都不尊重,但你永远不能确定他们的网站在10年内不会被黑客入侵你最终会从Nuget / npm或其他人那里获得恶意软件包包管理员。
有关验证的更多信息,请参阅此SO答案
现在,回到PBKDF2,这是简单的代码
public static byte[] PBKDF2Hash(string input, byte[] salt)
{
// Generate the hash
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(input, salt, iterations: 5000);
return pbkdf2.GetBytes(20); //20 bytes length is 160 bits
}
如果你需要哈希的字符串表示(不是字节数组) - 你可以从这个答案中使用这个超高速转换类http://stackoverflow.com/a/624379/714733
对于PBKDF2,您可以使用System.Security.Cryptography.Rfc2898DeriveBytes。
请参阅MSDN: http : //msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx
PBKDF2使用HMACSHA1,如果你想要一个更现代和可定制的解决方案,你应该使用HMACSHA256或512关键拉伸来看看这个API,就像PBKDF2一样
https://sourceforge.net/projects/pwdtknet/
源代码中包含的示例GUI演示了如何从密码中获取哈希,包括创建加密随机盐.....享受:)
对于使用.Net Core的任何人,Microsoft都有一个使用PBKDF2的示例代码页面:
来自文章:
using System;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
public class Program
{
public static void Main(string[] args)
{
Console.Write("Enter a password: ");
string password = Console.ReadLine();
// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");
// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA1,
iterationCount: 10000,
numBytesRequested: 256 / 8));
Console.WriteLine($"Hashed: {hashed}");
}
}
/*
* SAMPLE OUTPUT
*
* Enter a password: Xtw9NMgx
* Salt: NZsP6NnmfBuYeJrrAKNuVQ==
* Hashed: /OOoOer10+tGwTRDTrQSoeCxVTFr6dtYly7d0cPxIak=
*/
PBKDF2
在http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx中的示例中,当您到达“Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1,salt1,myIterations)”行时; “,k1是哈希。 该示例用于加密的原因是Rfc2898DeriveBytes最初设计用于创建加密密钥。
如果你不提供盐,Rfc2898DeriveBytes将创建它自己的,但我不知道RNGCryptoServiceProvider是否能更好地加密随机。
根据OWASP( https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2 ),Rfc2898DeriveBytes对SHA1的基础使用意味着它仅适用于长度最多为160位的散列。 如果你创建一个更长的哈希,攻击者仍然只需要担心前160位,但你已经使密码哈希/身份验证对你自己更加昂贵而没有任何收益。
以下是Rfc2898DeriveBytes密码散列的一些示例代码(在数据库中存储散列,salt和迭代):
public class Rfc2898PasswordEncoder
{
private int _byteLength = 160 / 8; // 160 bit hash length
public class EncodedPassword
{
public byte[] Hash { get; set; }
public byte[] Salt { get; set; }
public int Iterations { get; set; }
}
public EncodedPassword EncodePassword(string password, int iterations)
{
var populatedPassword = new EncodedPassword
{
Salt = CreateSalt(),
Iterations = iterations
};
// Add Hash
populatedPassword.Hash = CreateHash(password, populatedPassword.Salt, iterations);
return populatedPassword;
}
public bool ValidatePassword(string password, EncodedPassword encodedPassword)
{
// Create Hash
var testHash = CreateHash(password, encodedPassword.Salt, encodedPassword.Iterations);
return testHash == encodedPassword.Hash;
}
public byte[] CreateSalt()
{
var salt = new byte[_byteLength]; // Salt should be same length as hash
using (var saltGenerator = new RNGCryptoServiceProvider())
{
saltGenerator.GetBytes(salt);
}
return salt;
}
private byte[] CreateHash(string password, byte[] salt, long iterations)
{
byte[] hash;
using (var hashGenerator = new Rfc2898DeriveBytes(password, salt, (int)iterations))
{
hash = hashGenerator.GetBytes(_byteLength);
}
return hash;
}
}
我对不涉及任何图书馆的答案感兴趣。
我读了这篇文章https://crackstation.net/hashing-security.htm ,它链接了不同语言C#的实现,我将在这里链接
https://github.com/defuse/password-hashing/blob/master/PasswordStorage.cs
有趣的是,它使用的Rfc2898DeriveBytes在这里提到过几次。
private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes){
using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt)) {
pbkdf2.IterationCount = iterations;
return pbkdf2.GetBytes(outputBytes);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.