1

I'm actually trying to implement a very simple login mecanism for an app I'm developping in Visual C# .NET 2.0 on an embedded device. After some researches, I've found on the msdn a code sample performing password hashing :

How to store passwords

Unfortunately, when I try to use it, that code sample is raising a FormatException on the call to byte.Parse on the substrings of the hexadecimal string SaltValue. I really have trouble to understand why, since I haven't done any change to the code.

Here is the code :

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
//...
}
}

I only have changed one line :

string saltValueString = utf16.GetString(saltValue);

to

string saltValueString = utf16.GetString(saltValue, 0, SaltValueSize);

because the first version of the method doesn't seem to be available for embedded C#. But anyway I've tested without changing this line (on a non-embedded environment), and it still was raising a FormatException.

I've copied the SaltValueSize value from that other msdn code sample (which is related) : How to validate passwords

The test that raises the exception :

HashPassword("youpi", null, new SHA1CryptoServiceProvider());

Elouan Keryell-Even
  • 990
  • 1
  • 14
  • 36
  • If the exception is thrown on `Byte.Parse` then the problem has nothing to do with any code executed after it. Remove everything unnecessary. And just plain try `binarySaltValue[0] = byte.Parse("A9", System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat);` to see whether issue has something to do with embedded .Net `Byte.Parse` method. – Eugene Podskal Jul 28 '14 at 18:29
  • I've tried your line of code, and it doesn't raise any exception, so I assume the problem comes from the format of the string returned by `GenerateSaltValue()`. And I'm going to remove everything that is unnecessary – Elouan Keryell-Even Jul 28 '14 at 18:33

1 Answers1

2

The problem lies in the fact that your GenerateSaltValue method does not return string of hexademical numbers.

It returns string of some random symbols, that may or usually may not be valid hexademical symbols - for me it created string of mostly Chinese hieroglyphs that for sure aren't parseable by Byte.Parse method.

Also, your example pertains to Microsoft Commerce Server - I have no idea whatsoever it is.

"SOLUTION:"

I am not sure what all this examples wants to accomplish with this string-tohex-tobinary conversions, but for it to successfully execute the GenerateSaltValue should be something like:

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;
}

And your program will "work", thanks to How do you convert Byte Array to Hexadecimal String, and vice versa?

BUT:

  • Using Random for Salt creation is a bad idea.
  • string-tohex-tobinary conversion looks even worser.
  • And other problems...

SO:

Read some articles that really pertains to C# password hashing and encryption, like:

Hash and salt passwords in C#

And be very attentive while searching for code examples - they could use another version, platform or even language. Good luck.

Community
  • 1
  • 1
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
  • Thanks man! Everything is working now. My question was really bad cause I haven't even tried to fully understand the code, I was really assuming that it was correct since I took it from the MSDN. My question is more of a "debug my code" one, which is not what the StackOverflow community wants I think. – Elouan Keryell-Even Jul 29 '14 at 14:19
  • Well, I made even greater blunders, so don't fret over it. – Eugene Podskal Jul 29 '14 at 14:22
  • Anyway, could you explain a little bit why it solves my problem? I see that your new version of `GenerateSaltValue()` still starts by generating random bytes. How does it happen that their are formatted correctly when calling `hex.AppendFormat` on them? I mean if the bytes are not in a good hexadecimal format, I wonder how you can get a correct hexadecimal string from them. Or may be any couple of bytes correspond to a valid hexadecimal caracter? – Elouan Keryell-Even Jul 29 '14 at 14:23
  • Compare output strings from original code and proposed code. `Byte.Parse` can parse "A9", but it can't parse "漢字" or "-P". And do not use this code for password hashing, read http://stackoverflow.com/questions/2138429/hash-and-salt-passwords-in-c-sharp – Eugene Podskal Jul 29 '14 at 14:26
  • Well I don't think my app is going to be used, I think it's just a demo app. Plus I need a working version soon. But if I have some time later, I'll try to change the way passwords are stored. And if I don't have time, I'll write it down on my report, so that if the app is really used later, the next person working on it will change it. Anyway, thanks for the help man :) – Elouan Keryell-Even Jul 31 '14 at 16:38