Wednesday, November 11, 2015

Best way to secure password using Cryptographic algorithms in C# .NET

Let me explain with some of the common ways of storing passwords in the database with its demerits. By reading this full article you will understand the best way to secure your password  using Cryptographic algorithms in C# .NET.


1. Plain text

Storing password in plain text is the worst way of password management. If the database is compromised by the hacker, with no effort he can reveal all the passwords.

2. Symmetric Key Encryption

One usual way to storing password is using encryption. it's a two-way process. That means the password is encrypted using the secret key when storing and decrypt using the same key for the password authentication.

It's better than storing the password as plain text. But key management is the challenge. Where do you save that key? If it is a database, It won't be difficult for the hacker who got the encrypted password by hacking the database and decrypt it using the same key.

3. Asymmetric Key Encryption

So instead of using symmetric key encryption algorithm. we can use asymmetric key encryption algorithm like RSA where client uses public key to encrypt the password and sends it to the server for storage. When authenticate a private key is used to decrypt the password. That private key should be kept secret. This is also not a great solution as the key management is difficult like the previous way.

4. Hashing

If we use Hashing there won't be any over head of key management. Also no need to decrypt the password back to plain text. As we discussed in my previous article Cryptographic Hashing Algorithm in .NET C#, Hashing is one way operation. Once a data is hashed we cannot reverse and get the original message, It has four important properties,
  • Easy to compute the hash value for any given message
  • Not possible to generate a message from the given hash
  • Not possible to modify a message without changing the hash
  • Not possible to find two different messages with the same hash

Two types of attack is possible on the hashed password. They are,
  1. Brute force attack
  2. Rainbow table attack
Brute force attack

The attacker would try the different combination of passwords hash that is equivalent to the password hash you have stored. Using the latest high performance graphic processor system it is possible to generate billions of random password hash. It only the matter of time to  generate the correct password.

Rainbow table attack

A rainbow table is a listing of all possible plain text permutations of hashed passwords specific to a given hash algorithm. Which is often used for crack the password from the hashed values that we stored in the application database. It can be Giga bytes of size. Once an attacker gains access to a system’s password database, the password cracker compares the rainbow table’s precompiled list of hashes to hashed passwords in the database. The rainbow table relate plaintext possibilities with each of those hashes. Thus attacker could crack the password.

5. Salted Hash

It is common for a web application to store in a database the hash value of a user's password. Without a salt, a successful SQL injection attack may yield easily crackable passwords. Because many users re-use passwords for multiple sites, the use of a salt is an important component of overall web application security


If we append a random value with a hashed password, Which is difficult for the attacker to hack using brute force or rainbow table attack. The random value is called Salt. The Salted hash and the Salt will be stored in the database as the Salt is required when the password authentication.

Salted Hash Sample Code :
using System;
using System.Security.Cryptography;
using System.Text;
static void Main()
{
    const string password = "SampleP455w0rd";
    byte[] salt = GenerateSalt();

    Console.WriteLine("Sample Password : " + password);
    Console.WriteLine("Generated Salt : " + Convert.ToBase64String(salt));
    Console.WriteLine();

    var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);

    Console.WriteLine("Salted Hash Password : " + Convert.ToBase64String(hashedPassword));
    Console.WriteLine();
   
    Console.ReadLine();
}
public static byte[] GenerateSalt()
{
    const int saltLength = 32;

    using (var randomNumberGenerator = new RNGCryptoServiceProvider())
    {
        var randomNumber = new byte[saltLength];
        randomNumberGenerator.GetBytes(randomNumber);

        return randomNumber;
    }
}
private static byte[] Combine(byte[] first, byte[] second)
{
    var ret = new byte[first.Length + second.Length];

    Buffer.BlockCopy(first, 0, ret, 0, first.Length);
    Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);

    return ret;
}
public static byte[] HashPasswordWithSalt(byte[] toBeHashed, byte[] salt)
{
    using (var sha256 = SHA256.Create())
    {
        var combinedHash = Combine(toBeHashed, salt);

        return sha256.ComputeHash(combinedHash);
    }
}
Console Output



6. Password Based Key Derivation Function (PBKDF2)

Attackers can use super computers for the brute force attack as it could generate large number of random passwords within a sort period of time. To solve this PBKDF2 is used.


The PBKDF2 expect password input with salt also additionally the number of iteration the password should be hashed. It  makes password cracking much more difficult also increase the time taken to generate the hash value. You can see the delay in below sample code based on the number of iteration value u have passed.

