byte.Parse(c#):十六进制字符串上的FormatException

byte.Parse(c#):十六进制字符串上的FormatException,c#,string,hex,byte,formatexception,C#,String,Hex,Byte,Formatexception,实际上,我正在尝试为我正在嵌入式设备上用Visual C#.NET 2.0开发的应用程序实现一个非常简单的登录机制。经过一些研究,我在msdn上发现了一个执行密码哈希的代码示例: 不幸的是,当我尝试使用它时,该代码示例在对十六进制字符串的子字符串SaltValue调用byte.Parse时引发FormatException。我真的很难理解为什么,因为我没有对代码做任何更改 代码如下: using System; using System.Collections.Generic; using S

实际上,我正在尝试为我正在嵌入式设备上用Visual C#.NET 2.0开发的应用程序实现一个非常简单的登录机制。经过一些研究,我在msdn上发现了一个执行密码哈希的代码示例:

不幸的是,当我尝试使用它时,该代码示例在对十六进制字符串的子字符串
SaltValue
调用
byte.Parse
时引发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
值:

引发异常的测试:


HashPassword(“youpi”,null,新的SHA1CryptoServiceProvider())

问题在于
GenerateSaltValue
方法不返回十六进制数字字符串

它返回一些随机符号的字符串,这些符号可能是或通常不是有效的十六进制符号——对我来说,它创建了一个由大多数中国象形文字组成的字符串,这肯定是无法通过方法解析的

此外,你的例子涉及-我不知道它是什么

“解决方案:”

我不确定所有这些示例都希望通过这个字符串到十六进制到二进制的转换实现什么,但要成功执行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;
}
感谢您的支持,您的程序将“起作用”

但是:

  • 使用Random创建盐是个坏主意
  • 字符串到十六进制到二进制的转换看起来更糟糕
  • 还有其他问题
所以:

阅读一些真正与C#密码哈希和加密相关的文章,如:


在搜索代码示例时要非常注意——他们可以使用其他版本、平台甚至语言。祝你好运。

如果异常是在
Byte.Parse上抛出的,那么问题与在它之后执行的任何代码无关。除去一切不必要的东西。只需简单地尝试一下
binarySaltValue[0]=byte.Parse(“A9”,System.Globalization.NumberStyles.HexNumber,CultureInfo.InvariantCulture.NumberFormat)
查看问题是否与嵌入的.Net
Byte.Parse
方法有关。我已经尝试了您的代码行,并且它没有引发任何异常,因此我假设问题来自
GenerateSaltValue()
返回的字符串格式。我要把所有不必要的东西都拿走谢谢老兄!现在一切正常。我的问题真的很糟糕,因为我甚至没有尝试完全理解代码,我真的假设它是正确的,因为我从MSDN中获取了它。我的问题更多的是“调试我的代码”,这不是StackOverflow社区想要的。好吧,我犯了更大的错误,所以不要为此烦恼。无论如何,你能解释一下为什么它能解决我的问题吗?我发现新版本的
GenerateSaltValue()
仍然是从生成随机字节开始的。当对它们调用
hex.AppendFormat
时,它们的格式是如何正确的?我的意思是,如果字节的十六进制格式不好,我想知道如何从中获得正确的十六进制字符串。或者可能是任意两个字节对应一个有效的十六进制字符?比较原始代码和建议代码的输出字符串
Byte.Parse
可以解析“A9”,但不能解析“A9”漢字" 或“-P“。不要将此代码用于密码哈希,请仔细阅读。我不认为我的应用程序会被使用,我认为它只是一个演示应用程序。另外,我需要一个工作版本很快。但是如果我以后有时间,我会尝试更改密码的存储方式。如果我没有时间,我会把它写在我的报告上,这样如果以后真的使用这个应用程序,下一个使用它的人就会修改它。不管怎样,谢谢你的帮助:)