Reputation: 1068
i'm doing a test how hash and salt passwords. Well , i can add hash and salt password to the Database but i got stuck to store passwords from database. i have a simple Database :
Table
_______
ProvaHS
--------
(PK) LoginID int
UserName nvarchar(50)
Password nvarchar(50)
Salt nvarchar(50)
So i create a form to add new record to the database with this code:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
#region SALT
public static class PasswordCrypto
{
private static SHA1CryptoServiceProvider Hasher = new SHA1CryptoServiceProvider();
//Private Hasher As New MD5CryptoServiceProvider()
static internal string GetSalt(int saltSize)
{
byte[] buffer = new byte[saltSize + 1];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
static internal string HashEncryptString(string s)
{
byte[] clearBytes = Encoding.UTF8.GetBytes(s);
byte[] hashedBytes = Hasher.ComputeHash(clearBytes);
return Convert.ToBase64String(hashedBytes);
}
static internal string HashEncryptStringWithSalt(string s, string salt)
{
return HashEncryptString(salt + s);
}
}
#endregion
private void GetSalt()
{
this.textBoxSalt.Text = PasswordCrypto.GetSalt(16);
}
private void GetSaltHash()
{
// It's how i salt and hash the password before to save it to the Database
this.textBoxPassword.Text = PasswordCrypto.HashEncryptStringWithSalt(this.textBoxClear.Text, this.textBoxSalt.Text);
}
private void GetHash()
{
//Demo purposes -- this is an unsalted hash
this.textBoxClear.Text = PasswordCrypto.HashEncryptString(this.textBoxPassword.Text);
}
private void Add(object sender, RoutedEventArgs e)
{
DataClasses1DataContext dc = new DataClasses1DataContext();
try
{
if (textBoxUserName.Text.Length > 0)
{
ProvaH tab = new ProvaH();
tab.UserName = textBoxUserName.Text;
tab.Password = textBoxPassword.Text;
tab.Salt = textBoxSalt.Text;
dc.ProvaHs.InsertOnSubmit(tab);
dc.SubmitChanges();
}
}
catch (Exception ex)
{
MessageBox.Show("Error!!!");
}
}
private void HashButton(object sender, RoutedEventArgs e)
{
GetHash();
}
private void SaltButton(object sender, RoutedEventArgs e)
{
GetSalt();
}
private void HashSaltButton(object sender, RoutedEventArgs e)
{
GetSaltHash();
}
private void Close_W(object sender, RoutedEventArgs e)
{
this.Close();
}
}
}
Now i'm testing how store password from the database and here i got a trouble...
public partial class Login : Window
{
public Login()
{
InitializeComponent();
}
#region SALT
public static class PasswordCrypto
{
private static SHA1CryptoServiceProvider Hasher = new SHA1CryptoServiceProvider();
//Private Hasher As New MD5CryptoServiceProvider()
static internal string GetSalt(int saltSize)
{
byte[] buffer = new byte[saltSize + 1];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
static internal string HashEncryptString(string s)
{
byte[] clearBytes = Encoding.UTF8.GetBytes(s);
byte[] hashedBytes = Hasher.ComputeHash(clearBytes);
return Convert.ToBase64String(hashedBytes);
}
static internal string HashEncryptStringWithSalt(string s, string salt)
{
return HashEncryptString(salt + s);
}
}
#endregion
private void closs(object sender, RoutedEventArgs e)
{
this.Close();
}
public bool ValidateApplicationUser(string userName, string password)
{
bool OK = false;
DataClasses1DataContext dc = new DataClasses1DataContext();
object saltValue = from c in dc.ProvaHs where c.UserName == userName select c.Salt;
if (!(saltValue == System.DBNull.Value))
{
password = PasswordCrypto.HashEncryptStringWithSalt(passwordTextBox.Password, saltValue.ToString());
}
var query = from c in dc.ProvaHs where c.UserName == userName && c.Password == password select new { c.LoginID, c.UserName, c.Password };
if (query.Count() != 0)
{
return true;
}
return false;
}
private void Confirm(object sender, RoutedEventArgs e)
{
bool authenticated = true;
if (usernameTextBox.Text != "" && passwordTextBox.Password.ToString() != "")
{
authenticated = ValidateApplicationUser(usernameTextBox.Text, passwordTextBox.Password.ToString());
}
if (!authenticated)
{
MessageBox.Show("Invalid login. Try again.");
}
else
{
MessageBox.Show("Aaaaahhhh.JOB DONE!!!!....");
}
}
}
when i debug the application i receive always an error at this code line : if (query.Count() != 0) in "query" = Empty :"Enumeration yielded no results" Do you have any suggest how work out this error and store password from database in my case? Thanks
Upvotes: 2
Views: 2007
Reputation: 421960
Try:
public bool ValidateApplicationUser(string userName, string password)
{
DataClasses1DataContext dc = new DataClasses1DataContext();
var saltValue = dc.ProvaHs.Where(c => c.UserName == userName)
.Select(c => c.Salt)
.SingleOrDefault();
if (saltValue == null) return false;
password = PasswordCrypto.HashEncryptStringWithSalt(passwordTextBox.Password, saltValue.ToString());
return dc.ProvaHs.Any(c => c.UserName == userName && c.Password == password);
}
Upvotes: 2
Reputation:
Don't use SHA1. Use SHA256, real random salt, and lots (ie. 8000) of SHA256 iterations. Because SHA is designed for speed, but that means that dictionary attack is fast. There are also better ways, like scrypt algorithm. Or SRP protocol.
Upvotes: 2
Reputation: 65426
(Not strictly answering your question but I'll add it anyway)
Don't you want to just hex encode (not base64) the output?
public static string SHA256Hash(string Data)
{
SHA256 sha = new SHA256Managed();
byte[] hash = sha.ComputeHash( Encoding.ASCII.GetBytes(Data) );
StringBuilder stringBuilder = new StringBuilder();
foreach( byte b in hash )
{
stringBuilder.AppendFormat("{0:x2}", b);
}
return stringBuilder.ToString();
}
(That's SHA-2, just swap SHA256 for SHA1 and SHA256Managed with SHA1Managed).
Other snippet implementations here
Upvotes: 1