Monday 17 January 2011

Split String To Dictionary

I have created a Survey System, which allows an admin to set the questions.

One question type is a dropdownlist and the information needed (to keep it simple) was stored as a semi-colon separated list (I also extended this to allow colon separated values within that to allow key and value sets).

for example:
spring;summer;autumn;winter
or
0:spring;1:summer;2:autumn;3:winter

Both are valid and the second example will store the values defined as the answer.

I wanted to split a string into a Dictionary and set a return for use on an MVC SelectList,

I refactored out the SplitAndReturnIndex to handle case where the string does not contain a Key, only a value, as can be seen from the code:


public IDictionary QuestionValues()
{
return Question.SurveyItemValues.Split(';')
.Select(x => new { Key = SplitAndReturnIndex(x, 0), Value = SplitAndReturnIndex(x, 1) })
.ToDictionary(x => x.Key, x => x.Value);
}

private string SplitAndReturnIndex(string x, int indexValue)
{
return x.IndexOf(':') == -1 ? x : x.Split(':')[indexValue];
}

Tuesday 4 January 2011

Hash Password using HMACSHA1 or HMACSHA512

Quite a handy snippet to generate an HMACSHA1 encoded string, I use this for passwords, but it could be used generate a check sum when passing values through to a webservice.

public static string GeneratePassword(string valueToHash)
{
byte[] saltValueBytes = Encoding.ASCII.GetBytes("This is for the Salt");
// Change passkey value to known value, I tend to use a guid
Rfc2898DeriveBytes passwordKey = new Rfc2898DeriveBytes("96D9E8D3-1318-4291-B459-84EAB0E268A6", saltValueBytes);
byte[] secretKey = passwordKey.GetBytes(16);
HMACSHA1 myHash = new HMACSHA1(secretKey);
byte[] encodedValue = Encoding.UTF8.GetBytes(valueToHash);

return Convert.ToBase64String(myHash.ComputeHash(encodedValue));
}


The problem with this, has always been everyone has the same salt.

So a change in security and use of SHA512:

With a way to generate a unique Salt:


public byte[] GenerateSalt()
        {
            System.Security.Cryptography.RNGCryptoServiceProvider r = new System.Security.Cryptography.RNGCryptoServiceProvider();

            byte[] array = new byte[16];

            r.GetBytes(array);

            return array;
        }

And return the Hash value with Generated Salt Passed in:

        public string GetHash(string password, byte[] salt)
        {
            string ret = string.Empty;

            try
            {
                byte[] passwordBytes = Encoding.ASCII.GetBytes(password);

                byte[] input = new byte[salt.Length + passwordBytes.Length];

                salt.CopyTo(input, 0);

                passwordBytes.CopyTo(input, salt.Length);

                System.Security.Cryptography.SHA512CryptoServiceProvider cr = new System.Security.Cryptography.SHA512CryptoServiceProvider();

                ret = Convert.ToBase64String(cr.ComputeHash(input));
            }
            catch (Exception Ex)
            {
                throw new Exception("Error hashing password", Ex);
            }

            return ret;
        }

Remember to save the salt somewhere that can be referrenced with the encrypted value, so you can check it.