When the standard was written in 2000, the recommended minimum number of iterations was 1000, but the parameter is intended to be increased over time as CPU speeds increase. As of 2005 a Kerberos standard recommended 4096 iterations, Apple iOS 3 used 2000, iOS 4 used 10000, while in 2011 LastPass used 5000 iterations for JavaScript clients and 100000 iterations for server-side hashing.

PBKDF2 Sample Code
using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
static void Main()
{
    const string passwordToHash = "SamplePassword";

    HashPassword(passwordToHash, 100);

    HashPassword(passwordToHash, 50000);

    HashPassword(passwordToHash, 500000);

    Console.ReadLine();
}
private static void HashPassword(string passwordToHash, int numberOfRounds)
{
    var sw = new Stopwatch();

    sw.Start();
    var hashedPassword = HashPassword(Encoding.UTF8.GetBytes(passwordToHash), GenerateSalt(), numberOfRounds);
    sw.Stop();

    Console.WriteLine("Password to hash : " + passwordToHash);
    Console.WriteLine("PBKDF2 Hashed Password : " + Convert.ToBase64String(hashedPassword));
    Console.WriteLine("Iterations : " + numberOfRounds);
    Console.WriteLine("Elapsed Time : " + sw.ElapsedMilliseconds + "ms");
    Console.WriteLine();
}
public static byte[] GenerateSalt()
{
    using (var randomNumberGenerator = new RNGCryptoServiceProvider())
    {
        var randomNumber = new byte[32];
        randomNumberGenerator.GetBytes(randomNumber);

    return randomNumber;
    }
}
public static byte[] HashPassword(byte[] toBeHashed, byte[] salt, int numberOfRounds)
{
    using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(toBeHashed, salt, numberOfRounds))
    {
        return rfc2898DeriveBytes.GetBytes(32);
    }
}
Console Output



12 comments:

  1. I am in fact grateful to the owner of this web site who has shared this enormous piece of writing at
    here.

    ReplyDelete
  2. Rattling clean website, thanks for this post.

    ReplyDelete
  3. This design is spectacular! You most certainly know how to keep a reader
    amused. Between your wit and your videos, I
    was almost moved to start my own blog (well, almost...HaHa!) Excellent job.
    I really loved what you had to say, and more
    than that, how you presented it. Too cool!

    ReplyDelete
  4. I have been exploring for a little bit for any high-quality articles
    or weblog posts in this sort of house . Exploring in Yahoo I
    finally stumbled upon this website. Studying this information So i'm satisfied to convey that I have
    a very good uncanny feeling I discovered exactly what I needed.
    I such a lot unquestionably will make sure to do not forget this website and provides it a glance on a
    relentless basis.

    ReplyDelete
  5. Hey I am so delighted I found your blog, I really found you by
    mistake, while I was looking on Yahoo for something else,
    Anyhow I am here now and would just like to say cheers for
    a incredible post and a all round entertaining blog (I also
    love the theme/design), I don't have time to browse it all at the moment but I have bookmarked it
    and also added in your RSS feeds, so when I have time I will be back
    to read more, Please do keep up the superb job.

    ReplyDelete
  6. hi!,I really like your writing very so much!
    percentage we keep up a correspondence extra about your article
    on AOL? I need a specialist in this house to solve my problem.

    May be that is you! Looking forward to see you.

    ReplyDelete
  7. Normally I do not read post on blogs, but I wish to say that this write-up very forced me to check out and do it!
    Your writing style has been surprised me. Thank you, very great article.

    ReplyDelete
  8. hello!,I love your writing so a lot! proportion we
    keep in touch more approximately your article on AOL? I require an expert in this house to resolve my problem.
    May be that's you! Looking forward to peer you.

    ReplyDelete
  9. I truly appreciate this post. I have been looking everywhere for this!

    Thank goodness I found it on Bing. You have made my day!

    Thx again!

    ReplyDelete
  10. Oh my goodness! Incredible article dude! Thanks, However I am having troubles with
    your RSS. I don't know why I cannot subscribe to it. Is there anybody
    else getting similar RSS issues? Anybody who knows the answer will you kindly
    respond? Thanx!!

    ReplyDelete
  11. Hi, what about decrypt?
    How can decrypt after encryption done with your algorithm?
    Please respond.

    ReplyDelete
  12. How to use Password Based Key Derivation Function (PBKDF2) in Login form? As It is every time generate new key? How to compare with old stored encrypted password?

    ReplyDelete