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.
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 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
}
I'm making a program in C# which includes userdata like Username and Passowrd. I have created a Database in SQL Server 2008 and now I want to encrypt Passowrd in my Database because I wouldn't like to see their passwords.
I hope you will help me about this.
DB name: db_Biblioteka
Table: tbl_Users
Columns: ID, Name, Username, Password
Thank you.
If You want to Encrypt a Column of Data, so follow the link.
But for more security on sniffing you need to encode your password on passing them to SQL Server.
So you can use many functions in your code to do that; And the easiest way is:
public static string GetHashText(string txt)
{
byte[] tmpSource = new UTF8Encoding().GetBytes(txt);
return Convert.ToBase64String(tmpSource);
}
public static string DecodeText(string txt)
{
byte[] tmpData = Convert.FromBase64String(txt);
string tmp = new UTF8Encoding().GetString(tmpData);
return tmp;
}
But the better way is Hashing (#simon). And you can use this Hash Code
In proxy.exe I am creating a secure string the following way:
public SecureString GetSecureEncryptionKey()
{
string strPassword = "8charPwd";
SecureString secureStr = new SecureString();
if (strPassword.Length > 0)
{
foreach (var c in strPassword.ToCharArray()) secureStr.AppendChar(c);
}
return secureStr;
}
Then in main.exe I am decrypting it using this function:
public string convertToUNSecureString(SecureString secstrPassword)
{
IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secstrPassword);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}
The issue is that the returned string is empty, unless I encrypt the initial string within main.exe, then the returned decrypted string is indeed "8charPwd". Why is this happening? Is SecureString encryption bound to the executable?
The purpose of SecureString is to keep strings safety inside your application memory(keep the string secure in RAM)
SecureString object is not a serialize-able.
You cannot transfer an instance between applications.
SecureString encrypt the string by using RtlEncryptMemory (WINAPI) with the flag:"0" (only the same process can decrypt the content). RtlEncryptMemory API
if you don't want to expose the password(at any time) in the RAM, you can create a simple obfuscation(or encryption) logic, and then transfer the content.
Edit:
I found 2 old questions that might be helpful for you:
When would I need a SecureString in .NET?
Wcf-Authentication and Logging
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