I need to implement hashing (I am not referring encryption) to make some data fields (passwords or some details that do not require getting back in original format, rather only need to match in db) secure. Can you please suggest me the best practices to implement hashing. I will be using C# and SQL Server and it will be a web site.
OK now you've said you're protecting passwords you have some options.
The .NET framework has some built in algorithms - MD5, SHA1, SHA2. MD5 and SHA1 are considered obsolete and dangerous now, instead stick to SHA256.
For example (taken from my book)
static byte[] GenerateSaltedHash(string password, byte[] salt)
{
byte[] plainText = Encoding.UTF8.GetBytes(password);
HashAlgorithm algorithm = new SHA256Managed();
byte[] plainTextWithSaltBytes =
new byte[plainText.Length + salt.Length];
for (int i = 0; i < plainText.Length; i++)
{
plainTextWithSaltBytes[i] = plainText[i];
}
for (int i = 0; i < salt.Length; i++)
{
plainTextWithSaltBytes[plainText.Length + i] = salt[i];
}
byte[] hash = algorithm.ComputeHash(plainTextWithSaltBytes);
}
Now the salt is there to stop precomputed lookups of hashes (hashing itself is not enough any more, people have precomputed hashes of dictionary words and more). But how do you get a salt? Well it's any unique value really, usually a random set of bytes.
public byte[] GenerateSalt(int length)
{
salt = new byte[length];
// Strong runtime pseudo-random number generator, on Windows uses CryptAPI
// on Unix /dev/urandom
RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
random.GetNonZeroBytes(salt);
return salt;
}
So you'd call GenerateSalt(32) first to get the salt (32 is just an example, longer if you wish. You will need to store the salt alongside the password - you don't need to worry about protecting it at all.
Finally you'll need a compare function. When you want to check passwords you would take the user input, get the salt for that user, generate the hash for the supplied password and stored salt, and then compare. You would do this using something like
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static bool ConstantCompare(byte[] array1, byte[] array2)
{
const byte Zero = 0;
int maxLength = array1.Length > array2.Length ? array1.Length : array2.Length;
bool wereEqual = array1.Length == array2.Length;
byte[] paddedArray1 = new byte[maxLength];
byte[] paddedArray2 = new byte[maxLength];
for (int i = 0; i < maxLength; i++)
{
paddedArray1[i] = array1.Length > i ? array1[i] : Zero;
paddedArray2[i] = array2.Length > i ? array2[i] : Zero;
}
bool compareResult = true;
for (int i = 0; i < maxLength; i++)
{
compareResult = compareResult & paddedArray1[i] == paddedArray2[i];
}
return compareResult & wereEqual;
}
I should, of course, point out the ASP.NET membership functions do salt and hash, so they should probably be a first point of call. No point in rolling your own if someone else has done the work.
Here is an API using PBKDF2 for key stretching ONTOP of hashing, this is now best practice.
https://sourceforge.net/projects/pwdtknet
I think you misunderstand what hashing is. You don't use a hash to "make data fields secure", because a hash can only be calculated in one direction. Compute and store the hash for your data, store the hash only, and you will be unable to retrieve your data later.
You might need to encrypt the data. That is an entirely different can of worms with it's own set of problems: how do you store and protect the decryption key, what encryption algorithm to use, do you do the encryption at the database level (sql server supports this) or the application level? How do you enforce encrypted transfer, and protect against copy of the data by the end user?
Related
I'll get right to the question,
We have this block of C# code
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, passwordSaltBytes, iterationCount))
{
pbkdf2Bytes = pbkdf2.GetBytes(derivedLength + iterationCountBytes.Length);
}
Returns a byte array, first index has a value of 252
We attempt the same thing in PHP:
$key = hash_pbkdf2("SHA1", $password, $password.$salt, $iterationCount, 48);
First index is 102...
The values all match before this specific part.
It's just that hashing function that isn't giving me consistent results.
Any help is appreciated, cheers.
Edit - If it's not obvious, I'm trying to understand why those two values don't match, what encoding/decoding etc. am I misunderstanding or doing incorrectly.
This is the full C# code. As you can see there are some unnecessary loops etc. but the reasons why this wasn't working are 2:
As somebody pointed out, the bytes in PHP do no output raw data by default, and thus the hash (and consequently as such,) its bytes, weren't identical with that of the C# script.
Previously, I thought (as others also pointed out) that I should pass in the $salt as it is without any encoding or transformation. But upon looking closer at the actual C# code... we can see in the 2nd for i loop that they're actually appending saltBytes onto passwordBytes, thus creating something similar to $password.$salt in PHP
Combining the two above issues:
Sending the $password.$salt instead of just one, and then setting the $raw_output option to true, outputs the same hash, the same bytes as C# does.
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
byte[] iterationCountBytes = BitConverter.GetBytes(iterationCount);
int derivedLength = passwordBytes.Length + saltBytes.Length;
byte[] passwordSaltBytes = new byte[derivedLength];
byte[] pbkdf2Bytes;
string encryptedString;
for (int i = 0; i < passwordBytes.Length; i++)
{
passwordSaltBytes[i] = passwordBytes[i];
}
for (int i = 0; i < saltBytes.Length; i++)
{
passwordSaltBytes[passwordBytes.Length + i] = saltBytes[i];
}
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, passwordSaltBytes, iterationCount))
{
pbkdf2Bytes = pbkdf2.GetBytes(derivedLength + iterationCountBytes.Length);
}
Thanks.
So I am hashing passwords to a database using the Rcfc2898DeriveBytes class in .NET
Everything is working fine for hashing and storing both the final hash and the salt.
However, I am having an issue in figuring out to store the number of iterations that the class runs through when hashing the password.
After Googling, I have seen only that it should be stored in front of the password hash but I am unsure how to go about this in a way that would make the number retrievable in case I were to change the number later (which without storing the iterations, the change would break the old passwords).
I see the bcrypt will do this all for you but I don't have the luxury of added a library to the project.
What is the best way to store this number and how would I go about doing that so it is retrieveable and not just lost in the hash when stored (how would I seperate it from the hash once I get it back)?
Thanks for any advice and information ahead of time!
In principle, you don't have to store the amount of iterations at all. Just like you don't have to store the hash type if you keep it consistent.
I would propose something slightly different: store a single byte (prefixed) that contains a version number, starting with zero, just before the salt & hash. This version number is linked to the number of iterations, the hash method, the character encoding method and of course PBKDF2. If you want to upgrade to a better protocol, simply store 01 as initial byte and link that with new parameters. This way you can distinguish between the old style passwords and new style.
Normally you can only upgrade if the user enters his password as a hash is not reversible, so it's not easily possible to upgrade the number of iterations.
I found what I am looking for at the URL below.
https://cmatskas.com/-net-password-hashing-using-pbkdf2/
Relevant code here:
public class PasswordHash
{
public const int SALT_BYTE_SIZE = 24;
public const int HASH_BYTE_SIZE = 20;
public const int PBKDF2_ITERATIONS = 1000;
public const int ITERATION_INDEX = 0;
public const int SALT_INDEX = 1;
public const int PBKDF2_INDEX = 2;
public static string HashPassword(string password)
{
var cryptoProvider = new RNGCryptoServiceProvider();
byte[] salt = new byte[SALT_BYTE_SIZE];
cryptoProvider.GetBytes(salt);
var hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
return PBKDF2_ITERATIONS + ":" +
Convert.ToBase64String(salt) + ":" +
Convert.ToBase64String(hash);
}
public static bool ValidatePassword(string password, string correctHash)
{
char[] delimiter = { ':' };
var split = correctHash.Split(delimiter);
var iterations = Int32.Parse(split[ITERATION_INDEX]);
var salt = Convert.FromBase64String(split[SALT_INDEX]);
var hash = Convert.FromBase64String(split[PBKDF2_INDEX]);
var testHash = PBKDF2(password, salt, iterations, hash.Length);
return SlowEquals(hash, testHash);
}
}
I took HashPassword method to save my values to the database for later use. I used the ValidatePassword to get them back out for me to use again. It worked like a charm and allowed me to make the size of the bytes for the salt and hash, along with the number of iterations variable based on the strength needed. The values are just stored in the Web/App config file.
Thank you for the answers everyone!
Take a look at how bcrypt stores the hashes here:
What column type/length should I use for storing a Bcrypt hashed password in a Database?
So if you only plan to change iterations, you could go for something simple like this:
$<number of iterations>$<hash>
What is the best way to handle the following situation in C#?
I have a server application written in C/C++.
For example
It creates a unsigned char buffer with length 256.
In this buffer the server stores the data the client sends to it. After storing, there are some cryptography checks with the received buffer.
I'm writing a client for this server in C#.
The problem is the buffer the server is expecting at fixed length of 256.
When I create a byte[] array with content and total length of 256 the cryptography checks are failing.
The reason I found out is simple. The server expects a buffer of 256 bytes long. For example if the message is "Hello World", the rest of the buffer has to be 0-padded.
Or, better explained: the bytes need to be (unsigned) "204" or (signed) "-52".
I think this is a C/C++ concept issue/problem.
To solve my problem, I am setting that value explicitly.
public static byte[] GetCBuffer(this byte[] data, int len)
{
byte[] tmp = new byte[len];
for(int i = 0; i < len; i++)
if(i < data.Length)
tmp[i] = data[i];
else
tmp[i] = 204;
return tmp;
}
Are there better ways to work with these art expected bytes? Am I not seeing something essential?
If you don't like if in your code, you can try LINQ:
public static byte[] GetCBuffer(this byte[] data, int len)
{
byte[] tmp = Enumerable.Repeat((byte)204, len).ToArray();
for(int i = 0; i < data.Length; i++)
{
tmp[i] = data[i];
}
return ret;
}
But conceptually, it's the same, just looks (arguably) a bit nicer.
Can you 'memset' the entire array to the desired fill character and then insert the actual data?
I'm porting some code that uses incremental SHA-1 heavily:
SHA1 hasher = HashAlgoFactory.Create<SHA1>();
hasher.Initialize();
DiskIOCallback readCallback = null;
readCallback = delegate(bool successful) {
if (successful)
hasher.TransformBlock(hashBuffer, 0, count, hashBuffer, 0);
offset += count;
if (!successful || offset == endOffset)
{
object hash = null;
if (successful)
{
hasher.TransformFinalBlock(hashBuffer, 0, 0);
hash = hasher.Hash;
}
And am looking for a WinRT/Metro equivalent. I've used hasher.HashData before; is there some relatively simple way to get incremental behaviour out of HashData, or some alternative that implements the same functionality as above (in a WinRT/Metro way)? It's entirely possible I'm missing something obvious...
You should use CryptographicHash class:
var hashProvider = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha1);
var hasher = hashProvider.CreateHash();
You can append multiple increments of data:
hasher.Append(bytesPart.AsBuffer());
Once you're done, you retrieve the hash:
var hash = hasher.GetValueAndReset().ToArray();
I have been working on the problem sets at Project Euler for some time and have enjoyed the challenges presented. I am currently on Problem 59 which involves the process of encryption and decryption.
The problem is, by any reasonable standard, a very simple decryption problem.
I have been told that the encryption key consists of 3 lowercase letters.
I have been given a description of the encryption/decryption process.
I have been given an encrypted text file which contains only encrypted common English words
I fully understand the process of importing the data, cycling through all possible keys, and attempting to decrypt the file data with each possible key. My trouble is, after a decryption attempt with one of the keys, how can I tell if that key was the correct decryption key? As far as the computer is concerned, every decryption key just converts the data from one value to another. The meaning of that value is purely subjective/interpreted. How can I tell if a decryption key has decrypted the data into something meaningful (ie. common English words)
Here is the code I have so far (C#):
static void Main(string[] args)
{
/* Get the data from the file and convert to byte array*/
StreamReader inData = new StreamReader(#"C:\Users\thantos\Desktop\cipher1.txt");
string[] strData = inData.ReadLine().Split(new char[] {','});
byte[] fileData = new byte[strData.Length];
foreach (string x in strData) { byte.Parse(x); }
/* for each three character lowercase password */
for (uint i = 0; i < 26; i++) {
for (uint j = 0; j < 26; j++){
for (uint k = 0; k < 26; k++) {
/* create a key */
byte[] key = new byte[3];
key[0] = (byte)(i + 97);
key[1] = (byte)(j + 97);
key[2] = (byte)(k + 97);
/* create temp copy of data */
byte[] dataCopy = new byte[fileData.Length];
fileData.CopyTo(dataCopy, 0);
/* decrypt using key */
for (uint l = 0; l < dataCopy.Length; l++) {
dataCopy[l] = (byte)(dataCopy[l] ^ key[l%key.Length]);
}
/* cannot figure out how to check
* if data is meaningfully decrypted
*/
bool dataIsMeaningful = isMeaningful(dataCopy);
if(dataIsMeaningful) {
/* do stuff with data if correct
* decryption key was found
*/
}
}
}
}
}
I have tried this method for isMeaningful():
public static isMeaningful(byte[] inData) {
bool isGood = true;
for (uint i = 0; good && i < inData.Length; i++) {
isGood &= (char.IsLower((char)inData[i]));;
}
return isGood;
}
But it returns true for all 17576 possible keys.
How can I determine if the decryption key has decrypted the file data into meaningful data? I'm not looking for solution code or the answer to the Project Euler problem, I am looking for an explanation of how to check that your decryption attempt was successful.
Try different keys and score them against the letter frequency of normal English: space, followed by E, T, A, O, I, N, S, H, R, D, L, U. Pick the highest scoring keys first for a trial.
Well, you can assume only valid ASCII values are permitted (since it should be plaintext). So for every letter you decode, just check that the resulting XOR results in a valid value: if(dataCopy[l] < 32 || dataCopy[l] > 122) continue; This should help to eliminate a vast majority of the possible key combinations.
Actually, this technique could even be used to narrow down your keyset to begin with. So instead of iterating through the loop 26^3 times over the entire 1200 character string, initially iterate 26 times and keep track of which letter at which position is still valid.
var letters = Enumerable.Repeat(Enumerable.Range((int)'a', 'z'-'a' + 1).Select(e => (char)e), 3).Select (e => e.ToList()).ToList();
for(int i = 0, j = 0; i < passwordBytes.Length; i++)
{
j = i % 3;
for(int k = 0; k < letters[j].Count; k++)
{
byte r = (byte)(letters[j][k] ^ passwordBytes[i]);
if(r < 32 || r > 122) letters[j].RemoveAt(k--);
}
}
That should get your valid characters down to almost nothing, at which point you can just iterate over your remaining values (which shouldn't take too long) and look for a few valid sequences (I hear looking for " the " is a good option).
When you have used a key to decrypt the data, it should have given you a text document filled with text. To check for legitimate data, would it be possible to just split the text into a text array using a space character as a delimiter, and then check each of the "words" in the array against an English dictionary?
Can you send a checksum of the original message along with the encrypted message? After decryption, compute the checksum and see if they match.
If that is not available, what about a test message? You could send a test message first such as "This is my test message" and check to see if the decrypted message matches verbatim. It's not fool-proof, but it may cover you.