I have designed a signup page in C# and all users have to enter their password then the program will hash the password before saving it on a database with a SHA512 hashing method.
Now, I want to verify entered password on the login page with the saved password on database.
Below code is the method that I used to hash the passwords.
Now how can I verify entered password on login page???
byte[] infos = System.Text.Encoding.ASCII.GetBytes(txtPassword.Text);
infos = new System.Security.Cryptography.SHA512Managed().ComputeHash(infos);
String hash = System.Text.Encoding.ASCII.GetString(infos);
The Sha* hash family is not appropriate to store passwords safely, because they are way too fast and can be brute-forced too easily. You should switch to a dedicated password-hash function like BCrypt, Argon2 or PBKDF2, which apply a salt and use key-stretching.
A good BCrypt library is available via Nuget: https://www.nuget.org/packages/BCrypt.Net-Next/
Its usage is very straight foreward:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
string hashToStoreInDb = BCrypt.HashPassword(password);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from existingHashFromDb.
bool isPasswordCorrect = BCrypt.Verify(password, existingHashFromDb);
What about writing code like this:
using System;
using System.Text;
using System.Security.Cryptography;
using CodeShare.Cryptography;
namespace CodeShare.Cryptography
{
public static class SHA
{
public static string GenerateSHA512String(string inputString)
{
SHA512 sha512 = SHA512Managed.Create();
byte[] bytes = Encoding.UTF8.GetBytes(inputString);
byte[] hash = sha512.ComputeHash(bytes);
return GetStringFromHash(hash);
}
private static string GetStringFromHash(byte[] hash)
{
StringBuilder result = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
result.Append(hash[i].ToString("X2"));
}
return result.ToString();
}
}
}
Example:
public void UsageExample()
{
Console.WriteLine(SHA.GenerateSHA512String("abc"));
//returns DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F
}
Related
I am making some kind of thinking problem.
I created a Register/Login system for my Xamarin.Forms app. Now when I register an account, I hash the password and add random salt, but I do the same for the login. The problem is that I need to get the exact same salt for the password that I used on the register.
Here are the 2 functions to create salt and hasing:
public String CreateSalt(int size)
{
var rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
var buff = new byte[size];
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}
public String GenerateSHA256Hash(String input, String salt)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(input + salt);
System.Security.Cryptography.SHA256Managed sha256hashstring =
new System.Security.Cryptography.SHA256Managed();
byte[] hash = sha256hashstring.ComputeHash(bytes);
return Convert.ToBase64String(hash);
}
And here is the code I use when registering and logging in:
async void btnLogInClicked(object sender, EventArgs args)
{
string username = txtUsername.Text;
string password = txtPassword.Text;
string salt = CreateSalt(16);
string HashedPassword = GenerateSHA256Hash(password, salt);
HashedPassword = HashedPassword.Replace('+', '-');
HashedPassword = HashedPassword.Replace('/', '_');
User user = new User
{
Username = username,
Password = HashedPassword
};
var result = await App.RestService.Login(user);
if (result != null)
{
App.Current.MainPage = new SideMenuItems();
}
}
How can I do that and still use a random salt for every new generated password?
It seems like every year I have to re-learn how to properly hash passwords. I just did that, and I'll do my best to explain here.
Your problem is that you are generating a new salt every time you call CreateSalt, when user logs in. As mentioned in the comments, you'll want generate the salt and hash once during registration, and save them to a database.
Then, when a user logs in, you can retrieve the salt from the database, and use it along with the password entered by the user to generate the hash. Finally, you'll compare the newly generated hash with the hash saved in the database, to see if the password is correct.
I'd suggest using a slow hash algorithm and not SHA256 for generating the hash. PBKDF2 would be a good option, and comes built-in with .NET as the Rfc2898DeriveBytes class. Another popular option is bcrypt. It necessitates a third-party library in .NET, but I find it to be easy to implement (at least with Node). More general info on password hashing algorithms here.
One last thing to consider is the number of iterations the algorithm uses. The Rfc2898DeriveBytes class has a few constructors, one of which sets a default of 1000 iterations, which should be sufficient. The iterations (or "cost") slows the hash function and helps thwart attacks.
I'm making a Windows application, which you need to log into first.
The account details consist of username and password, and they need to be saved locally.
It's just a matter of security, so other people using the same computer can't see everyone's personal data.
What is the best/most secure way to save this data?
I don't want to use a database, so I tried some things with Resource files.
But since I'm kind of new with this, I'm not entirely sure of what I'm doing and where I should be looking for a solution.
If you are just going to verify/validate the entered user name and password, use the Rfc2898DerivedBytes class (also known as Password Based Key Derivation Function 2 or PBKDF2). This is more secure than using encryption like Triple DES or AES because there is no practical way to go from the result of RFC2898DerivedBytes back to the password. You can only go from a password to the result. See Is it ok to use SHA1 hash of password as a salt when deriving encryption key and IV from password string? for an example and discussion for .Net or String encrypt / decrypt with password c# Metro Style for WinRT/Metro.
If you are storing the password for reuse, such as supplying it to a third party, use the Windows Data Protection API (DPAPI). This uses operating system generated and protected keys and the Triple DES encryption algorithm to encrypt and decrypt information. This means your application does not have to worry about generating and protecting the encryption keys, a major concern when using cryptography.
In C#, use the System.Security.Cryptography.ProtectedData class. For example, to encrypt a piece of data, use ProtectedData.Protect():
// Data to protect. Convert a string to a byte[] using Encoding.UTF8.GetBytes().
byte[] plaintext;
// Generate additional entropy (will be used as the Initialization vector)
byte[] entropy = new byte[20];
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(entropy);
}
byte[] ciphertext = ProtectedData.Protect(plaintext, entropy,
DataProtectionScope.CurrentUser);
Store the entropy and ciphertext securely, such as in a file or registry key with permissions set so only the current user can read it. To get access to the original data, use ProtectedData.Unprotect():
byte[] plaintext= ProtectedData.Unprotect(ciphertext, entropy,
DataProtectionScope.CurrentUser);
Note that there are additional security considerations. For example, avoid storing secrets like passwords as a string. Strings are immutable, being they cannot be notified in memory so someone looking at the application's memory or a memory dump may see the password. Use SecureString or a byte[] instead and remember to dispose or zero them as soon as the password is no longer needed.
I have used this before and I think in order to make sure credential persist and in a best secure way is
you can write them to the app config file using the ConfigurationManager class
securing the password using the SecureString class
then encrypting it using tools in the Cryptography namespace.
This link will be of great help I hope : Click here
I wanted to encrypt and decrypt the string as a readable string.
Here is a very simple quick example in C# Visual Studio 2019 WinForms based on the answer from #Pradip.
Right click project > properties > settings > Create a username and password setting.
Now you can leverage those settings you just created. Here I save the username and password but only encrypt the password in it's respectable value field in the user.config file.
Example of the encrypted string in the user.config file.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<secure_password_store.Properties.Settings>
<setting name="username" serializeAs="String">
<value>admin</value>
</setting>
<setting name="password" serializeAs="String">
<value>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAQpgaPYIUq064U3o6xXkQOQAAAAACAAAAAAAQZgAAAAEAACAAAABlQQ8OcONYBr9qUhH7NeKF8bZB6uCJa5uKhk97NdH93AAAAAAOgAAAAAIAACAAAAC7yQicDYV5DiNp0fHXVEDZ7IhOXOrsRUbcY0ziYYTlKSAAAACVDQ+ICHWooDDaUywJeUOV9sRg5c8q6/vizdq8WtPVbkAAAADciZskoSw3g6N9EpX/8FOv+FeExZFxsm03i8vYdDHUVmJvX33K03rqiYF2qzpYCaldQnRxFH9wH2ZEHeSRPeiG</value>
</setting>
</secure_password_store.Properties.Settings>
</userSettings>
</configuration>
Full Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace secure_password_store
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Exit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void Login_Click(object sender, EventArgs e)
{
if (checkBox1.Checked == true)
{
Properties.Settings.Default.username = textBox1.Text;
Properties.Settings.Default.password = EncryptString(ToSecureString(textBox2.Text));
Properties.Settings.Default.Save();
}
else if (checkBox1.Checked == false)
{
Properties.Settings.Default.username = "";
Properties.Settings.Default.password = "";
Properties.Settings.Default.Save();
}
MessageBox.Show("{\"data\": \"some data\"}","Login Message Alert",MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void DecryptString_Click(object sender, EventArgs e)
{
SecureString password = DecryptString(Properties.Settings.Default.password);
string readable = ToInsecureString(password);
textBox4.AppendText(readable + Environment.NewLine);
}
private void Form_Load(object sender, EventArgs e)
{
//textBox1.Text = "UserName";
//textBox2.Text = "Password";
if (Properties.Settings.Default.username != string.Empty)
{
textBox1.Text = Properties.Settings.Default.username;
checkBox1.Checked = true;
SecureString password = DecryptString(Properties.Settings.Default.password);
string readable = ToInsecureString(password);
textBox2.Text = readable;
}
groupBox1.Select();
}
static byte[] entropy = Encoding.Unicode.GetBytes("SaLtY bOy 6970 ePiC");
public static string EncryptString(SecureString input)
{
byte[] encryptedData = ProtectedData.Protect(Encoding.Unicode.GetBytes(ToInsecureString(input)),entropy,DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encryptedData);
}
public static SecureString DecryptString(string encryptedData)
{
try
{
byte[] decryptedData = ProtectedData.Unprotect(Convert.FromBase64String(encryptedData),entropy,DataProtectionScope.CurrentUser);
return ToSecureString(Encoding.Unicode.GetString(decryptedData));
}
catch
{
return new SecureString();
}
}
public static SecureString ToSecureString(string input)
{
SecureString secure = new SecureString();
foreach (char c in input)
{
secure.AppendChar(c);
}
secure.MakeReadOnly();
return secure;
}
public static string ToInsecureString(SecureString input)
{
string returnValue = string.Empty;
IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
try
{
returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
return returnValue;
}
private void EncryptString_Click(object sender, EventArgs e)
{
Properties.Settings.Default.password = EncryptString(ToSecureString(textBox2.Text));
textBox3.AppendText(Properties.Settings.Default.password.ToString() + Environment.NewLine);
}
}
}
DPAPI is just for this purpose. Use DPAPI to encrypt the password the first time the user enters is, store it in a secure location (User's registry, User's application data directory, are some choices). Whenever the app is launched, check the location to see if your key exists, if it does use DPAPI to decrypt it and allow access, otherwise deny it.
This only works on Windows, so if you are planning to use dotnet core cross-platform, you'll have to look elsewhere. See https://github.com/dotnet/corefx/blob/master/Documentation/architecture/cross-platform-cryptography.md
For simple scenarios can also use Windows Credential Management API using C# wrapper CredentialManagement. It gives single place to store/retrieve passwords, easy to change.
https://stackoverflow.com/a/32550674/1129978
I'm making the equivalent java code for the code below. But I can make something that returns the same result for encodedString. What Java class can I use for achieve the same result?
//Set the Hash method to SHA1
HMAC hash;
switch (validation)
{
case MachineKeyValidation.MD5:
hash = new HMACMD5();
break;
case MachineKeyValidation.SHA1:
default:
hash = new HMACSHA1();
break;
}
//Get the hash validation key as an array of bytes
hash.Key = HexToByte(validationKey);
//Encode the password based on the hash key and
//converts the encrypted value into a string
encodedString = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
Thanks in advance!
:)
I found a solution for the translation code.
There was two main problem. When a request a HMACSHA1 I'm not talking about a SHA1 algorithm, but a HmacSHA1. And there is a difference between the encoding from Java and C#. I was using the correct key, and the correct algorithm, but the encoding was differente.
SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
// The big problem is difference between C# and Java encoding
byte[] rawHmac = mac.doFinal(data.getBytes("UTF-16LE"));
result = new String(Base64.encode(rawHmac));
See this question about computing hash functions in Java.
And look at the javadoc for java.security.MessageDigest.getInstance(String algorithm).
Edited to add:
Try running the following app to see what providers you have registered.
import java.security.Provider;
import java.security.Security;
public class SecurityTest {
public static void main(String[] args) {
Provider[] providers = Security.getProviders();
for (Provider p : providers) {
System.out.println(p.toString());
}
}
}
You should have at least a few Sun providers listed. If not, you may need to download some security libraries.
I have a program that uses System.DirectoryServices.AccountManagement.PrincipalContext to verify that the information a user entered in a setup screen is a valid user on the domain (the computer itself is not on the domain) and do some operations on the users of the domain. The issue is I do not want the user to need to enter his or her password every time they run the program so I want to save it, but I do not feel comfortable storing the password as plain-text in their app.config file. PrincipalContext needs a plain-text password so I can not do a salted hash as everyone recommends for password storing.
This is what I did
const byte[] mySalt = //It's a secret to everybody.
[global::System.Configuration.UserScopedSettingAttribute()]
public global::System.Net.NetworkCredential ServerLogin
{
get
{
var tmp = ((global::System.Net.NetworkCredential)(this["ServerLogin"]));
if(tmp != null)
tmp.Password = new System.Text.ASCIIEncoding().GetString(ProtectedData.Unprotect(Convert.FromBase64String(tmp.Password), mySalt, DataProtectionScope.CurrentUser));
return tmp;
}
set
{
var tmp = value;
tmp.Password = Convert.ToBase64String(ProtectedData.Protect(new System.Text.ASCIIEncoding().GetBytes(tmp.Password), mySalt, DataProtectionScope.CurrentUser));
this["ServerLogin"] = value;
}
}
Was this the right thing to do or is there a better way?
EDIT --
Here is a updated version based on everyone's suggestions
private MD5 md5 = MD5.Create();
[global::System.Configuration.UserScopedSettingAttribute()]
public global::System.Net.NetworkCredential ServerLogin
{
get
{
var tmp = ((global::System.Net.NetworkCredential)(this["ServerLogin"]));
if(tmp != null)
tmp.Password = System.Text.Encoding.UTF8.GetString(ProtectedData.Unprotect(Convert.FromBase64String(tmp.Password), md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmp.UserName.ToUpper())), DataProtectionScope.CurrentUser));
return tmp;
}
set
{
var tmp = value;
tmp.Password = Convert.ToBase64String(ProtectedData.Protect(System.Text.Encoding.UTF8.GetBytes(tmp.Password), md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmp.UserName.ToUpper())), DataProtectionScope.CurrentUser));
this["ServerLogin"] = tmp;
}
}
For the salt, I'd do a transformation on the username (hash it) rather than share the same salt for everyone.
For something like this, I'd also look for a way to keep the existing session alive longer rather than saving the password to create new sessions.
Instead of writing new System.Text.ASCIIEncoding(), you should write System.Text.Encoding.ASCII.
Also, I recommend using UTF8 instead.
Other than that, your code looks pretty good.
I like the JoelCoehoorn approach.
Use a value unique for the user machine as the password salt.
So it will be different in each deplyment ; ).
UPDATE: See this thread for ideas: How-To-Get-Unique-Machine-Signature
I have a desktop application with a remote interface. The access to the remote interface is secured by a username and password.
What would be the best way to save these password securely, preferably in the registry?
If you do need to store an unhashed password, look at using the ProtectedData class. This makes use of the Data Protection API (DPAPI) which is the best way of securing data on Windows.
Here's a little class that wraps ProtectedData and provides two extension methods on String to Encrypt and Decrypt data:
public static class DataProtectionApiWrapper
{
/// <summary>
/// Specifies the data protection scope of the DPAPI.
/// </summary>
private const DataProtectionScope Scope = DataProtectionScope.CurrentUser;
public static string Encrypt(this string text)
{
if (text == null)
{
throw new ArgumentNullException("text");
}
//encrypt data
var data = Encoding.Unicode.GetBytes(text);
byte[] encrypted = ProtectedData.Protect(data, null, Scope);
//return as base64 string
return Convert.ToBase64String(encrypted);
}
public static string Decrypt(this string cipher)
{
if (cipher == null)
{
throw new ArgumentNullException("cipher");
}
//parse base64 string
byte[] data = Convert.FromBase64String(cipher);
//decrypt data
byte[] decrypted = ProtectedData.Unprotect(data, null, Scope);
return Encoding.Unicode.GetString(decrypted);
}
}
You would need to save the hashed password (be it in the registry or somewhere else). Then when the user enters their password you check the hashed version of what they enter with the hashed version as stored. If these match then the passwords match and you can let the user in.
This way you're not storing the password in plain text for anyone (including yourself) to get at and gain access as someone else.
As to which hash algorithm to use - I don't know. There are plenty to choose from, so I'm reluctant to recommend one blind. I'd suggest you find several and evaluate them. CSharpFriends has an article which looks like it might be a good starting point.