2

I found some code online that works fairly well for what I am trying to do. I need something that will encrypt a password, save it to a database, and retrieve with ease. The below code does almost everything I am looking for.

        string UserName = txtUser.Text;
        string password = txtPass.Text;

        string encrKey = "keyvalue";
        byte[] byteKey = { };
        byte[] IV = {25, 47, 60, 88, 99, 106, 125, 139};
        byteKey = Encoding.UTF8.GetBytes(encrKey.Substring(0, 8));
        DESCryptoServiceProvider des = new DESCryptoServiceProvider();
        byte[] inputArray = Encoding.UTF8.GetBytes(password);

        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(byteKey, IV), CryptoStreamMode.Write);
        cs.Write(inputArray, 0, inputArray.Length);
        cs.FlushFinalBlock();
        password = Convert.ToBase64String(ms.ToArray());

        SqlCommand cmd = new SqlCommand("INSERT INTO USers (UserName, Password) VALUES (@UserName, @Password)", myConnection);
        cmd.CommandType = CommandType.Text;

        cmd.Parameters.AddWithValue("@UserName", UserName);
        cmd.Parameters.AddWithValue("@Password", password);

        SqlDataReader rdr = cmd.ExecuteReader();

The issue that I am running into is the code errors out when the password is 8 characters or longer. I get this error:

System.Security.Cryptography.CryptographicException: Specified key is not a valid size for this algorithm. The error is generated on the Cryptostream line.

Do I need to use a different type for my keys?

Matt
  • 1,220
  • 3
  • 21
  • 36
  • possible duplicate of [Salting Your Password: Best Practices?](http://stackoverflow.com/questions/674904/salting-your-password-best-practices) – Cole Tobin Jul 10 '14 at 20:52

5 Answers5

14

The common practice is not to encrypt a password in the database but to hash it.
When the user attempts to login, you take his typed password, hash it and compare to the hash stored in your db.

The industry standard hashing algorithm is SHA-1, which is readly available in .NET.

For even greater security you use a "Salt" in your hashing.

You can read more about it here: Salting Your Password: Best Practices?

Community
  • 1
  • 1
Variant
  • 17,279
  • 4
  • 40
  • 65
  • 1
    I tried MD5 and got it working perfectly but I could not figure out how to compare the hash in the database to the login form and the forgot password link. – Matt Jun 28 '11 at 21:20
  • When you hash your passwords you cannot do a "Forgot your password" to send the user his current password, instead you offer a "Reset my password". – Variant Jun 28 '11 at 21:26
  • SHA1 is better than MD5 as MD5 is no longer considered secure enough. – Variant Jun 28 '11 at 21:26
  • I can do that. My last question would be, how do I compare the plain text password from the login form text box to the hashed password in the database? – Matt Jun 28 '11 at 21:27
  • when the user attempts to login you hash his typed password using the exact same hashing algorithm you did with his initial password and compare the hash results. – Variant Jun 28 '11 at 21:27
  • So would I do the compare through my SQL statement? My current statement is SELECT u.UID, ServerID, Permission FROM Users u, Roles WHERE UserName = @user AND Password = @password – Matt Jun 28 '11 at 21:36
  • that would be fine as long as @password is the hashed value. – Variant Jun 28 '11 at 21:38
  • I had @password set to the textbox still. I changed it to my hashed value and everything works great. Thanks a lot for all of your help. – Matt Jun 28 '11 at 21:41
  • _"The industry standard hashing algorithm is SHA-1..."_ **NO** Even though it hasn't been broken like MD5, **don't use SHA-1**. Use [bcrypt](http://bcrypt.sourceforge.net/). – Cole Tobin Jul 10 '14 at 20:47
2

If you need to actually reverse the encryption, just use the ProtectedData class: http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata.aspx

If others here are correct, use a salted hash as in the example class below. The following was taken from "Another example of how to store a salted password hash"

public sealed class PasswordHash
{
    const int SaltSize = 16, HashSize = 20, HashIter = 10000;
    readonly byte[] _salt, _hash;
    public PasswordHash(string password)
    {
        new RNGCryptoServiceProvider().GetBytes(_salt = new byte[SaltSize]);
        _hash = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
    }
    public PasswordHash(byte[] hashBytes)
    {
        Array.Copy(hashBytes, 0, _salt = new byte[SaltSize], 0, SaltSize);
        Array.Copy(hashBytes, SaltSize, _hash = new byte[HashSize], 0, HashSize);
    }
    public PasswordHash(byte[] salt, byte[] hash)
    {
        Array.Copy(salt, 0, _salt = new byte[SaltSize], 0, SaltSize);
        Array.Copy(hash, 0, _hash = new byte[HashSize], 0, HashSize);
    }
    public byte[] ToArray()
    {
        byte[] hashBytes = new byte[SaltSize + HashSize];
        Array.Copy(_salt, 0, hashBytes, 0, SaltSize);
        Array.Copy(_hash, 0, hashBytes, SaltSize, HashSize);
        return hashBytes;
    }
    public byte[] Salt { get { return (byte[])_salt.Clone(); } }
    public byte[] Hash { get { return (byte[])_hash.Clone(); } }
    public bool Verify(string password)
    {
        byte[] test = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
        for (int i = 0; i < HashSize; i++)
            if (test[i] != _hash[i])
                return false;
        return true;
    }
}
csharptest.net
  • 62,602
  • 11
  • 71
  • 89
1

Hashing passwords is much better than encrypting. You store the hash of the password in the database and you don't care any more about the normal text password. When the user login, you fetch the normal text password, hash it and compare the two hashes (i.e. the one in the database, and the one you hashed from the user input) to authenticate. The clear benefit here is that you ensure no one - whatever the why he accessed the database - will know the original password (theoretically).

mohammedn
  • 2,926
  • 3
  • 23
  • 30
1

i suggest u use bcrypt. the source code available at http://code.google.com/p/bcryptnet/ download and use it. but before using it. read the documentation and understand how it works and why bcrypt... it is important.

through my research for few weeks about password encryption. i finally found this bcrypt which best suit my need. ( i think it is the best suited for password, correct me if i am wrong)

it is a one way encryption. just like what few dope programmers said, hash it and compare but not decrypt.

hope this help you. if you find othre interesting things please let me know XD peace~~

anything i said wrong, correct me XD

Loonb
  • 1,068
  • 5
  • 18
  • 30
0

Try this instead:

var hash = Encoding.ASCII.GetBytes(password);
var sha1 = new SHA1CryptoServiceProvider();
var sha1hash = sha1.ComputeHash(hash);
var hashedPassword = Encoding.ASCII.GetString(sha1hash);
Cole Tobin
  • 9,206
  • 15
  • 49
  • 74
mrK
  • 2,208
  • 4
  • 32
  • 46
  • 1
    -1 Using ASCII is a **terrible** idea. That means any characters outside the ASCII range are _ignored_! So two _completly different_ passwords consisting of only non-ASCII characters would have the same hash! – Cole Tobin Jul 10 '14 at 20:49