0

I've been searching all over google just for a simple encryption and decryption method to store passwords. I'm not looking for a very complex encryption so I guess that's what is making it hard to find.

Does anyone have any simple encryption and decryption methods they could share with me?

Samrikan
  • 63
  • 3
  • 10
  • 4
    why would you need to "decrypt" passwords? – Thomas Lindvall Apr 06 '15 at 20:15
  • 1
    There's plenty of simple examples on the Internet for encryption and decryption and *hashing*, which is probably more along the lines of what you should be doing. We're not tutorial finders. In any case, rolling your own security mechanism is not something to be undertaken by anyone. If you have to ask how to do it, that's a good sign you **shouldn't** be doing it and should instead use something pre-built. – mason Apr 06 '15 at 20:16
  • @ThomasLindvall Are you trying to say I should encrypt a password, when the user logs in encrypt the password they typed in and match it with the stored original encrypted password? – Samrikan Apr 06 '15 at 20:18
  • 2
    @Samrikan, no that's not what he is trying to say. You should never be encrypting passwords and storing them. You should only be storing the hashes of the passwords which is quite different. Here's a good start: http://stackoverflow.com/questions/4948322/fundamental-difference-between-hashing-and-encryption-algorithms – Darin Dimitrov Apr 06 '15 at 20:20
  • 1
    What kind of project are you working on? have you considered using ASP.NET Identity it takes care of all the encryption and user management. – oskar132 Apr 06 '15 at 20:34

4 Answers4

3

You should hash your passwords using SHA256 for example. To check password validity, you hash the password received from the user and compare it with the hash stored in your database.

That said, you should ensure passwords are sent over SSL or they could be captured. If your own OS is not secured, the passwords could be captured in clear text as they arrive.

You would be better off using Windows Integrated Authentication when your web site is on the Intranet. For the Internet, OAuth might prove to be a better option.

Thanks to @philsoady for pointing out https://security.stackexchange.com/questions/35250/hmacsha512-versus-rfc2898derivebytes-for-password-hash for further reading.

Community
  • 1
  • 1
Tarik
  • 10,810
  • 2
  • 26
  • 40
  • @mason You are right. Thanks! Edited my answer accordingly. – Tarik Apr 06 '15 at 20:43
  • Sha256 is better suited to message integrity issues rather than password encoding. It is too fast – phil soady Apr 07 '15 at 00:04
  • @philsoady could you please elaborate? – Tarik Apr 07 '15 at 01:36
  • http://security.stackexchange.com/questions/35250/hmacsha512-versus-rfc2898derivebytes-for-password-hash BTW no downvote from for me – phil soady Apr 07 '15 at 05:43
  • @philsoady Thanks for the link. You are right, fast algorithms are prone to be broken through dictionary attacks. That can be remedied by hashing n times, n being large enough to make it computationally expensive. That said, I believe that we should not reinvent the wheel and use a secure framework. – Tarik Apr 07 '15 at 07:07
  • absolutely, use existing frameworks. My answer dot point 4. But if someone is determined to Build their own. Some tips can avoid a rubbish solution. – phil soady Apr 08 '15 at 08:41
1

Why you should use hashing rather than encryption:

If you use encryption, then you will need to have a key. This key can be taken and used to decrypt your passwords. Most likely, people within your organization will have access to this key. This means there is potential for everyone to know your users' passwords.

What does Hashing do differently?

Hashing is designed to be a one way linear transform. Therefore, you cannot go backwards and get the actual password. A simple hashing algorithm can be demonstrated in the following manner: use the remainder of dividing a password by 6. Lets say that your password is 10. You will store 4 in the database, as 10/6 has a remainder of 4. If you see 4 in the database, you cannot go backwards and figure out that you had 10, because it could also have been 4, or 16 (or infinitely many others). However, by passing in 10 you can verify that this is the same as the 4 stored in the database. You may notice an inherent flaw here. If you use 16 as your password it will still match in the database. This is known as a collision.

It is recommended that you use a hashing algorithm larger than SHA128 (output of 128 bits) because it is computationally infeasible to search until you find a collision. SHA algorithms are designed for speed, so these should still be fast enough for you (you said it was light weight). As an addition, some people generate sets of known popular passwords and their hashes (more commonly referred to as rainbow tables) which are used to quickly cross-reference against stored values.

For more security, creating a unique value (commonly referred to as salt) for each user which you should append to the beginning or end of your password before you hash. For example, the salt value is salt and the password is password, so we would hash saltpassword and store the result. Then when the user logs in again, we would compare the generated hash against the stored value. The reason this is better is in the scenario where two users have the same password, they will have two different unique hashes.

A small code sample:

using System.Security.Cryptography;

private string HashPassword(string password,  string salt) 
{
    string hashedString = CryptoConfig.CreateFromName("SHA256")
                                      .ComputeHash(salt+password);
    return hashedString;
}

Basically, using encryption means that passwords can be discovered. Using hashing means that you cannot feasibly found out what they are, just find a potential collision (unless you are really lucky).

Community
  • 1
  • 1
