2019年5月24日 星期五

The right way to implement password hashing using PBKDF2 and C#

Following from my previous post about hashing using BCrypt and in response to some comments I received on Google+, I decide to provide an alternative hashing implementation using PBKDF2.
As you will notice, the implementation is somewhat bigger than the one provided for BCrypt but in effect, both code segments perform the same task. First we create a hash from the plain text password and then we validate a password against the stored hash.
NOTE: The constants, like the iterations, can be changed to tweak the hash strength.
public class PasswordHash
{
public const int SaltByteSize = 24;
public const int HashByteSize = 20; // to match the size of the PBKDF2-HMAC-SHA-1 hash
public const int Pbkdf2Iterations = 1000;
public const int IterationIndex = 0;
public const int SaltIndex = 1;
public const int Pbkdf2Index = 2;
public static string HashPassword(string password)
{
var cryptoProvider = new RNGCryptoServiceProvider();
byte[] salt = new byte[SaltByteSize];
cryptoProvider.GetBytes(salt);
var hash = GetPbkdf2Bytes(password, salt, Pbkdf2Iterations, HashByteSize);
return Pbkdf2Iterations + ":" +
Convert.ToBase64String(salt) + ":" +
Convert.ToBase64String(hash);
}
public static bool ValidatePassword(string password, string correctHash)
{
char[] delimiter = { ':' };
var split = correctHash.Split(delimiter);
var iterations = Int32.Parse(split[IterationIndex]);
var salt = Convert.FromBase64String(split[SaltIndex]);
var hash = Convert.FromBase64String(split[Pbkdf2Index]);
var testHash = GetPbkdf2Bytes(password, salt, iterations, hash.Length);
return SlowEquals(hash, testHash);
}
private static bool SlowEquals(byte[] a, byte[] b)
{
var diff = (uint)a.Length ^ (uint)b.Length;
for (int i = 0; i < a.Length && i < b.Length; i++)
{
diff |= (uint)(a[i] ^ b[i]);
}
return diff == 0;
}
private static byte[] GetPbkdf2Bytes(string password, byte[] salt, int iterations, int outputBytes)
{
var pbkdf2 = new Rfc2898DeriveBytes(password, salt);
pbkdf2.IterationCount = iterations;
return pbkdf2.GetBytes(outputBytes);
}
}
The code above is pretty self explanatory. You call PasswordHash.HashPassword(plaintext) to get the hash back and then you call PasswordHash.ValidatePassword(plainText, storedHash) to check if the supplied password matches the originally supplied one by the user.
Personally, I'm a fan of BCrypt for its simplicity, but it is nice to know that there are two ways to achieve the same thing.
What is your preference? Did you find this useful? Let me know in the comments.

from : https://cmatskas.com/-net-password-hashing-using-pbkdf2/

Password hash using PBKDF2 with HMAC SHA256/ SHA512 in .NET Framework 4.7.2 and .NET Core 2.0

Here I am back with more updates on PBKDF2 with HMAC but this time I am talking about SHA-2 family of hashes which includes SHA-256 and SHA-512, both that to in standard .NET framework.
I have posted another article for implementing PBKDF2 with SHA-2 family for password hashing which has custom implementation of PBKDF2 as at that time this option was not available in standard .NET framework.
Latest version (at the time of writing this article) of .NET framework that is 4.7.2 has introduced in-build feature to use PBKDF2 with SHA-2 (that is SHA-256 and SHA-512).
I have written a sample class which you can use for generating PBKDF2 based salted hash using SHA-2 family.
using System;
using System.Security.Cryptography;

namespace pbkdf2_sha2
{
    class PasswordHash
    {
        private const int SaltByteSize = 32;
        private const int HashByteSize = 32;
        private const int Iterations = 4096;

        private static string GetSalt()
        {
            var cryptoProvider = new RNGCryptoServiceProvider();
            byte[] b_salt = new byte[SaltByteSize];
            cryptoProvider.GetBytes(b_salt);
            return Convert.ToBase64String(b_salt);
        }

