Encoding options for byte array when hashing - c#

I'm trying to write a basic hashing function accepts an input string and a salt string. Both of those strings then need to be converted to byte arrays, combined then the hash is generated.
I've dug around the Microsoft Membership for inspiration and see that they do it this way:
byte[] bytes = Encoding.Unicode.GetBytes(input);
byte[] array = Convert.FromBase64String(salt);
So what I want to ask is:
Is unicode the best encoding to use when converting the input string to a byte array? What about UTF-8?
Is a Base64String the best format to use for the salt value? If I limit to a Base64 string then essentially I always have to use a hash as a salt, is this the recommended way?

Related

Is There A Better Way Than Unicode Conversion To Convert AES IV To String And Back? [duplicate]

I have been looking at a lot of different C# encryption examples. In most examples the encryption Key as well as the Initialization Vector (IV) are passed into the encryption/decryption methods as an array of bytes.
I would like to store the Key and IV as strings. The Key in a Hardware Security Module and the IV as an nvarchar in the SQL Server database.
I keep running into propblems on how to properly convert the Key and the IV as string. Some examples say to use Base64 Encoding while other examples use Encoding.UTF8.
Here is an example that generates an IV and converts it to a Base64 string...
using (var aesProvider = new AesCryptoServiceProvider())
{
aesProvider.GenerateIV();
var ivBase64 = Convert.ToBase64String(aesProvider.IV);
return ivBase64;
}
However, when I pass this string representation of the IV into the encryption method and then convert it back to a byte array the following code fails saying the IV is not the proper size.
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initializationVector);`
// intermediate code excluded for brevity
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
Is there a standard way of converting an encryption Key and IV back and forth between a byte array and String representation?
You cannot convert binary data to UTF-8 and back again. Some binary sequences are not valid UTF-8 characters and when you convert to UTF-8 that data is lost. It's the equivalent of some characters getting set to '?' when converting between encodings.
You can instead use base64 encoding of binary data to text, and then base64 decode to get back the original binary.
Try converting this to UTF-8, for example: "\x00?\xdc\x80" (that's four bytes: 0, 63, 220, 128). It won't encode to UTF-8 -- it's not valid.
The standard way is using Base-64 encoding - How do I encode and decode a base64 string?

SHA1Managed doesn't produce the expected SHA1 hash

I have an Excel workbook currently acting as a booking diary. It has users/passwords stored in a database, the passwords are hashed using SHA1 (with no salt at the moment to make this easier)
When I store a user with password password I get the following hash in the database:
5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
This is backed up by trying the string here and here, both give the same result as my VBA SHA1 function
So now I want to move this application into C# (probably and ASP.NET web app eventually), so I'm using the following to generate the SHA1 hash:
// Convert plain text into a byte array
byte[] plainTextBytes = Encoding.Default.GetBytes("password");
// Define hash object
HashAlgorithm hash = new SHA1Managed();
// Compute hash value of our plain text
byte[] hashBytes = hash.ComputeHash(plainTextBytes);
// Convert result into a base64-encoded string
string hashValue = Convert.ToBase64String(hashBytes);
Console.WriteLine(hashValue);
but this outputs
W6ph5Mm5Pz8GgiULbPgzG37mj9g=
I must have done some small thing wrong, but I can't work out what it is :(. I have tried the different encoding types (UTF8, ASCII, Unicode) but none produce the correct hash
Can someone shed some light on this for me please?
You converted the string to base64, although it seems you want hex. Convert to hex instead.
You should convert hashBytes into HexString, not Base64.
string hashValue = Convert.ToBase64String(hashBytes);
That's the problem statement, the result string you quoted was not base64 encoded, it was encoded in hex. You get the value you are looking for with:
string hashValue = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
Which produces:
"5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8"

getting byte[] (or char[]) from maskedTextBox

I want to get text inputted by the user into the maskedTextBox and then encode it into byte[] which will be hashed into SHA256 to compare with password hashes stored at my database. The problem is that I've only found .GetCharFromPosition(Point pt) which I don't know how to use (I would know if it would be a simple index in place of this "Point") and .GetHashCode but it needs to be SHA256, not some undefined hash...
You can get the bytes of a string in a certain encoding using Encoding.GetBytes. For example, to get it as an array of bytes as UTF-8:
System.Text.Encoding.UTF8.GetBytes(yourTextBox.Text)

How to hash a password with SHA512

In my previous question I was told to hash passwords instead of encrypt, and that turned out to be correct. Problem is, I've never dealt with hashing passwords before and all the docs say SHA512 which I've tried to use on a test account to no avail. I'm not sure where to go from here. The code comments give me the example "encrypted" string as they call it, and it's "FA35A0194E3BE7024CEFB1839CBFC922" which I'm not sure how to format it like that with SHA512 since all it takes and gives back is a byte array or stream from the ComputeHash() method:
byte[] hashedPassword = HashAlgorithm.Create("SHA512").ComputeHash( ??? );
UPDATE
I've tried printing out the UTF8Encoding.GetString on the bytes, but it just displays a bunch of bullshit characters that look nothing like the one in the example docs.
Hashing with plain SHA-512 is still wrong. Use PBKDF2 which is exposed via Rfc2898DeriveBytes.
It returns raw bytes, which you should encode with either hex or base64.
You can do hex encoding with:
BitConverter.ToString(bytes).Replace("-","")
You sure it said 512 because that's 128, but anyway you could use something like
System.String Hashed = System.BitConverter.ToString(((System.Security.Cryptography.SHA512)new System.Security.Cryptography.SHA512Managed()).ComputeHash(System.Text.Encoding.ASCII.GetBytes("NotHashedPass"))).Replace("-","");
MessageBox.Show(Hashed);
but id recommend at least using a salt.
Please see tutorial here:
http://www.obviex.com/samples/hash.aspx
From the tutorial:
"These code samples demonstrate how to hash data and verify hashes. It supports several hashing algorithms. To help reduce the risk of dictionary attacks, the code prepends random bytes (so-called salt) to the original plain text before generating hashes and appends them to the generated ciphertext (original salt value will be needed for hash verification). The resulting ciphertext is base64-encoded. IMPORTANT: DATA HASHES CANNOT BE DECRYPTED BACK TO PLAIN TEXT"

Using C#, what is the most efficient method of converting a string containing binary data to an array of bytes

While there are 100 ways to solve the conversion problem, I am focusing on performance.
Give that the string only contains binary data, what is the fastest method, in terms of performance, of converting that data to a byte[] (not char[]) under C#?
Clarification: This is not ASCII data, rather binary data that happens to be in a string.
UTF8Encoding.GetBytes
I'm not sure ASCIIEncoding.GetBytes is going to do it, because it only supports the range 0x0000 to 0x007F.
You tell the string contains only bytes. But a .NET string is an array of chars, and 1 char is 2 bytes (because a .NET stores strings as UTF16). So you can either have two situations for storing the bytes 0x42 and 0x98:
The string was an ANSI string and contained bytes and is converted to an unicode string, thus the bytes will be 0x00 0x42 0x00 0x98. (The string is stored as 0x0042 and 0x0098)
The string was just a byte array which you typecasted or just recieved to an string and thus became the following bytes 0x42 0x98. (The string is stored as 0x9842)
In the first situation on the result would be 0x42 and 0x3F (ascii for "B?"). The second situation would result in 0x3F (ascii for "?"). This is logical, because the chars are outside of the valid ascii range and the encoder does not know what to do with those values.
So i'm wondering why it's a string with bytes?
Maybe it contains a byte encoded as a string (for instance Base64)?
Maybe you should start with an char array or a byte array?
If you realy do have situation 2 and you want to get the bytes out of it you should use the UnicodeEncoding.GetBytes call. Because that will return 0x42 and 0x98.
If you'd like to go from a char array to byte array, the fastest way would be Marshaling.. But that's not really nice, and uses double memory.
public Byte[] ConvertToBytes(Char[] source)
{
Byte[] result = new Byte[source.Length * sizeof(Char)];
IntPtr tempBuffer = Marshal.AllocHGlobal(result.Length);
try
{
Marshal.Copy(source, 0, tempBuffer, source.Length);
Marshal.Copy(tempBuffer, result, 0, result.Length);
}
finally
{
Marshal.FreeHGlobal(tempBuffer);
}
return result;
}
There is no such thing as an ASCII string in C#! Strings always contain UTF-16. Not realizing this leads to a lot of problems. That said, the methods mentioned before work because they consider the string as UTF-16 encoded and transform the characters to ASCII symbols.
/EDIT in response to the clarification: how did the binary data get in the string? Strings aren't supposed to contain binary data (use byte[] for that).
If you want to go from a string to binary data, you must know what encoding was used to convert the binary data to a string in the first place. Otherwise, you might not end up with the correct binary data. So, the most efficient way is likely GetBytes() on an Encoding subclass (such as UTF8Encoding), but you must know for sure which encoding.
The comment by Kent Boogaart on the original question sums it up pretty well. ;]

Categories

Resources