我实际上正在尝试为我在嵌入式设备上的Visual C#.NET 2.0中开发的应用程序实现一个非常简单的登录机制。经过一些研究,我在msdn上找到了一个执行密码哈希的代码示例:
不幸的是,当我尝试使用它时,该代码示例在十六进制字符串byte.Parse
的子字符串上调用SaltValue
时引发FormatException。我真的很难理解为什么,因为我没有对代码做任何改动。
以下是代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Globalization;
private const int SaltValueSize = 4;
private static string GenerateSaltValue()
{
UnicodeEncoding utf16 = new UnicodeEncoding();
if (utf16 != null)
{
// Create a random number object seeded from the value
// of the last random seed value. This is done
// interlocked because it is a static value and we want
// it to roll forward safely.
Random random = new Random(unchecked((int)DateTime.Now.Ticks));
if (random != null)
{
// Create an array of random values.
byte[] saltValue = new byte[SaltValueSize];
random.NextBytes(saltValue);
// Convert the salt value to a string. Note that the resulting string
// will still be an array of binary values and not a printable string.
// Also it does not convert each byte to a double byte.
//Original line :
//string saltValueString = utf16.GetString(saltValue);
//Replaced by :
string saltValueString = utf16.GetString(saltValue, 0, SaltValueSize);
// Return the salt value as a string.
return saltValueString;
}
}
return null;
}
private static string HashPassword(string clearData, string saltValue, HashAlgorithm hash)
{
UnicodeEncoding encoding = new UnicodeEncoding();
if (clearData != null && hash != null && encoding != null)
{
// If the salt string is null or the length is invalid then
// create a new valid salt value.
if (saltValue == null)
{
// Generate a salt string.
saltValue = GenerateSaltValue();
}
// Convert the salt string and the password string to a single
// array of bytes. Note that the password string is Unicode and
// therefore may or may not have a zero in every other byte.
byte[] binarySaltValue = new byte[SaltValueSize];
//FormatException raised here
binarySaltValue[0] = byte.Parse(saltValue.Substring(0, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
binarySaltValue[1] = byte.Parse(saltValue.Substring(2, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
binarySaltValue[2] = byte.Parse(saltValue.Substring(4, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
binarySaltValue[3] = byte.Parse(saltValue.Substring(6, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);
//...
//Some more code
//...
}
}
我只改变了一行:
string saltValueString = utf16.GetString(saltValue);
到
string saltValueString = utf16.GetString(saltValue, 0, SaltValueSize);
因为该方法的第一个版本似乎不适用于嵌入式C#。但无论如何,我已经测试过但没有改变这一行(在非嵌入式环境中),它仍然引发了一个FormatException。
我已经复制了其他msdn代码示例中的SaltValueSize
值(相关):
How to validate passwords
引发异常的测试:
HashPassword("youpi", null, new SHA1CryptoServiceProvider());
答案 0 :(得分:1)
问题在于你的GenerateSaltValue
方法没有返回十六进制数字的字符串。
它返回一些随机符号的字符串,这些符号可能或通常可能不是有效的十六进制符号 - 对我而言,它创建的字符串主要是中国象形文字,肯定不能通过Byte.Parse方法解析。
此外,您的示例属于Microsoft Commerce Server - 我不知道它是什么。
<强> “SOLUTION:”强>
我不确定所有这些示例都希望通过此字符串tohex-tobinary转换完成,但是要成功执行GenerateSaltValue应该是这样的:
public static string ByteArrayToString(byte[] byteArray)
{
StringBuilder hex = new StringBuilder(byteArray.Length * 2);
foreach (byte b in byteArray)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
// Renamed GenerateSaltValue method
private static string GenerateHexSaltString()
{
Random random = new Random();
// Create an array of random values.
byte[] saltValue = new byte[SaltValueSize];
random.NextBytes(saltValue);
string saltValueString = ByteArrayToString(saltValue);
// Return the salt value as a string.
return saltValueString;
}
感谢How do you convert Byte Array to Hexadecimal String, and vice versa?
,您的计划将“正常运作”<强> BUT:强>
<强> SO:强>
阅读一些真正与C#密码哈希和加密有关的文章,例如:
<强> Hash and salt passwords in C# 强>
在搜索代码示例时非常注意 - 他们可以使用其他版本,平台甚至语言。祝你好运。