        public static string GetPasswordHash(string password)
        {
            string salt = GetSalt();

            byte[] saltBytes = Convert.FromBase64String(salt);
            byte[] derived;

            using (var pbkdf2 = new Rfc2898DeriveBytes(
                password,
                saltBytes,
                Iterations,
                HashAlgorithmName.SHA512))
            {
                derived = pbkdf2.GetBytes(HashByteSize);
            }

            return string.Format("{0}:{1}:{2}", Iterations, Convert.ToBase64String(derived), Convert.ToBase64String(saltBytes));
        }

        public static bool VerifyPasswordHash(string password, string hash)
        {
            try
            {
                string[] parts = hash.Split(new char[] { ':' });

                byte[] saltBytes = Convert.FromBase64String(parts[2]);
                byte[] derived;

                int iterations = Convert.ToInt32(parts[0]);

                using (var pbkdf2 = new Rfc2898DeriveBytes(
                    password,
                    saltBytes,
                    iterations,
                    HashAlgorithmName.SHA512))
                {
                    derived = pbkdf2.GetBytes(HashByteSize);
                }

                string new_hash = string.Format("{0}:{1}:{2}", Iterations, Convert.ToBase64String(derived), Convert.ToBase64String(saltBytes));

                return hash == new_hash;
            }
            catch
            {
                return false;
            }
        }
    }
}
For calling these methods for generating and then verifying use it like this:
var password = "YourTestPassword";
string hash = PasswordHash.GetPasswordHash(password);
Console.WriteLine(hash);
Console.WriteLine(PasswordHash.VerifyPasswordHash(password, hash));

from : https://edunyte.com/2018/11/password-hash-using-pbkdf2-with-hmac-sha256-sha512-in-net-framework-4-7-2-and-net-core-2-0/

2019年5月23日 星期四

Decrypting with private key from .pem file in c# with .NET crypto library

//------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider  ---
public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
    byte[] MODULUS, E, D, P, Q, DP, DQ, IQ ;

// ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
    MemoryStream  mem = new MemoryStream(privkey) ;
    BinaryReader binr = new BinaryReader(mem) ;    //wrap Memory Stream with BinaryReader for easy reading
    byte bt = 0;
    ushort twobytes = 0;
    int elems = 0;
    try {
        twobytes = binr.ReadUInt16();
        if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
            binr.ReadByte();    //advance 1 byte
        else if (twobytes == 0x8230)
            binr.ReadInt16();   //advance 2 bytes
        else
            return null;

        twobytes = binr.ReadUInt16();
        if (twobytes != 0x0102) //version number
            return null;
        bt = binr.ReadByte();
        if (bt !=0x00)
            return null;


//------  all private key components are Integer sequences ----
        elems = GetIntegerSize(binr);
        MODULUS = binr.ReadBytes(elems);

        elems = GetIntegerSize(binr);
        E = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        D = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        P = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        Q = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        DP = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        DQ = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        IQ = binr.ReadBytes(elems) ;

        Console.WriteLine("showing components ..");
        if (verbose) {
            showBytes("\nModulus", MODULUS) ;
            showBytes("\nExponent", E);
            showBytes("\nD", D);
            showBytes("\nP", P);
            showBytes("\nQ", Q);
            showBytes("\nDP", DP);
            showBytes("\nDQ", DQ);
            showBytes("\nIQ", IQ);
        }

// ------- create RSACryptoServiceProvider instance and initialize with public key -----
        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
        RSAParameters RSAparams = new RSAParameters();
        RSAparams.Modulus =MODULUS;
        RSAparams.Exponent = E;
        RSAparams.D = D;
        RSAparams.P = P;
        RSAparams.Q = Q;
        RSAparams.DP = DP;
        RSAparams.DQ = DQ;
        RSAparams.InverseQ = IQ;
        RSA.ImportParameters(RSAparams);
        return RSA;
    }
    catch (Exception) {
        return null;
    }
    finally {
        binr.Close();
    }
}

from : https://stackoverflow.com/questions/1162504/decrypting-with-private-key-from-pem-file-in-c-sharp-with-net-crypto-library