C# 使用Rfc2898DeriveBytes和MSSQL在C中发出加密密码
我已经为我的应用程序建立了一个登录系统,但是,它的工作极不一致 有时密码会起作用,但有时它会说它不正确。我百分之百肯定我打对了 为了存储密码,我生成一个随机salt,将密码与salt散列,并将散列后的密码和salt与用户名一起存储在数据库中 为了验证用户,我根据给定的用户名选择哈希密码和salt。然后我用salt散列他们的密码尝试,看看它是否和他们原来的散列密码匹配,如果匹配,允许他们登录 我的代码如下:C# 使用Rfc2898DeriveBytes和MSSQL在C中发出加密密码,c#,sql-server,encryption,hash,rfc2898,C#,Sql Server,Encryption,Hash,Rfc2898,我已经为我的应用程序建立了一个登录系统,但是,它的工作极不一致 有时密码会起作用,但有时它会说它不正确。我百分之百肯定我打对了 为了存储密码,我生成一个随机salt,将密码与salt散列,并将散列后的密码和salt与用户名一起存储在数据库中 为了验证用户,我根据给定的用户名选择哈希密码和salt。然后我用salt散列他们的密码尝试,看看它是否和他们原来的散列密码匹配,如果匹配,允许他们登录 我的代码如下: private const int NumberOfRounds = 5000, Salt
private const int NumberOfRounds = 5000, SaltLength = 32;
public static byte[] GenerateSalt()
{
using (var rng = new RNGCryptoServiceProvider())
{
var randomNumber = new byte[SaltLength];
rng.GetBytes(randomNumber);
return randomNumber;
}
}
public static byte[] HashPassword(byte[] passwordToHash, byte[] salt)
{
using (var deriveBytes = new Rfc2898DeriveBytes(passwordToHash, salt, numberOfRounds))
{
return deriveBytes.GetBytes(32);
}
}
public static bool IsPasswordValid(string inputPassword, string hashedPassword, string salt)
{
byte[] potentialValidPassword = HashPassword(Encoding.Unicode.GetBytes(inputPassword),
Encoding.Unicode.GetBytes(salt));
string potentialAsString = Encoding.Unicode.GetString(potentialValidPassword);
return Encoding.Unicode.GetBytes(hashedPassword).SequenceEqual(potentialValidPassword) ||
hashedPassword.Equals(potentialAsString);
}
我的检查比较字节数组值和字符串值的原因是,有时字节值比较失败,但字符串值有效
我将用户插入数据库的代码如下
public SecurityReturnMessage AddUser(string username, string password)
{
byte[] salt = PasswordManagement.GenerateSalt();
byte[] hashedPassword = PasswordManagement.HashPassword(Encoding.Unicode.GetBytes(password), salt);
if (conn.State != ConnectionState.Open)
conn.Open();
int result;
using (IDbCommand comm = conn.CreateCommand())
{
comm.CommandText = "usp_IFRS_SEC_USER_INSERT";
comm.CommandType = CommandType.StoredProcedure;
SqlParameter hashPwd =new SqlParameter("@hashpwd", SqlDbType.NVarChar)
{
Value = Encoding.Unicode.GetString(hashedPassword)
};
SqlParameter saltParameter = new SqlParameter("@salt", SqlDbType.NVarChar)
{
Value = Encoding.Unicode.GetString(salt)
};
comm.Parameters.Add(Extensions.CreateParameter(comm, "@user", username));
comm.Parameters.Add(hashPwd);
comm.Parameters.Add(saltParameter);
var returnVal = comm.CreateParameter();
returnVal.Direction = ParameterDirection.ReturnValue;
comm.Parameters.Add(returnVal);
comm.ExecuteNonQuery();
result = (int)returnVal.Value;
}
if (conn.State != ConnectionState.Closed)
conn.Close();
return (SecurityReturnMessage)result;
}
如果有人能帮我解决这个问题,我将不胜感激。我建议您在将值从字节转换为字符串时使用Base64转换,如下所示,反之亦然
string base64 = Convert.ToBase64String(bytes);
byte[] bytes = Convert.FromBase64String(base64);
通过这种方式,您可以确保unicode数据在任何转换过程中都不会丢失或损坏,这可能是代码不一致的有效原因。我建议您在将值从字节转换为字符串时使用Base64转换,如下所示,反之亦然
string base64 = Convert.ToBase64String(bytes);
byte[] bytes = Convert.FromBase64String(base64);
通过这种方式,您可以确保unicode数据在任何一个转换过程中都不会丢失或损坏,这可能是代码不一致的一个有效原因。谢谢您的回复,但是我现在收到了格式异常。消息可能是输入不是有效的Base-64字符串,因为它包含非Base-64字符、两个以上的填充字符,或者填充字符中包含非法字符。或者Base-64字符数组或字符串的长度无效。是的,这是更好的方法,但它不会自动修复已存储的密码。@HenkHolterman当然,这仍在开发中,因此我截断了用户表并创建了新的用户表,但是我得到了上面描述的异常,那么您做得不对。寻找一些示例代码,还有很多其他的。谢谢你的回复,不过我现在遇到了格式异常。消息可能是输入不是有效的Base-64字符串,因为它包含非Base-64字符、两个以上的填充字符,或者填充字符中包含非法字符。或者Base-64字符数组或字符串的长度无效。是的,这是更好的方法,但它不会自动修复已存储的密码。@HenkHolterman当然,这仍在开发中,因此我截断了用户表并创建了新的用户表,但是我得到了上面描述的异常,那么您做得不对。寻找一些示例代码,还有很多,主要错误是Unicode.Get\uuuuuuuuuuuuu。为了防止这种情况,请不要编写自己的安全代码。ASP.NET提供了IdentityManager,可惜有很多变体和版本。@HenkHolterman当然,我只是假设这意味着我自己不会实现哈希算法,但我没有。你对IdentityManager有什么好的了解吗?主要错误是Unicode。获取。为了防止这种情况,请不要编写自己的安全代码。ASP.NET提供了IdentityManager,可惜有很多变体和版本。@HenkHolterman当然,我只是假设这意味着我自己不会实现哈希算法,但我没有。你对IdentityManager有什么好的了解吗?