Storing Secrets (Like Passwords)

Hey Guys,  I thought I would share a little snippet of code that I use the occasional time I need to store passwords or things like that.  This is a class that I call SecretUtility.  What it does is generates SHA256 Hashes from whatever is inputed, normally Passwords.  Moreover it Salts the input making it much harder for an attacker to discover the original secret put into it.



The point of salting it by the way (dumbed down version), is that even if the attacker knew exactly how the salt was used, it would take a long time and a lot of space to generate the type of lookup tables required to crack the password.  Long enough, and large enough to hopefully make it not worth their while.  And if they did decide to embark upon this, they would have to do the same for each and every user, since each and every user has a different salt.

While my specific interpretation may have varying opinions as to whether this is done properly or improperly, I think in practice, it's done pretty well.  I DO very much welcome your thoughts and an opinions, as I consider myself a lifetime-learner.  So if you have some recommendations, please do share!

If you have questions, please do ask.

On to the good stuff.  The class:
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Utilities {


       
/// <summary>

       
/// This utility is designed to store secrets safetly..

       
/// That is, this utility is unable to return a stored secret, it is just able to

       
/// generate a hash, so that when the same secret is handed in twice, it can tell you if the

       
/// secrets are the same.

       
/// </summary>

       
[CLSCompliant(true)]

       
public class SecretUtility {


               
/// <summary>

               
/// Password Encoding

               
/// </summary>

               
private static Encoding m_encoding;


               
/// <summary>

               
/// Random number generator

               
/// </summary>

               
private static Random m_random;


               
/// <summary>

               
/// Hash Provider

               
/// </summary>

               
private static SHA256 m_sha256;


               
/// <summary>

               
/// Grab the Secret Processors Encoding

               
/// </summary>

               
public static Encoding Encoding {

                       
get {

                               
return m_encoding;

                       
}

               
}


               
/// <summary>

               
/// initialize static members

               
/// </summary>

               
static SecretUtility() {

                        m_encoding
= Encoding.UTF8;

                        m_random
= new Random();

                     
  m_sha256
= new SHA256Managed();

               
}


               
/// <summary>

               
/// Generate new random salt

               
/// </summary>

               
/// <returns></returns>

               
public static byte[] new_salt() {

                       
byte[] salt = new byte[64];

                        m_random
.NextBytes(salt);

                       
return salt;

               
}


               
/// <summary>

               
/// Generate Hash

               
/// </summary>

               
/// <param name="input">decoded password</param>

               
/// <param name="salt">salt</param>

               
/// <returns>binary hash</returns>

               
public static byte[] get_hash(byte[] input, byte[] salt) {

                       
MemoryStream ms = new MemoryStream();

                        ms
.Write(input, 0, input.Length);

                        ms
.Write(salt, 0, salt.Length);

                       
return m_sha256.ComputeHash(ms.ToArray());

               
}


       
}
}

What this requires, is that you store both the secret-hash and the secret-hash-salt.  The salt does not need to be kept secret. (or at least any more secret than the hash).

here's how you use it.


byte[] salt = SecretUtility.new_salt();
byte[] secret_hash = SecretUtility.get_hash(

       
SecretUtility.Encoding.GetBytes("SUPER PASSWORD!!!!"),

        salt
);

There you have it.  You store the hash and the salt in your database table or whatever.  If you were to use SQL Server, the hash requires a binary(32) and the salt requires a binary(64) field.

I should note that most things I read suggest that a salt doesn't need to be this complex.  And that's fine, you can easily adjust the length of that accordingly in the class

When you want to test if a password entered is correct, you do so like this.


byte[] salt = GetSaltFromDatabase("username"); //however you have this implemented
byte[] secret_hash = SecretUtility.get_hash(

       
SecretUtility.Encoding.GetBytes("A WRONG PASSWORD"),

        salt
);

Now you have a

hash generated from the purposed secret, with the same salt you used in the first place.  If the secret was correct, the hash will be the same as the secret you already stored.


While I think that the code to compare this is out of the scope of this article, I'll throw a bone.  If you really want to see an actual ADO.NET implementation of this, let me know.


SELECT ISNULL
((SELECT 1 FROM users WHERE username = @username AND password_hash = @password_hash ), 0)

So in this case, if the password entered is the same as when the user registered, you would get a nice 1 scalar response.  However if the password was different, you get a scalar 0.

There are no limits to the size, length or complexity of storing passwords this way.  The longer a password is, the much harder it is to crack.  Also, keep in mind, you cannot recover a users password in this way, you can only offer to set it to something else.

Anyways, hope you find that helpful. 

Read more: http://forum.codecall.net/topic/60754-storing-secrets-like-passwords/#ixzz2GdjYu93Y

No comments:

Post a Comment