Im a CS major and I just got done designing an ASP.net site, and for the site I needed a login authentication system... I didn't want to use SQLMembershipProvider as I really wanted to learn how to make one on my own... Anyways this is what I came up with, and I was wondering if anyone can give me some feedback, tips, or advice.
Thanks in Advance
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Security.Cryptography;
/// <summary>
/// Summary description for PwEncrypt
/// </summary>
public class PwEncrypt
{
public const int DefaultSaltSize = 5;
private static string CreateSalt()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buffer = new byte[DefaultSaltSize];
rng.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
public static string CreateHash(string password, out string salt)
{
salt = CreateSalt();
string saltAndPassword = String.Concat(password, salt);
string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1");
hashedPassword = string.Concat(hashedPassword, salt);
return hashedPassword;
}
public static string CreateHashAndGetSalt(string password, string salt)
{
string saltAndPassword = String.Concat(password, salt);
string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1");
hashedPassword = string.Concat(hashedPassword, salt);
return hashedPassword;
}
public static bool comparePassword(string insertedPassword, string incUserName, out string newEncryptedPassword, out string originalPassword)
{
databaseInteraction DBI = new databaseInteraction();
string actualPassword ="";
string salt = "";
DBI.getSaltandPassword(incUserName, out salt, out actualPassword);
string hashedIncPassword = PwEncrypt.CreateHashAndGetSalt(insertedPassword, salt);
// hashedIncPassword = string.Concat(hashedIncPassword, salt);
newEncryptedPassword = hashedIncPassword;
originalPassword = actualPassword;
if (newEncryptedPassword == originalPassword)
{
return true;
}
else { return false; }
}
Suppose we have a table for accounts like this
Then you can create some helper class that returns an account object
private static Account GetByName(string accountName, bool activatedOnly = false)
{
using (var context = new DBEntities())
{
return context.Accounts.FirstOrDefault(s =>
s.AccountName == accountName &&
s.IsApproved == activatedOnly);
}
}
public static Account Get(string accountName, string password)
{
var account = GetByName(accountName, true);
if (account != null)
if (!Cryptographer.IsValidPassword(password,
account.PasswordSalt,
account.PasswordKey))
return null;
return account;
}
I'm using EntityFramework
but it's not important here. The main idea is show that you don't need to get the whole list of accounts (especially if you have a big list of users).
My Cryptographer
class looks like
public class Cryptographer
{
private const int keyByteLength = 20;
public static void Encrypt(string password,
out byte[] salt,
out byte[] key)
{
using (var deriveBytes = new Rfc2898DeriveBytes(password,
keyByteLength))
{
salt = deriveBytes.Salt;
key = deriveBytes.GetBytes(keyByteLength);
}
}
public static bool IsValidPassword(string password,
byte[] salt,
byte[] key)
{
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
byte[] newKey = deriveBytes.GetBytes(keyByteLength);
return newKey.SequenceEqual(key);
}
}
}
Of cource you can implement the algorithm of your own.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With