Joh*_*uit 7 c# hash cryptography salt sha
我对密码学很陌生,但学习.我已经从我的在线研究中拼凑了许多不同的建议,并且已经创建了我自己的类来处理相关数据的哈希,盐,键拉伸和比较/转换.
在研究了用于加密的内置.NET库之后,我发现我所拥有的只是SHA-1.但是我得出结论,因为我正在使用散列过程的多次迭代,所以它并不坏.那是对的吗?
但如果我想从更强大的SHA-512开始,我怎么能在下面的代码中实现它?提前致谢.
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
public class CryptoSaltAndHash
{
private string strHash;
private string strSalt;
public const int SaltSizeInBytes = 128;
public const int HashSizeInBytes = 1024;
public const int Iterations = 3000;
public string Hash { get { return strHash; } }
public string Salt { get { return strSalt; } }
public CryptoSaltAndHash(SecureString ThisPassword)
{
byte[] bytesSalt = new byte[SaltSizeInBytes];
using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
crypto.GetBytes(bytesSalt);
}
strSalt = Convert.ToBase64String(bytesSalt);
strHash = ComputeHash(strSalt, ThisPassword);
}
public static string ComputeHash(string ThisSalt, SecureString ThisPassword)
{
byte[] bytesSalt = Convert.FromBase64String(ThisSalt);
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(
convertSecureStringToString(ThisPassword), bytesSalt, Iterations);
using (pbkdf2)
{
return Convert.ToBase64String(pbkdf2.GetBytes(HashSizeInBytes));
}
}
public static bool Verify(string ThisSalt, string ThisHash, SecureString ThisPassword)
{
if (slowEquals(getBytes(ThisHash), getBytes(ComputeHash(ThisSalt, ThisPassword))))
{
return true;
}
return false;
}
private static string convertSecureStringToString(SecureString MySecureString)
{
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.SecureStringToGlobalAllocUnicode(MySecureString);
return Marshal.PtrToStringUni(ptr);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(ptr);
}
}
private static bool slowEquals(byte[] A, byte[] B)
{
int intDiff = A.Length ^ B.Length;
for (int i = 0; i < A.Length && i < B.Length; i++)
{
intDiff |= A[i] ^ B[i];
}
return intDiff == 0;
}
private static byte[] getBytes(string MyString)
{
byte[] b = new byte[MyString.Length * sizeof(char)];
System.Buffer.BlockCopy(MyString.ToCharArray(), 0, b, 0, b.Length);
return b;
}
}
Run Code Online (Sandbox Code Playgroud)
注意:我从https://crackstation.net/hashing-security.htm引用了很多实践.slowEquals比较方法是通过阻止分支来规范化执行时间.SecureString的用法是在此类与我的Web应用程序中的其他类和页面之间传递加密形式的密码.虽然这个站点将通过HTTPS,但总是很好的做法,以确保尽可能安全,同时仍然在合理范围内.
在我的代码中,我将密钥字符串设置为128个字节(虽然它有时变大,这很好),散列大小为1KB,迭代次数为3,000.它比典型的64字节盐,512字节散列以及1,000或2,000次迭代略大,但是再次登录速度和应用程序性能是一个极低的优先级.
思考?
Cod*_*aos 10
散列大小大于本机大小(SHA-1为20个字节)会降低防御者的性能,但不会降低攻击者的性能.因为这意味着您可以承受更少的迭代,实际上会削弱安全性.
例如,与具有3000次迭代的1024字节散列相同的成本,您可以提供具有156000次迭代的20字节散列,这是破解的52倍.
要使用SHA-2,您需要一个完全不同的PBKDF2实现,.net中包含的实现是硬编码使用SHA-1.
如果您懒得使用第三方库,我宁愿使用bcrypt库,因为这对基于GPU的攻击者来说要强得多.
您的API难以使用,因为您将盐管理推送到调用者而不是在Create/ Verifyfunctions 中处理它.
使用SecureString然后将其转换为傻是愚蠢的String.这抵消了SecureString首先使用a的全部意义.
就个人而言,我不会SecureString在典型的应用程序中烦恼.如果将它与广泛的整体堆栈安全性审核结合起来,这是非常值得的,它会检查密码永远不会存储在一个String并且一旦不再需要就会从可变存储中删除.
我不会将密码/ salt存储在实例变量中.只需将它们保留在相关功能的本地.我只在实例变量中存储配置(例如迭代计数).
虽然SHA-1以加密方式被削弱,但攻击会产生冲突.对于密码哈希冲突是无关紧要的,您关心的是第一次预映像攻击.在这方面,SHA-1仍然非常强大.
SHA-512的主要优点并不在于它的密码更强(尽管它是),因为防御者可能会使用64位Intel CPU来提供快速的64位算术,因此64位算术比攻击者花费更多.
小智 6
回答这个问题:从" SecurityDriven.NET "一书中下载免费代码示例.找到需要HMAC工厂的PBKDF2类.HMACSHA512工厂可供选择.
由于您不熟悉密码学,我还强烈建议您阅读本书(例如,要完全理解CodesInChaos所做的观点).
如果有人通过搜索遇到此问题,则现在Microsoft提供了Microsoft.AspNetCore.Cryptography.KeyDerivation NuGet程序包,该程序包允许将PBKDF2与SHA-256和SHA-512哈希函数一起使用。可从docs.microsoft.com获得文档。