Category Archives: ASP .NET

Asp .NET Core custom Identity PasswordHasher

A few days ago I started to develop a new web application using ASP.NET Core, that work with the same database (so the same Users credentials) of a web application made in ASP .NET MVC 5. That’s fine and funny. But the big problem is: Identity on ASP.NET Core changed the password’s hash and if you login with the new version it will update the old hash with the new one, so on the other application is no longer possible login.
What can we do to tell to Identity: don’t change the existing password hash?
A solution is take from git hub the original class PasswordHasher and make my version, on override the method HashPassword return always the password hash of V2, so is guarantee the compatibility with previous versions of Identity

/// 
<summary>
/// Returns a hashed representation of the supplied <paramref name="password"/> for the specified <paramref name="user"/>.
/// </summary>

/// <param name="user">The user whose password is to be hashed.</param>
/// <param name="password">The password to hash.</param>
/// <returns>A hashed representation of the supplied <paramref name="password"/> for the specified <paramref name="user"/>.</returns>
public override string HashPassword(TUser user, string password)
{
    if (password == null)
    {
        throw new ArgumentNullException(nameof(password));
    }

    //if (_compatibilityMode == PasswordHasherCompatibilityMode.IdentityV2)
    //{
    //	return Convert.ToBase64String(HashPasswordV2(password, _rng));
    //}
    //else
    //{
    //	return Convert.ToBase64String(HashPasswordV3(password, _rng));
    //}
                //retunr always the hash of V2
    return Convert.ToBase64String(HashPasswordV2(password, _rng));
}

So my class look like this:

using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Identity;

namespace MyApp.Manager.Services
{
	/// 
<summary>
	/// Implements the standard Identity password hashing.
	/// </summary>

	/// <typeparam name="TUser">The type used to represent a user.</typeparam>
	public class MyPasswordHasher<TUser> : PasswordHasher<TUser> where TUser : class
	{
		/* =======================
         * HASHED PASSWORD FORMATS
         * =======================
         * 
         * Version 2:
         * PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
         * (See also: SDL crypto guidelines v5.1, Part III)
         * Format: { 0x00, salt, subkey }
         *
         * Version 3:
         * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
         * Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
         * (All UInt32s are stored big-endian.)
         */

		private readonly PasswordHasherCompatibilityMode _compatibilityMode;
		private readonly int _iterCount;
		private readonly RandomNumberGenerator _rng;

		/// 
<summary>
		/// Creates a new instance of <see cref="PasswordHasher{TUser}"/>.
		/// </summary>

		/// <param name="optionsAccessor">The options for this instance.</param>
		public StarmePasswordHasher(IOptions<PasswordHasherOptions> optionsAccessor = null)
		{
			var options = optionsAccessor?.Value ?? new PasswordHasherOptions();

			_compatibilityMode = PasswordHasherCompatibilityMode.IdentityV2;
			switch (_compatibilityMode)
			{
				case PasswordHasherCompatibilityMode.IdentityV2:
					// nothing else to do
					break;

				case PasswordHasherCompatibilityMode.IdentityV3:
					_iterCount = options.IterationCount;
					if (_iterCount < 1)
					{
						throw new InvalidOperationException("");
					}
					break;

				default:
					throw new InvalidOperationException("");
			}
			_rng = RandomNumberGenerator.Create();
			//_rng = options.Rng;
		}

		// Compares two byte arrays for equality. The method is specifically written so that the loop is not optimized.
		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private static bool ByteArraysEqual(byte[] a, byte[] b)
		{
			if (a == null && b == null)
			{
				return true;
			}
			if (a == null || b == null || a.Length != b.Length)
			{
				return false;
			}
			var areSame = true;
			for (var i = 0; i < a.Length; i++)
			{
				areSame &= (a[i] == b[i]);
			}
			return areSame;
		}

		/// 
<summary>
		/// Returns a hashed representation of the supplied <paramref name="password"/> for the specified <paramref name="user"/>.
		/// </summary>

