This question already has answers here:
Hashing a SecureString in .NET
(4 answers)
Closed 7 years ago.
I believe I'm misunderstanding a fundamental part of SecureString. I understand that string's are immutable and there a password or sensitive data is found as clear text on the heap.
What I'm struggling to understand is, how do I use SecureString in a client application which needs to verify the hashed password in a database?
Here's my context:
I'm using a WPF client application.
I have a local SQL database (on the client's machine)
The passwords are hashed and stored in the database.
The user tries logging into to my WPF application
The PasswordBox control stores the password in a SecureString via the SecurePassword property.
Now what? How do I hash a SecureString WITHOUT casting it back into string first?
All the advise I've received so far is to write extension methods converting SecureString to String, hash it and then send it to db to verify. But this defeats the whole exercise!
Must I just accept that SecureString is useless in my mentioned context and use plain string?
SecureString is represented as a byte[] you could encode the bytes e.g. with bitconverter and save the result.
Furthermore SecureString is a encryption not a hash as it can be decrypted. (see below)
SecureString mainly meant to store sensitive data in memory.
If you have a service / website, this is not as important as the values which are stored in the database. These should never be plaintext, and imo not be decryptable by your or any administrator
Also i'm not sure wether another server could decrypt the strings, so you may have a problem when you change the server or have somekind of cluster scenario.
Especially for passwords would prefer using hash algorithms (e.g. SHA256) .
These can't be uncrypted (like the sum of the digits).
In the use case of a login funtionality you would encrypt the userinput and compare the hashs the user and and the one thats in the database. (details se below)
I would also suggest to add a dynamic criteria like the userid to the hashinput so that 2 user with same password would have different hashes.
With this strategy you don't have a risc with userpasswords and therefore if data gets leaked it wouldn't be a problem at this point.
Here an short overview of using hash algorithms
So ( if the securestring is given) first decrypt the SecureString
String SecureStringToString(SecureString value){
IntPtr valuePtr = IntPtr.Zero;
try{
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
return Marshal.PtrToStringUni(valuePtr);
}
finally{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
Than hash it for example with SHA256. From this post
using (SHA256 hash = SHA256Managed.Create()) {
Encoding enc = Encoding.UTF8;
//the user id is the salt.
//So 2 users with same password have different hashes.
//For example if someone knows his own hash he can't see who has same password
string input = userInput+userId;
Byte[] result = hash.ComputeHash(enc.GetBytes(input));
foreach (Byte b in result)
Sb.Append(b.ToString("x2")); //You could also use other encodingslike BASE64
}
Store this hashsum. Depending on your encoding it may looke like this:
ac5b208b4d35ec79fa7c14b7a31f9c80392cdab2bc58bc5b79bcfe64b044d899
in your database.
If the user signs on then create the hash from his input and compare it with the hash in the database. if they are equal then the password is correct.
Therefore you never need to have the plaintext user password anywhere stored.
If the client makes the hash then it should absolut should no where exist as a plaintext (except the textbox if it doesnt support the securestring)
PS: this is only one option. But the main thing is to never store plaintextpasswords anywhere. For best never know them and have no change to get them decrypted.
Another strategy would be to use asymmetric encryptions like RSA but this can become more complex. If you need help with that i would recommend a dedicated post on this.
Depending on your requirements and envionment most of the time hashsums should be an acceptable solution. (But thats not an legal advice as i'm not a lawyer)
Related
At the time of registering
string crypt = CryptSharp.Crypter.Sha512.GenerateSalt();
crypt = txtspss.Text.Trim();
crypt = CryptSharp.Crypter.Sha512.Crypt(txtspss.Text, crypt);
At the time of login..
string cpass=dr["strUPass"].ToString();
bool matches = Crypter.CheckPassword(pass,cpass);
if (matches)
{....}
A salt is supposed to be unique. By doing this, someone trying to crack passwords has to do a separate compuation for each password, instead of being able to generate hashes for a million passwords and then check them against the entire stolen password database.
CryptSharp encodes passwords in Modular Crypt Format. Here's the design. Suppose the algorithm is A, the salt is B, and the hash is C. GenerateSalt writes AB, Crypt reads AB and generates C, returning ABC. Underneath, you see, CheckPassword is more or less equivalent to:
Crypter.Crypt(password, crypt) == crypt
Because Crypt reads only AB, if you pass it ABC, it's the same as passing it AB. This is how Crypt does double-duty both generating and checking password hashes.
At registration, GenerateSalt and Crypt, and at log-in, CheckPassword. Many people will tell you this or that about storing salts separately, etc. and this is good general advice, but Modular Crypt Format is designed so everything needed is stored in the same string. It's all taken care of for you.
Oh... Also, in your code, you have a bug. Your line in the middle isn't doing you any good. The following will work correctly:
string crypt = CryptSharp.Crypter.Sha512.GenerateSalt();
crypt = CryptSharp.Crypter.Sha512.Crypt(txtspss.Text.Trim(), crypt);
There is not enough code to say what exactly is wrong, but you should start by using the result of
CryptSharp.Crypter.Sha512.GenerateSalt()
because right now, you just dump it by overwriting the variable in the following line.
SHA512 is a Hashing algorithm, and to make it more secure against attacks like rainbow tables library methods optionally take a salt value.
The same salt value should be present when hashing and when comparing the hash of a new value, and in your code you don't seem to be doing that.
When registering a user; the Salt should be stored in the database and retrieved when logging in so it can be supplied to the CheckPassword function.
I'm creating a C# application that will lock out functionality (key combinations, windows task bar, etc.) in a Kiosk-style environment. One of the requirements is that some people should still be able to break out of the application using a key combination and a password.
The application itself is completely done, but I have not found a good way to store and check against a password. Everything should be stored locally (there is not check against a network database or whatever). How can I define a password for unlocking my application while also making this flexible (the ability to change the password without recompiling the application). How can I accomplish this in a secure way?
Store a secure hash of the password, it doesn't need to be reversible.
When someone enters a password you hash that by the same algorithm and check it matches the hash.
Because you never store the actual password it's secure.
I recommend using a key stretching algorithm like PBKDF2. .NET has support for this using Rfc2898DeriveBytes or you can use System.Web.Helpers.Crypto.
In addition the password you use should be long (at least 12 chars, but longer the better) and salted with an extra string that stops attackers using a rainbow table attack.
The standard method for storing a password in a configuration file is to use a strong hash algorithm. Read the answer at How to store passwords in Winforms application? and maybe the wiki article at https://en.wikipedia.org/wiki/Cryptographic_hash_function
I have to disagree with Brian, because as of now the standard method for storing passwords in any database is to "salt" (see Wikipedia for a detailed explanation) the password with a randomly generated value and store the hashed value and the salt in your "database" (see remarks). The salt is not a secret so you can store it in plain text. Whenever the user enters the password you read the salt from your file, apply it to the entered password and then apply your chosen hash algorithm. Then you compare the results with your stored hash. If they match, the user is authenticated. For a good (and entertaining :)) explanation why "just" hashing the password isn't enough, see: How NOT to store passwords!
For a tutorial implementation of the salting and hashing process in C# see: C# Salting & Hashing Passwords
You can also find a good way to do this here: https://stackoverflow.com/a/12657970
For a quick reference, the process in pseudocode:
First password storage:
//get user input
username = GetUserName
password = GetPassword
//generate random salt
salt = GetRandomValue
//combine password and salt and apply hash
hashedPassword = Hash(password + salt)
//store hash value and salt in database
AddToDatabase(username, hashedPassword, salt)
User login:
//get user input
username = GetUserName
password = GetPassword
//read salt from database
salt = GetSaltFromDatabase(username)
//combine password and salt and apply hash
hashedPassword = Hash(password + salt)
//compare hash to stored hash value
correctHash = GetHashFromDatabase(username)
if (hashedPassword == correctHash) then
passwordIsCorrect = True
else
passwordIsCorrect = False
end if
Remarks:
This assumes that your usernames are unique as they are used as identifying key in your "database".
The "database" doesn't have to be any kind of "real" database, it can also be your configuration file or a plain text file.
You can store a hash of your key and a password somewhere, for example in some local file. When person input key and password, you get hashes for this values and compare it with hashes in your file.
You need a hash of the password and validate using the hashed text. Adding a salt can make your password more secure. In .Net, you can use System.Security.Cryptography.RNGCryptoServiceProvider .
Here is a good article talking about how to store your passwords and I use its way in my web application.
Is relatively easy using ProtectSection() and UnprotectSection() methods from SectionInformation class. See this article:
http://www.davidgiard.com/2012/06/05/EncryptingAndDecryptingApplicationConfigSections.aspx
http://msdn.microsoft.com/en-us/library/system.configuration.sectioninformation.protectsection.aspx
I have been writing a little program for myself using C# that I can use to store my passwords and then retrieve them for viewing/editing.
While the passwords are stored to disk in an encrypted format, when they are read into memory for display/editing on a form, they are unencrypted.
I have learned that having unencrypted passwords in memory is a pretty big security problem, so I came across the SecureString class.
Would there be a more secure way to do this than using the SecureString class, or does SecureString live up to its name?
SecureString keeps its text encrypted in the memory and you can dispose it immediately when you don't need it. The problem is, when you want to display it or use it in almost any other way, you have to convert it to normal string, which is not secure.
Also, I wouldn't rely on it too much – the system is able to decrypt it without any decryption key, which means determined hacker will most likely be able to do the same. When a hacker gains control of your computer, you can't be sure of anything and he will be probably able to access anything that's not encrypted using a good algorithm with good key.
SecureString goes some way to secure the in memory instance of a string, however you should be aware of some significant drawbacks.
A SecureString (just as svick points out) can be retrieved without a decryption key, so any hacker skilled enough to retrieve this chunk of memory you can safely assume can easily perform this minor operation to retrieve the plain text string. Consider the simplicity of SecureStringToBSTR(input);
SecureString needs to be populated in a character by character way as there is no .Text property Get or Set accessor to use. On blogs including MSDN you will often see code like the following:
public static SecureString StringToSecureString(string input)
{
SecureString output = new SecureString();
int l = input.Length;
char[] s = input.ToCharArray(0, l);
foreach (char c in s)
{
output.AppendChar(c);
}
return output;
}
The significant issue with this code is that the developer allowed the input string to ever exist in memory in the first place. The User Control or WinForm TextBox of PasswordBox used to collect this password from the user should never collect the whole password in one operation, as
Hackers can access memory directly and retrieve the password directly from the control on the stack or inject code to retrieve the password on the instantiation of this method
If your last Memory Dump still resides on your machine from your last blue-screen, and this control was populated with your plain text password, then the password is sitting in a tidy little file ready for your Hacker to pick up and use at his/her leisure.
Instead consider options where the KeyPress is used to retrieve each character from the user, otherwise, WPF's PasswordBox is backed by a SecureString by default I believe (someone else may confirm this).
Finally there are much more simple ways to collect passwords from users like Key Loggers. My recommendation is to consider your user demographic, exposure risk, and determine whether something as trivial as a SecureString is really going to cut it.
SecureString is exactly what the name says and you guesed: It saves the string also encrypted in memory, so yes it is the correct way to go.
See HERE:
Represents text that should be kept
confidential. The text is encrypted
for privacy when being used, and
deleted from computer memory when no
longer needed. This class cannot be
inherited.
You guys are making this WAY too complicated. No one asked if this was the best way to solve the problem. They just want to see some working code. Jeez. In this example, passwordPre is a string that was decrypted from a resource (e.g. a config file) using your proprietary decryption algorithm.
string passwordPre = DecryptProprietary(objectReferringToPassword);
char[] passwordChars = passwordPre.ToCharArray();
System.Security.SecureString securePassword = new System.Security.SecureString(); // in production, this should probably be a global variable
foreach (char c in passwordChars)
securePassword.AppendChar(c);
string decryptedPassword = new System.Net.NetworkCredential(string.Empty, securePassword).Password; // this is how to convert it to a string for quick usage to access the protected resource
So you use the decrypted password quickly to gain access to whatever resource you need and you dispose of it by exiting the method.
I'm building a project from the ground up and I want to do things the Right Way™. I've read online about hashes and that's basically turning a password in 64 letters of mumbo jumbo, correct?
What about salting?
My questions are:
How do I hash a string using C#?
What would the field declaration type be in MSSQL? nvarchar(64)?
What is salting and do I need to save that somewhere in my database?
If I intend to let people use Facebook Connect, do I need to worry about creating a hash/salt?
Code examples are preferred. Thanks!
I will skip question 1 as I'm not a C# person.
Question 3:
Salting is adding a string of random data to the password before hashing. Salts are essential because without them it is possible for an attacker to pre-generate a rainbow table of known password hashes. Salting means that rainbow tables cannot be pre-built, and it means each password must be brute-forced separately.
It is important to generate a new salt for each password.
Salt values are not secret and can be stored alongside the hashed password in your database.
Pseudocode for generating and checking a password are as follows:
generatePassword(String user, String password) {
String salt = generateRandomSalt();
String salted = salt + password;
String hash = hexEncode(hash(salted));
store(user, hash, salt);
}
checkPassword(String user, String testPassword) {
String salt = lookupSalt(user);
String salted = salt + testPassword;
String testHash = hexEncode(hash(salted));
return testHash.equals(lookupHash(user));
}
Question 2:
The length of the database field depends on the hash algorithm. SHA1 generates 160-bit output, so that will be 40 characters if hex-encoded. A good rule of thumb is to use a salt that is the same size as the hash output, so you'll have two 40-character columns: one for salt, and one for the hash.
Question 4:
No idea how Facebook Connect works, sorry. I hope the other two answers are helpful.
1) Code
public static string HashStringSha1(string plainText, string salt)
{
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
{
byte[] bb = sha1.ComputeHash(Encoding.UTF8.GetBytes(salt + plainText + plainText));
return Convert.ToBase64String(bb);
}
}
2) Store base64 string in SQLserver varchar
3) Store the salt in a different field with the hash. Salt as plain text.
4) Not sure what you mean. If you use OpenId, you do not need to store passwords.
Hash & salt are used to keep your users password safe. MD5 hash is the most popular algorithm used. Hash functions are irreversible -> you cannot get the password from the hash, but somebody somewhere thought - hey! let's generate a a table that contains example passwords and their hashes then sort that and do simple lookup to check the password. This is why salt was introduced - salt is added to the user password and then hashed. Salt is randomly generated thus should be kept in the db for each hash.
For the details of implementation I suggest you look at live examples like nopCommerce which is open source e-commerce solution. http://www.nopcommerce.com
(this one is very useful because it has a custom membership provider implemented which utilizes the ideas of salt & hash)
How do I hash a string using C#?
Take a look here:
http://support.microsoft.com/kb/307020
What would the field declaration type be in MSSQL? nvarchar(64)?
It is binary data. You might want to format it as string, but thats "extra work"
What is salting and do I need to save that somewhere in my database?
You should use a unique salt per entry. The salt is there to make it impossible to know if 2 times the same password was used. usually a slat is constructed from 2 components... A "shared secret" (Needs to be resonably complex, so it can defeat lookup lists) and a unique part (for example a ID value of the user in the DB or something else.... Just make sure that "shared" + "Unique" + Password is unique
If I intend to let people use Facebook Connect, do I need to worry about creating a hash/salt?
If you can use a 3rd party API, then you dont have to care about hashing salting. As long as you dont save the passwords, there is no need to hash. Hashing is a one way function, so there is no "good" way (Hint: Rainbow tables) to reconstruct the original password. If you let facebook handle the authentication, you wont have to worry about all that base plumbing, since you dont store the passwords.
Hashing is used if you want some information so secure, that even someone that steals your DB cannot access it. BTW: That includes yourself... There is no way to recreate the original password...
I am looking to encrypt data. I want to generate encryption keys based on a password, and some moving value, like time. The goal is to have the key change, but have anyone that knows the password be able to decrypt. This is happening in C#. I am using the following code to hash the password.
private static string GetPasswordHash(string password)
{
TimeSpan span = (DateTime.UtcNow - new DateTime(1900, 1, 1));
string result = Convert.ToInt32(span.TotalHours).ToString();
result += password;
result += Convert.ToInt32(span.TotalDays).ToString();
result = Convert.ToBase64String(SHA256.Create().ComputeHash(Encoding.ASCII.GetBytes(result)));
return result;
}
I then use that hash, plus a salt to generate a key.
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(GetPasswordHash(password), salt);
rdb.IterationCount = 1000;
RijndaelManaged rm = new RijndaelManaged();
rm.KeySize = 256;
rm.Key = rdb.GetBytes(32);
rm.IV = rdb.GetBytes(16);
There seem to be issues with the way I am doing this. Some of the computers are in different timezones, or if the hour ticks as I send the data, or if the machines times are slightly off. Are there better suggestions?
The standard strategy is to just send the value (time, etc.) just be sent with the encryption key. Since the value you are using is public knowledge, it is fine if whoever first creates the password provides the "moving value" publicly. See Salt. What you are doing is not a new technique. You also seem to be using Key Strengthening.
You might just send the changing part (unencrypted) along with the encrypted data, so that anyone who knows the secret password can easily reconstruct the password used for encryption. Since the changing part is relatively easy to guess, it wouldn't make it much less secure.
You could find a scheme that generates the same moving value over a window of time, centered on the current time. Thus, if you choose a window of 12 hours, all computers 6 hours behind and 6 hours ahead of yours would generate the same encryption key.
Are you worried that a file with the same data encrypted with the same password looks the same?
You could use set the initialisation vector with the current time, and encrypt using your password.
To decrypt, you use the same IV value (so this has to be stored unencrypted with your file somewhere).
Password based key derivation is already implemented in .net. While I can't see anything wrong with your function GetPasswordHash() its always worth using library functions in crypto as they'll likely be better tested and small errors can completely destroy the security of a system. Here're two links, there are probably others too:
rfc2898derivebytes
passwordderivebytes