I am attempting to apply some security to a project I'm completing for college. This security is somewhat glancing so I'm tempted to give up, save passwords as plaintext or converted to base64, and do something more user-obvious.
Before I give up, I'm asking SO. This is my first attempt at asking anything here so please be gentle.
I decided that implementing this MSDN code wouldn't be too hard.
http://msdn.microsoft.com/en-us/library/aa545602%28v=cs.70%29.aspx
Turns out, it really is. I'm getting the error
System.FormatException: Input string was not in a correct format.
For code
binarySaltValue[0] = byte.Parse( salt.Substring( 0, 2 ), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture.NumberFormat );
I'm going to be honest, I don't fully understand this code.
What is SaltValueSize supposed to be? The provided code doesn't supply it, neither do any References. Also it's capitalised, so is it an object? Or a field in some object somewhere?
The variable "hash" is not defined anywhere, so I just filled it with new MD5CryptoServiceProvider(). Is this a mistake?
If I'm reading it right, the string "salt" is supposed to hold binary, but it doesn't at runtime, it has garbled text, meanwhile the line everything crashed at is trying to parse binary from "salt"? Why?
If anyone can fix this or supply an idiot-proof asynchronous hashing class I'd appreciate it.
( apologies for my random user name, I have no idea how that happened )
Here's a basic method (no salt) to at least get you started. It just "hashes" the string coming in.
private string GetHashedString(string _PW)
{
string _HashedPW = "";
SHA512 sha = new SHA512CryptoServiceProvider();
byte[] result;
StringBuilder strBuilder = new StringBuilder();
sha.ComputeHash(ASCIIEncoding.ASCII.GetBytes(_PW));
result = sha.Hash;
for (int i = 0; i < result.Length; i++)
{
strBuilder.Append(result[i].ToString("x2"));
}
_HashedPW = strBuilder.ToString();
return _HashedPW;
}
Related
What is best way to create SecureString(unicode encoded) from byte array?
I want to store my decrypted DEK key in memory, the decryption process is made by Azure.KeyVault(api), that produce byte array as a result.
var keyBytes = client.DecryptAsync(url, keyName, keyVersion, algorithm, encryptedKeyBytes).GetAwaiter().GetResult().Result;
I have created something like that but I am not proud from that implementations.
var secureKey = new SecureString();
var secureKeyCharArray = Encoding.Unicode.GetChars(keyBytes);
for (int i = 0; i < keyBytes.Length; i++)
{
keyBytes[i] = 0;
}
for (int i = 0; i < secureKeyCharArray.Length; i++)
{
secureKey.AppendChar(secureKeyCharArray[i]);
secureKeyCharArray[i] = (char)0;
}
secureKey.MakeReadOnly();
After rewriting DEK key to SecureString variable I am cleaning both array: secureKeyCharArray and keyBytes but i dont know that it is enough.
Do you know some better solutions for that case? Maybe some nuget packages? Or maybe my whole idea is wrong?
Thanks for any suggestion.
=== Edited ===============================================================
But if we focus on storing secure data in memeory, do you know any better solution than SecureString? Work with this type is a little bit dificult, for example to read key from that vartiable I am using something like that:
IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
I dont know that it is ok for production purpose to use Marshal classes.
The most obvious problem is:
.GetAwaiter().GetResult().Result;
You should almost never do that; await would be far preferable:
var keyBytes = await client.DecryptAsync(url, keyName, keyVersion,
algorithm, encryptedKeyBytes);
Using .GetAwaiter().GetResult().Result; on an incomplete awaitable operation can cause hard deadlocks. More generally, you should only try to access the result if you know (either by checking IsCompleted, or because you've awaited) that it is complete.
As for the rest: it really depends what your aim is here; and note that yes SecureString is more secure than string, but it isn't actually secure in the strong sense - a malicious user can still reverse it. It is mostly an inconvenience and something that makes it hard for memory scanners to find the data. Other than that, what you have looks OK? Note that if you want to avoid the AppendChar loop you could use fixed in an unsafe block and make use of the constructor that takes a char* and int, but that's just a performance tweak. You'd still need to erase the source array manually, of course. If you're going that route, and the password isn't large, you could actually stackalloc a block to decode into, rather than having secureKeyCharArray as an array. You would still need to manually wipe the stackalloc area when you're done.
I'm trying to learn some good practice for handling passwords. I will supply some code snippets from my project and explain what I'm worried and curious about.
Lets start with the code that gets the user input, my button event code:
string username = txtUser.Text;
string password = Hash.EncryptString(txtPass.Text);
Here my idea is that, storing a password in a string in clear text is probably bad practice? I'm aware this is probably not the solution to that (especially since I'm sending it in clear text to another method which then stores it in a string anyway), but here I'm calling a method I've created to make the password into a hash.
The EncryptString method in the "Hash" class:
public static string EncryptString(string text) {
var sha1 = System.Security.Cryptography.SHA1.Create();
var inputBytes = Encoding.ASCII.GetBytes(text);
text = ""; //clear string
var hash = sha1.ComputeHash(inputBytes);
var sb = new StringBuilder();
for (var i = 0; i < hash.Length; i++)
sb.Append(hash[i].ToString("X2"));
return sb.ToString();
}
So not much to say here, I make a hash of the password with SHA1 encryption. I thought it would be smart to clear the string after I used it so that the password isn't stored anymore?
Later in the code where I'm authenticating or adding the user, I'm getting or creating a unique salt and mixing it with the hashed password and using the EncryptString method again, before comitting to the DB.
In the name of privacy and security, is this good practice? Or rather, what vulnerabilities are in my code at the moment and how can I fix them?
There are two issues here:
the one you know about -- unprotected memory in heap, and
the one you don't know about -- you shouldn't be hashing passwords
with SHA1.
Let's address both:
(1) Many security people will recommend SecureString to protect your heap memory. However, it turns out that SecureString is not quite as good as advertised. If you want to understand why, you can watch this SecureString design review on youtube. It is long, but it is excellent, and you really only need to watch 10 or 15 minutes to see the issues with it.
In the specific context of a web application, you can try all sorts of stunts to prevent cleartext passwords from being in memory, but at the end of the day you are getting the object as a string from a Request Object. You have no control over the garbage collection of that Request Object. Trying to protect the memory after you get your hands on it is analogous to putting band-aids on a sieve.
Bottom line: don't worry about it. You can't fix that problem, which is inherent to the framework.
(2) Your ideas for password storage are falling under #4 in Top 10 Developer Crypto Mistakes.
Troy Hunt has an excellent article showing how passwords are cracked by one who gets access to the database, and how to prevent such attacks by using bcrypt or pbkdf2 (bcrypt is better).
What scenario are you trying to protect against? The main scenario you are at threat from here is a memory dump containing the string password, or other memory analysis debugging tools. Now, that may be a legitimate threat, or it may not, depending on a lot more context. But if txtPass.Text is a client-side control, then frankly by the time the memory tools come into play, you're more at risk of a key-logger simply grabbing the input for every app as it is entered.
Note that:
text = ""; //clear string
does not remove the string from the unmanaged heap. It just changes the reference in the variable called text to be the interned zero-length string aka string.Empty. The actual string still exists on the managed heap, and probably still in various unmanaged places relating to the input mechanisms underneath txtPass.
I am in quite the situation here at work as I´m all of a sudden starts getting this error:
An exception of type 'System.Web.HttpRequestValidationException' occurred in System.Web.dll but was not handled in user code
Additional information: A potentially dangerous Request.Cookies value was detected from the client (CustomerRegionName="Ö").
I know that there are several threads about this issue already, and I´ve tried all of the answers I have seen, the most common being the following:
Use
httpRuntime requestValidationMode="2.0"
in your web.config (keeping any attributes you already have on that element, if it's already there). ASP.NET4.0 ignores ValidateRequest otherwise.
Taken from: Here
I am building a website where most input is in Swedish, so to prevent browserproblems I encode all cookie values with the help of HttpUtility class.
That means that A value like "Örebro" will be encoded to something like this: %c3%96rebro.
And for some reason .net framework thinks that this is some kind of dangerous value.
I have absolutely no idea what to do here... Any help would be greatly appreciated.
To avoid this error, convert your string into a hexadecimal representation of the string. This can be done with code like this:
string ConvertedString = BitConverter.ToString(Encoding.Default.GetBytes(YourString));
Note that this string will have the hex separated into pairs with "-" (i.e., 4f-cc-12-ab).
When you read it back, restore it to the original string with code like this, assuming your read the encoded string back into string zBackInHex:
string zHex = (zBackInHex.Replace("-", "");
byte[] ba = new byte[zHex.Length / 2]; //One byte for each two chars in zHex
for(int ZZ = 0; ZZ < ba.Length; ZZ++){
ba[ZZ] = Convert.ToByte(zHex.Substring(ZZ * 2, 2), 16);
}
string zBackIn = Encoding.ASCII.GetString(ba); //The original string
I got the idea for this method from another post. I'd give credit, but I don't remember where I originally saw it.
Why don't you try to replace strings with IDs, that will remove all the hassle with encoding. Create lookup table with region ID, RegionName. Pass ID to your cookie, and there will be no problem with dangerous requests.
So, I found a question just like this with an accepted answer, so I hopped off and tried to implement the necessary changes. For some reason though, I am still getting two different strings, and I don't know what it is I'm doing wrong. I tried to comment on the accepted answer to find help, but I lack the reputation to do so. So, I figured I'd ask the question again (that question was 2 years old, too).
Let me explain what I'm doing.
In php...
$intermediatesalt = md5(uniqid(rand(), true));
$salt = substr($intermediatesalt, 0, 8);
$hashpassword = base64_encode(
hash('sha256', $salt . hash('sha256', $password), true)
);
The line that says $hashpassword was taken from the accepted answer from this question. I didn't write any of this php, my friend did. I only know enough about programming to alter the code, but I couldn't create anything in php, let alone HTML.
After the hash has been created, both the hash and the salt are stored on a database.
The C# method I'm using is also from the answer I found here.
public static string ComputeHash(string plainText, string salt)
{
// Convert plain text into a byte array.
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
SHA256Managed hash = new SHA256Managed();
// Compute hash value of salt.
byte[] plainHash = hash.ComputeHash(plainTextBytes);
byte[] concat = new byte[plainHash.Length + saltBytes.Length];
System.Buffer.BlockCopy(saltBytes, 0, concat, 0, saltBytes.Length);
System.Buffer.BlockCopy(plainHash, 0, concat, saltBytes.Length, plainHash.Length);
byte[] tHashBytes = hash.ComputeHash(concat);
// Convert result into a base64-encoded string.
string hashValue = Convert.ToBase64String(tHashBytes);
// Return the result.
return hashValue;
}
But for some bizarre reason, even though the person who asked the question got what s/he wanted, I am still getting an undesired result.
This is the block of code that loads player data then compares the the php generated hashed password with the c# generated hashed password.
// load the player based on the given email
PlayerStructure.Player newPlayer = MySQL.loadPlayer(email);
// compute a hash based on the given password and the retrieved salt
// then, compare it to the hashed password on the database
string hPassword = Program.ComputeHash(password, newPlayer.salt);
if (newPlayer.password != hPassword)
{
sendStatusMsg(index, "Invalid password.");
sendStatusMsg(index, "1: " + hPassword);
sendStatusMsg(index, "2: " + newPlayer.password);
return;
}
MySQL.loadPlayer loads the hash string and the salt string from the database, and I had to use those sendStatusMessage methods to print strings as this is for a server application that takes up to 15 minutes to load data from the database in debug mode. So I run the debug exe instead, ergo no Console.WriteLine calls. newPlayer.password is the hashed password stored on the database (the password created with php). hPassword is the computed hash using the C# method I borrowed.
The salt is e0071fa9 and the plain-text password is 'test'.
This is the result I get with the sendStatusMsg methods:
Invalid password.
1: 3QQyVEfmBN4kJJHsRQ307TCDYxNMpc4k3r3udBaVz8Y=
2: moHRVv9C0JvpdTk28xGm3uvPPuhatK2rAHXd5he4ZJI=
Any ideas as to what I might be doing incorrectly? As I've stated before, I literally just used the answer on here (borrowing the code almost verbatim) and I'm still not getting my desired result. This is the question I referenced: Why isn't my PHP SHA256 hash equivalent to C# SHA256Managed hash
Because as the answer to question you are linking to says, hash returns a hex-encoded string instead of raw bytes by default. You are passing true as the third parameter to override this behavior for the outer call to hash, but you are not doing the same for the inner call.
In fact why are there two hashes in the first place? The inner hash doesn't seem to serve any purpose at all.
As Jon stated earlier, the php was slightly flawed. If anyone else is attempting to do something like this, know that
$hashpassword = base64_encode(
hash('sha256', $salt . hash('sha256', $password), true)
);
as opposed to
$hashpassword = base64_encode(
hash('sha256', $salt . hash('sha256', $password, true), true)
);
makes a HUGE difference. The second line of php is what did the trick.
I hope this helps!
Please on PHP avoid using your own hashing mechanism, unless you are a security / crypto expert and (more important, know what you are doing).
Have a good look on how password_hash works in PHP (and if using a PHP version that doesn't support it - please upgrade it), you can always use Anthony Ferrara compatibility library for good effect:
https://github.com/ircmaxell/password_compat
If you follow his blog, you will get some hints about the issues at stake:
http://blog.ircmaxell.com/search/label/Security
:)
as a small (large) hobby project I've set out to make a (very primitive) ssh-2.0 client in C#.
This is to explore and better understand DH and help flourish my encryption familiarities :)
As per RFC 4253, I've begun the initial connection like this:
(leaving out irrelevant presetting of vars etc.)
Random cookie_gen = new Random();
while ((ssh_response = unsecure_reader.ReadLine()) != null)
{
MessageBox.Show(ssh_response);
if (ssh_response.StartsWith("SSH-2.0-")
{
// you told me your name, now I'll tell you mine
ssh_writer.Write("SSH-2.0-MYSSHCLIENT\r\n");
ssh_writer.Flush();
// now I should write up my supported (which I'll keep to the required as per rfc 4253)
ssh_writer.Write(0x20); // SSH_MSG_KEXINIT
byte[] cookie = new byte[16];
for (int i = 0; i < 16; i++)
cookie[i] = Convert.ToByte(cookie_gen.Next(0, 10));
ssh_writer.Write(cookie); // cookie
// and now for the name-list
// This is where I'm troubled
// "Footer"
ssh_writer.Write(0x00); // first_kex_packet_follows
ssh_writer.Write(0x00); // 0
ssh_writer.Flush();
}
}
As you can see on page 16 of RFC 4253, I'm expected to give 10 name-lists. Are these simply suppose to be strings, or how do I mark start/end of each list (simply by newline \n)? Am I even on the right track here? (keep in mind I will handle DH and encryption past this point. My question is solely based on the initial contact so far).
Any help or comments are welcomed and appreciated,
PS: I'm aware libraries exist, but this is not relevant to my project.
Well, as RFC 4251 states on page 9:
Terminating null characters MUST NOT be used, neither
for the individual names, nor for the list as a whole.
There are also examples in the named RFC.