		/// <param name="user">The user whose password is to be hashed.</param>
		/// <param name="password">The password to hash.</param>
		/// <returns>A hashed representation of the supplied <paramref name="password"/> for the specified <paramref name="user"/>.</returns>
		public override string HashPassword(TUser user, string password)
		{
			if (password == null)
			{
				throw new ArgumentNullException(nameof(password));
			}

			//if (_compatibilityMode == PasswordHasherCompatibilityMode.IdentityV2)
			//{
			//	return Convert.ToBase64String(HashPasswordV2(password, _rng));
			//}
			//else
			//{
			//	return Convert.ToBase64String(HashPasswordV3(password, _rng));
			//}
            //retunr always the hash of V2
			return Convert.ToBase64String(HashPasswordV2(password, _rng));
		}

		private static byte[] HashPasswordV2(string password, RandomNumberGenerator rng)
		{
			const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes
			const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes
			const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits
			const int SaltSize = 128 / 8; // 128 bits

			// Produce a version 2 (see comment above) text hash.
			byte[] salt = new byte[SaltSize];
			rng.GetBytes(salt);
			byte[] subkey = KeyDerivation.Pbkdf2(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength);

			var outputBytes = new byte[1 + SaltSize + Pbkdf2SubkeyLength];
			outputBytes[0] = 0x00; // format marker
			Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
			Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, Pbkdf2SubkeyLength);
			return outputBytes;
		}

		private byte[] HashPasswordV3(string password, RandomNumberGenerator rng)
		{
			return HashPasswordV3(password, rng,
				prf: KeyDerivationPrf.HMACSHA256,
				iterCount: _iterCount,
				saltSize: 128 / 8,
				numBytesRequested: 256 / 8);
		}

		private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
		{
			// Produce a version 3 (see comment above) text hash.
			byte[] salt = new byte[saltSize];
			rng.GetBytes(salt);
			byte[] subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);

			var outputBytes = new byte[13 + salt.Length + subkey.Length];
			outputBytes[0] = 0x01; // format marker
			WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
			WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
			WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
			Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
			Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
			return outputBytes;
		}

		private static uint ReadNetworkByteOrder(byte[] buffer, int offset)
		{
			return ((uint)(buffer[offset + 0]) << 24)
				| ((uint)(buffer[offset + 1]) << 16)
				| ((uint)(buffer[offset + 2]) << 8)
				| ((uint)(buffer[offset + 3]));
		}

		/// 
