I use the following code to Encrypt and protect the password and I add salt to it, but when I try to validate it when the user login they don't match, I don't know why.
public static class Encrypt
{
public static string saltValue { get; set; }
public static string hashValue { get; set; }
public static void SecurePassword(string password)
{
// Create a truly random salt using RNGCryptoServiceProvider.
RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
byte[] salt = new byte[32];
csprng.GetBytes(salt);
// Get the salt value
saltValue = Convert.ToBase64String(salt);
// Salt the password
byte[] saltedPassword = Encoding.UTF8.GetBytes(saltValue + password);
// Hash the salted password using SHA256
SHA512Managed hashstring = new SHA512Managed();
byte[] hash = hashstring.ComputeHash(saltedPassword);
// Save both the salt and the hash in the user's database record.
saltValue = Convert.ToBase64String(salt);
hashValue = Convert.ToBase64String(hash);
}
public static void ValidateLogin(string password, string username)
{
// Read the user's salt value from the database
string saltValueFromDB = saltValue;
// Read the user's hash value from the database
string hashValueFromDB = hashValue;
byte[] saltedPassword = Encoding.UTF8.GetBytes(saltValueFromDB + password);
// Hash the salted password using SHA256
SHA512Managed hashstring = new SHA512Managed();
byte[] hash = hashstring.ComputeHash(saltedPassword);
string hashToCompare = Convert.ToBase64String(hash);
if (hashValueFromDB.Equals(hashToCompare))
Console.WriteLine("User Validated.");
else
Console.WriteLine("Login credentials incorrect. User not validated.");
}
}
Please advise. Thank you in advance
Changed your code a bit but this works:
public class Encrypt
{
public HashedCredential SecurePassword(string password, string salt = "")
{
var saltValue = salt;
if (string.IsNullOrEmpty(salt))
{
saltValue = GenertateSalt();
}
// Salt the password
byte[] saltedPassword = Encoding.UTF8.GetBytes(saltValue + password);
// Hash the salted password using SHA256
SHA512Managed hashstring = new SHA512Managed();
byte[] hash = hashstring.ComputeHash(saltedPassword);
return new HashedCredential(saltValue, Convert.ToBase64String(hash));
}
private string GenertateSalt()
{
RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
byte[] salt = new byte[32];
csprng.GetBytes(salt);
return Convert.ToBase64String(salt);
}
}
public class HashedCredential
{
public string SaltValue { get; }
public string HashValue { get; }
public HashedCredential(string saltValue, string hashValue)
{
SaltValue = saltValue;
HashValue = hashValue;
}
}
[TestMethod]
public void GenerateSalt()
{
// Arrange
var sut = new Encrypt();
// Act
var result = sut.SecurePassword("Test");
var resultB = sut.SecurePassword("Test", result.SaltValue);
// Assert
Console.WriteLine($"resultA:'{result.HashValue}'");
Console.WriteLine($"resultB:'{resultB.HashValue}'");
Assert.AreEqual(result.HashValue, resultB.HashValue);
}
Related
I have a field in my database which is binary(32) for storing SHA-256 passwords. Since MSSQL store the hash in upper case and with 0x prefix, I've done this:
public static string getHashSha256(string text)
{
byte[] bytes = Encoding.UTF8.GetBytes(text);
SHA256Managed hashstring = new SHA256Managed();
byte[] hash = hashstring.ComputeHash(bytes);
string hashString = string.Empty;
foreach (byte x in hash)
{
hashString += String.Format("{0:x2}", x);
}
return "0x" + hashString.ToUpper();
}
Is this acceptable or there is a more appropriate way to do this?
public static string ConvertToHash(string dataToComputeHash)
{
var hash = "";
try
{
var keyByte = encoding.GetBytes(key);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
hmacsha256.ComputeHash(encoding.GetBytes(dataToComputeHash));
hash = ByteToString(hmacsha256.Hash);
}
}
catch (Exception ex)
{
}
return hash;
}
My C# console app actually prompts the user for a password and process the password as a string:
Console.Write("Please enter your password: ");
string password = GetPassword();
var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);
Is there a way to modify the code to use a secure password (reducing the risk of having the password be exposed throught a memory dump)?
I would like something like:
Console.Write("Please enter your password: ");
SecureString password = GetSecurePassword();
securePassword = GetSecurePassword();
var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);
password.Dispose();
Below a complete sample the compiles under Visual Studio 2015:
using System;
using System.Security;
using System.Security.Cryptography;
using System.Text;
namespace PasswordTest
{
internal class Program
{
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())
{
return sha256.ComputeHash(Combine(toBeHashed, salt));
}
}
private static string GetPassword()
{
// skip here the code that prompts the password
// to make simple test that just return a password
return "mypa55w0rd";
}
// Here the code that would normally be used to prompt for a password
// and return a SecureString
public static SecureString GetSecurePassword()
{
var password = new SecureString();
// get the first character of the password
var nextKey = Console.ReadKey(true);
while (nextKey.Key != ConsoleKey.Enter)
{
if (nextKey.Key == ConsoleKey.Backspace)
{
if (password.Length > 0)
{
password.RemoveAt(password.Length - 1);
// erase the last * as well
Console.Write(nextKey.KeyChar);
Console.Write(" ");
Console.Write(nextKey.KeyChar);
}
}
else
{
password.AppendChar(nextKey.KeyChar);
Console.Write("*");
}
nextKey = Console.ReadKey(true);
}
Console.WriteLine();
// lock the password down
password.MakeReadOnly();
return password;
}
private static void Main(string[] args)
{
// Generate the salt
var salt = GenerateSalt();
// Hash a password stored in a string variable
// Issue: can be exposed through a memory dump
var password = GetPassword();
var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);
// How to hash a password stored in a securestring so that the code could become
// something like:
/*
Console.Write("Please enter your password: ");
SecureString password = GetSecurePassword();
var hashedPassword = HashPasswordWithSalt(Encoding.UTF8.GetBytes(password), salt);
password.Dispose();
*/
Console.WriteLine("Hashed Password = " + Convert.ToBase64String(hashedPassword));
Console.ReadLine();
}
}
}
I have the following code in .net framework.
public string GetHashedPassword(string password, string salt)
{
byte[] saltArray = Convert.FromBase64String(salt);
byte[] passArray = Convert.FromBase64String(password);
byte[] salted = new byte[saltArray.Length + passArray.Length];
byte[] hashed = null;
saltArray.CopyTo(salted, 0);
passArray.CopyTo(salted, saltArray.Length);
using (var hash = new SHA256Managed())
{
hashed = hash.ComputeHash(salted);
}
return Convert.ToBase64String(hashed);
}
I'm trying to create an equivalent in .net core for a UWP application. Here's what I have so far.
public string GetHashedPassword(string password, string salt)
{
IBuffer input = CryptographicBuffer.ConvertStringToBinary(password + salt, BinaryStringEncoding.Utf8);
var hashAlgorithm = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256);
var hash = hashAlgorithm.HashData(input);
//return CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, hash);
}
The last line, converting the buffer back to a string doesn't work. I get this exception:
No mapping for the Unicode character exists in the target multi-byte code page.
How can I convert the buffer back into a string?
I am assuming, that you want to get the hashed password in a base64-format, because you did that in your .net example.
To get this, change:
CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, hash);
to:
CryptographicBuffer.EncodeToBase64String(hash);
So the complete method looks like this:
public string GetHashedPassword(string password, string salt)
{
IBuffer input = CryptographicBuffer.ConvertStringToBinary(password + salt, BinaryStringEncoding.Utf8);
var hashAlgorithm = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256);
var hash = hashAlgorithm.HashData(input);
return CryptographicBuffer.EncodeToBase64String(hash);
}
I have salt and encrypted password in my db. and want to create a login function. I created a login function but it always returns false.
My function for conversion is here, is it right or not?
public static String HashPassword(String password, String salt)
{
var combinedPassword = String.Concat(password, salt);
var sha256 = new SHA256Managed();
var bytes = UTF8Encoding.UTF8.GetBytes(combinedPassword);
var hash = sha256.ComputeHash(bytes);
return Convert.ToBase64String(hash);
}
public static Boolean ValidatePassword(String enteredPassword, String storedHash, String storedSalt)
{
// Consider this function as an internal function where parameters like
// storedHash and storedSalt are read from the database and then passed.
var hash = HashPassword(enteredPassword, storedSalt);
return String.Equals(storedHash, hash);
}
I have a datacontract and in my service I am trying to hash/salt the password datamember:
public void AddStudent(Student student)
{
student.StudentID = (++eCount).ToString();
byte[] passwordHash = Hash(student.Password, _passwordSalt); //invalid expression? _passwordSalt?
student.TimeAdded = DateTime.Now;
students.Add(student);
}
Can anyone help?
Try to replace the _passwordSalt with this function GenerateSalt() from one of my projects:
protected RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
public byte[] GenerateSalt() {
byte[] salt = new byte[10];
random.GetNonZeroBytes(salt);
return salt;
}
By the way you have to save this generated salt. You need the same salt every time to check the password.