David
  • 236
  • 1
  • 12
  • Piggy-backing off Bob's answer, [here's](http://security.blogoverflow.com/2011/11/why-passwords-should-be-hashed/) a blog post from the StackExchange Security Community Blog with another explanation. There are also tons of articles out on why hashing is better than encrypting. – Cameron Apr 06 '15 at 22:20
1

As oscar132 explained in a comment, you shouldn't try and reinvent membership.

ASP.NET has a really good membership provider as a default option that requires not that much configuration. It has everything you need for good password management: User management, password resets, integrated web controls,...

It also does not do the terribly unsafe method of encryption, but instead hashes the passwords using the already recommended SHA256 method, with the option to use custom providers for enhanced cryptoalgorithms like PBKDF2 or bcrypt.

And even if your project already is underway, it's not that hard to add support for it. Visual Studio has default support for upgrading a asp.net website to an asp.net web forms application that implements membership.

Nzall
  • 3,439
  • 5
  • 29
  • 59
1

Not a SO question really but incase others find this. Some do and donts. Home grown sites can be lacking here.

  • Don't Store passwords, Store one-way hashes. Encode them if possible.
  • Don't Use HMacSHA* as the algorithm, USE BCRPT, SCRYPT or RFC2898DerivedBytes(PBKDF2) for PASSWORDS. SHA is too fast and not suitable for password hashing.
  • Use a SALT
  • Prefer standard well tested and accepted tools eg in your environment ASP.Net Identity
  • Always use SSL when requesting a users password
  • If you Must (are you really sure) Encrypt and Decrypt have a machine Key / decryption key policy. The encryption is only as good as the key's safety.

If serious application consider using SCyrpt for c# The bare minimum in standard c# to encode a password should be something like the following using Rfc2898.

a) Store the encoded password and random SALT in you database.
b) Use a cost that takes at least 250 msecs.
c) compare the user provided password with stored SALT to the same routine and compare hashes.

private string PasswordEncode(string password, byte[] salt ) {
      var deriver2898 = new Rfc2898DeriveBytes(password, salt,64000); // approx 300msecs
      byte[] hash = deriver2898.GetBytes(20); // 
      //    return hash;
      // If you dont like storing bytes, use a string
      return Convert.ToBase64String(hash);
}


// himalayan pink rock salt... the best kind
    public byte[] GenerateSalt(int size = 64) {
        using (var crypto = new RNGCryptoServiceProvider()) {
            var bytes = new byte[size];
            crypto.GetBytes(bytes); //get a bucket of very random bytes
            return bytes;
        }
    }

if you at this stage are still convinced you need to Encrypt then use one of the symmetric algorithms from Microsoft. EG AesManaged

  /// <summary>
    /// Encrypt using preferred provider. 
    /// </summary>
    /// <typeparam name="T">AesManaged,TripleDESCryptoServiceProvider,RijndaelManaged</typeparam>
    /// <param name="value">Value to be encrypted</param>
    /// <param name="decryptionKey">secret key .. see machine key descryptionKey</param>
    /// <param name="salt">salt for process</param>
    /// <returns></returns>
    public string Encrypt<T>(string value, string salt, string decryptionKey)
        where T : SymmetricAlgorithm, new() {
        var derivedKey = GenerateKey(decryptionKey, salt);
        SymmetricAlgorithm algorithm = new T();
        byte[] rgbKey = derivedKey.GetBytes(algorithm.KeySize >> 3);
        byte[] rgbIv = derivedKey.GetBytes(algorithm.BlockSize >> 3);

        ICryptoTransform transform = algorithm.CreateEncryptor(rgbKey, rgbIv);
        using (var buffer = new MemoryStream()) {
            using (var stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write)) {
                using (var writer = new StreamWriter(stream, Encoding.Unicode)) {
                    writer.Write(value);
                }
            }
            // before finished with the buffer return, now as the stream is now closed
            return Convert.ToBase64String(buffer.ToArray());
        }
    }

public string Decrypt<T>(string text, string salt, string decryptionKey)
        where T : SymmetricAlgorithm, new() {
        // could catch errors here, and return a null string. ? 
        // "CryptographicException: Padding is invalid and cannot be removed"
        // can occur if there is a coding problem , such as invalid key or salt passed to this routine.

        var derivedKey = GenerateKey(decryptionKey, salt);
        SymmetricAlgorithm algorithm = new T();
        byte[] rgbKey = derivedKey.GetBytes(algorithm.KeySize >> 3);
        byte[] rgbIv = derivedKey.GetBytes(algorithm.BlockSize >> 3);

        ICryptoTransform transform = algorithm.CreateDecryptor(rgbKey, rgbIv);
        using (var buffer = new MemoryStream(Convert.FromBase64String(text))) {
            using (var stream = new CryptoStream(buffer, transform, CryptoStreamMode.Read)) {
                using (var reader = new StreamReader(stream, Encoding.Unicode)) {
                    return reader.ReadToEnd(); // error here implies wrong keys supplied , and code or environment problem.. NASTY issue
                }
            }
        }
    }


  public DeriveBytes GenerateKey(string salt, string decryptionKey) {
        // generate the key from the shared secret and the salt
        var saltAsByteArray = salt.UTF8StringToByteArray();
        var key = new Rfc2898DeriveBytes(decryptionKey, saltAsByteArray);
        return key;
    }

Sample calls: of encrypt and decrypt. Plus consider,how to get machine key and use as key here

Encrypt<AesManaged>(password, salt, decryptionKey);
Decrypt<AesManaged>(encryptedPassword, salt, decryptionKey);
Community
  • 1
  • 1
phil soady
  • 11,043
  • 5
  • 50
  • 95