<summary>
		/// Returns a <see cref="PasswordVerificationResult"/> indicating the result of a password hash comparison.
		/// </summary>

		/// <param name="user">The user whose password should be verified.</param>
		/// <param name="hashedPassword">The hash value for a user's stored password.</param>
		/// <param name="providedPassword">The password supplied for comparison.</param>
		/// <returns>A <see cref="PasswordVerificationResult"/> indicating the result of a password hash comparison.</returns>
		/// <remarks>Implementations of this method should be time consistent.</remarks>
		public override PasswordVerificationResult VerifyHashedPassword(TUser user, string hashedPassword, string providedPassword)
		{
			if (hashedPassword == null)
			{
				throw new ArgumentNullException(nameof(hashedPassword));
			}
			if (providedPassword == null)
			{
				throw new ArgumentNullException(nameof(providedPassword));
			}

			byte[] decodedHashedPassword = Convert.FromBase64String(hashedPassword);

			// read the format marker from the hashed password
			if (decodedHashedPassword.Length == 0)
			{
				return PasswordVerificationResult.Failed;
			}
			switch (decodedHashedPassword[0])
			{
				case 0x00:
					if (VerifyHashedPasswordV2(decodedHashedPassword, providedPassword))
					{
						// This is an old password hash format - the caller needs to rehash if we're not running in an older compat mode.
						return (_compatibilityMode == PasswordHasherCompatibilityMode.IdentityV3)
							? PasswordVerificationResult.SuccessRehashNeeded
							: PasswordVerificationResult.Success;
					}
					else
					{
						return PasswordVerificationResult.Failed;
					}

				case 0x01:
					int embeddedIterCount;
					if (VerifyHashedPasswordV3(decodedHashedPassword, providedPassword, out embeddedIterCount))
					{
						// If this hasher was configured with a higher iteration count, change the entry now.
						return (embeddedIterCount < _iterCount) ? PasswordVerificationResult.SuccessRehashNeeded : PasswordVerificationResult.Success; } else { return PasswordVerificationResult.Failed; } default: return PasswordVerificationResult.Failed; // unknown format marker } } private static bool VerifyHashedPasswordV2(byte[] hashedPassword, string password) { const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits const int SaltSize = 128 / 8; // 128 bits // We know ahead of time the exact length of a valid hashed password payload. if (hashedPassword.Length != 1 + SaltSize + Pbkdf2SubkeyLength) { return false; // bad size } byte[] salt = new byte[SaltSize]; Buffer.BlockCopy(hashedPassword, 1, salt, 0, salt.Length); byte[] expectedSubkey = new byte[Pbkdf2SubkeyLength]; Buffer.BlockCopy(hashedPassword, 1 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); // Hash the incoming password and verify it byte[] actualSubkey = KeyDerivation.Pbkdf2(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength); return ByteArraysEqual(actualSubkey, expectedSubkey); } private static bool VerifyHashedPasswordV3(byte[] hashedPassword, string password, out int iterCount) { iterCount = default(int); try { // Read header information KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1); iterCount = (int)ReadNetworkByteOrder(hashedPassword, 5); int saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9); // Read the salt: must be >= 128 bits
				if (saltLength < 128 / 8) { return false; } byte[] salt = new byte[saltLength]; Buffer.BlockCopy(hashedPassword, 13, salt, 0, salt.Length); // Read the subkey (the rest of the payload): must be >= 128 bits
				int subkeyLength = hashedPassword.Length - 13 - salt.Length;
				if (subkeyLength < 128 / 8) { return false; } byte[] expectedSubkey = new byte[subkeyLength]; Buffer.BlockCopy(hashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); // Hash the incoming password and verify it byte[] actualSubkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, subkeyLength); return ByteArraysEqual(actualSubkey, expectedSubkey); } catch { // This should never occur except in the case of a malformed payload, where // we might go off the end of the array. Regardless, a malformed payload // implies verification failed. return false; } } private static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value) { buffer[offset + 0] = (byte)(value >> 24);
			buffer[offset + 1] = (byte)(value >> 16);
			buffer[offset + 2] = (byte)(value >> 8);
			buffer[offset + 3] = (byte)(value >> 0);
		}
	}
}

And then add this code to Startup.cs

services.AddScoped<IPasswordHasher<ApplicationUser>, MyPasswordHasher<ApplicationUser>>();

How to solve Exception : The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value with Entity Framework when calling SaveChanges

In order to fix this Issue you need to go on your EDMX file and View the Model.
So select the field interested and under it’s properties select “Computed” for the property StoreGeneratedPattern 


MS SQL How To Store a File into a blob field

If you need to store a file from your hard drive into a filed in MS Sql Server, you can run this code

UPDATE dbo.[Table] SET [Field]= (SELECT * FROM OPENROWSET(BULK N’C:fileName.PNG’,SINGLE_BLOB) rs)

How to use jQuery and Footable to make GridView responsive

Nowadays make a website compatible with desktop platforms and mobile is a must.
Making a responsive design is important to adapt the content of your website to the platform where it will be viewed.
To render the GridView control responsive we procdeed to hide some columns with Footable and jQuery plugins.
In order to do that, download Footable plugin
Now in your aspx page add the follow code:

Add a GridView control, this is the ASP.NET code for that:

Initialize footable plugin to the GridView control

Populate the GridView with data

The default header row for GridView is now generated, now we need to make it accessible

So we can proceed to define which colums will be hided in which devices

You can teel to Footable which columns to hide on which breakpoints, by specifying data-hide attributes on the table head columns

Enable / Disable controls in an Asp.Net Panel C#

If there are Panel controls in the page then a mere iteration with the Page.Controls collection will not reflect the controls which are placed inside the Panel, to Enable/Disable controls in the Panel, we need to iterate throught the Controls in the Panel.

Enable / Disable all controls in an Asp.Net Page in C#

In general for Asp.Net forms we maintain different modes like Create mode, View mode & Edit mode.
In the View mode we will disable all the controls to make sure that the user does not, modify any of the details.

If the form is small then we can manually set the .Enabled property to false for all the controls in the form to achieve the effect, however if we have a huge form with hundreds of controls then this becomes a tedious task to set the property for each of the controls, in these scenarios we can make use of the Page.Controls collection to loop throught all the controls in the page and Enable/Disable the controls.