I have searched all over Google and I can't find a code sample of Scrypt usage (for hashing a password) using the Cryptsharp library.
Can you please provide a sample for hashing the password?
It's only a single call so I'll walk you through the parameters:
key: this is your password, use UTF-8 encoding (without byte order mark) to encode your password into a byte array;
salt: a string of secure random bytes stored with the result of the scrypt function, 16 bytes should be ample;
cost: the given suggestion is 262144, but you may want to increase that value if your server can handle the additional load;
blockSize: see cost, the given suggestion is 8;
parallel: I would keep this to 1 unless you want to experiment with multi-threading;
maxThreads: in general null will do nicely;
derivedKeyLength: well, that depends, for passwords 128 should be ample though, it's unlikely that your password has more than 128 bits of security.
You should store at least the salt and result. You may want to use base 64 encoding if you want to store them as strings.
I would recommend you to store one additional piece of data: a version of your password based key derivation scheme (PBKDF). Say, set it to 1 for using scrypt, using the given key encoding, salt size, cost, blocksize etc. In that case you can upgrade your scheme later on (you need the user to supply his/her password to do this, so you will have to do this online, so you will end up having multiple schemes operational at the same time).
Note that you may chain PBKDF function calls, so you could use the original PBKDF output and use that as input for the next PBKDF. In that case the user doesn't have to supply the password (this hint was taken from CodesInChaos on another question).
#MaartebBodewes provides an excellent answer with very wise additional tips. Here is a code sample with his recommendations. I would also suggest reading 'Your password is too damn short' which shows the importance of using modern cryptography like (at the time of writing) BCrypt or Scrypt.
public string Hash(string secret, string salt)
{
var keyBytes = Encoding.UTF8.GetBytes(secret);
var saltBytes = Encoding.UTF8.GetBytes(salt);
var cost = 262144;
var blockSize = 8;
var parallel = 1;
var maxThreads = (int?)null;
var derivedKeyLength = 128;
var bytes = SCrypt.ComputeDerivedKey(keyBytes, saltBytes, cost, blockSize, parallel, maxThreads, derivedKeyLength);
return Convert.ToBase64String(bytes);
}
Related
I am new to hashing the data, I got a requirement to Hash data to the length of 128.
Tried hashing using SHA256 and SHA512, which produces 44 and 88 lengths of hashed data. Is there any way to generate hashed data at a specified length?
I am trying to achieve using the below code.
var value = "Test";
using var sha256 = SHA256.Create();
byte[] privatekeyBytes = Encoding.UTF8.GetBytes(value);
var text = Convert.ToBase64String(sha256.ComputeHash(privatekeyBytes));
I know it's a pretty basic question, any links to understand more on this will also help me.
It really depends on what you want to achieve. In some contexts, I keep insisting that return 1 is a valid hash function. By and large, there are three applications for hashes:
Quickly differentiate between data that is certainly different for better runtime performance. For that purpose, depending on your data something dumb like return input.Length can be perfectly sufficient.
Evenly distribute data in a HashSet or similar, i.e., you primarily care that all available hashes are used roughly equally often. For that, and again depending on the type of data you are processing, it might suffice to take the first 128 bytes, XOR them with the next 128 bytes, XOR with the next 128 bytes and so on until the end of the input data.
Cryptographically sign something. For that you should use one of the hashing algorithms designed for that purpose; they all produce a fixed number of bytes. If you find one that produces more than 128 bytes, it is perfectly fine to just truncate it to that length (at the loss of the additional security the extra bytes would have brought). As far as I can see, SHA512 is available in C# and should return a sufficiently long hash, that is, SHA512.Create().ComputeHash(privatekeyBytes).First(128).
I've been reading about securing users passwords in the database (https://crackstation.net/hashing-security.htm). The basic idea is understood - generate a random Salt, append it to the password and hash the password.
So here's what I did (I didn't put here some methods that do conversion to strings):
RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create();
byte[] rndBytes = new byte[512];
randomNumberGenerator.GetBytes(rndBytes);
string salt = ToHexString(rndBytes);
var sha512Hasher = SHA512.Create();
string hashedPwd = ToHexString(sha512Hasher.ComputeHash(GetBytes(pwd + salt)))
According to the article this is secured but can be even more secured by using "key stretching" which for my understanding is hashing that done slower (using a parameter) to make brute-force the password harder.
So here's what I did:
RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create();
byte[] salt = new byte[512];
randomNumberGenerator.GetBytes(salt);
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(user.Password, salt, 1000);
byte[] hashBytes = k1.GetBytes(512);
string hash = ToHexString(hashBytes);
Now here are my questions:
What is the difference between SHA512 and Rfc2898DeriveBytes? which is more secure?
Should I have smaller salt with more iterations? Will it make it more secure?
On a 1000 iterations it runs very fast - how slow should it be? half a second? a second? What is the rule of thumb here?
On the database - should I convert the byte array to string and store strings or should I store the byte array in a binary data field?
Edit (another questions)
If I iterate a 1000 times over rehashing SHA512 - does it give the same security?
What is the difference between SHA512 and Rfc2898DeriveBytes?
SHA512 is a cryptographic hash function, while Rfc2898DeriveBytes is a key-derivation function. As you already wrote, hash functions are too fast and can be brute-forced too easily, that's why we need functions with a cost factor like BCrypt, SCrypt, PBKDF2 or Argon2. As far as i know, Rfc2898DeriveBytes implements the PBKDF2 using a HMAC with SHA1. This answers your other question that an iterated SHA is less secure than Rfc2898DeriveBytes.
Should I have smaller salt with more iterations?
Salt and cost factor are not related and have different purposes. The salt prevents the usage of rainbow tables, the iterations are a counter measure for brute-force attacks. More infos you can get from my tutorial about safe password storage. So no, don't make the salt shorter.
how slow should it be?
Of course this depends on your server and your requirements for security, slower means harder to brute-force. A rule of thumb is about 50 milliseconds for a single hash.
On the database - should I convert the byte array to string?
This is up to you. Strings are easier to handle for backups, migration and debugging, while byte arrays need less space in the database. Maybe you should also have a look at BCrypt.Net, it generates strings as output which contain the salt and are easy to store in a single database field [string].
I found the following code that is used to hash a password before storing it in an MSSQL database (the column is of type NVARCHAR).
string HashPassword(string password)
{
var encoding = Encoding.UTF8,
var plainBytes = encoding.GetBytes(password);
var hashedBytes = MD5.Create().ComputeHash(plainBytes);
return encoding.GetString(hashedBytes); //<-- Bad practice?
}
At first I thought it was really strange to try and store random bytes as an UTF8 string and that I should change this to Base64 encoding. But are there any real implications of doing it this way other than bad practice?
And also; if anyone would get a hold of the database doesn't this mean that it would be impossible to use a rainbow table or similar to try and brute reverse the hashes since the original bytes are lost?
You're weakening the security by reducing the number of possible strings that will be encoded. Any time your hash ends up being an invalid UTF-8 sequence, you'll end up with U+FFFD as the output character (the Unicode "replacement" character). That means multiple hashes end up with the same string:
using System;
using System.Text;
class Program
{
static void Main(string[] args)
{
byte[] hash1 = FillBytes(128);
byte[] hash2 = FillBytes(129);
string text1 = Encoding.UTF8.GetString(hash1);
string text2 = Encoding.UTF8.GetString(hash2);
Console.WriteLine(text1 == text2);
}
static byte[] FillBytes(byte data)
{
byte[] bytes = new byte[16];
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = data;
}
return bytes;
}
}
It's also possible that the text returned by GetString won't be correctly stored in SQL Server, depending on how you've got it configured. (If the field is set up so that it can store anything in Unicode, that part is okay.) If it is losing data, that's even worse - the stored correct hash won't match the computed correct hash, so someone typing in the right password will still be denied access. As I say, this may not be a problem - but you haven't given us enough information to say for sure, so it's at least worth considering. This part wouldn't be a problem if you used Base64 or hex, both of which end up with ASCII data.
Using MD5 to hash a password is a bad idea to start with - weakening it still further with a lossy text transformation is worse. It makes it significantly easier for an attacker to find an incorrect password that still ends up with the same text.
I would suggest:
You use a more secure hashing approach (e.g. bcrypt or PBKDF2) - see Jeff Atwood's blog post for more details (and read a security book for more still)
To store the hash, either use a blob (store the bytes directly) or convert to base64 or hex in order to preserve the full information.
This may work, however is really a bad practice. At least conversion will depend on local charset.
I want to store login and password in sqlite database. This database in encrypted using SQLCipher library. But password to encrypt database is separate issue. This password is stored in code of application. Login and password are provided by user to login to application. In C# there is the SHA256 class. If I use this class if it is enough ? Or rather I should use hash and salt or other methods ?
Thanks
To store a user password in a database for login matters, you should use a hash function with a salt.
SHA 256 is one of them, but there are better ones existing. I recommend you using the PBKDF2 derivative function. You can implement your own PBKDF2 hashing method using the Rfc2898DeriveBytes class provided in the .NET framework.
Here is a quick how-to-do-it:
int saltSize = 256; // Number of bytes of the salt
int iterations = 1000; // Number of times we iterate the function
// The more we iterate, the more it is gonna take time.
// The advantage of a great iterations number is to
// make brutforce attack more painful.
int hashSize = 20; // Number of bytes of the hash (the output)
var deriveBytes = new Rfc2898DeriveBytes("mypassword", saltSize, iterations);
byte[] salt = deriveBytes.Salt;
byte[] hash = deriveBytes.GetBytes(hashSize);
You just have now to store the salt and the hash in your database. Use Convert.FromBase64String and Convert.ToBase64String to get a string from a byte[] and vice-versa.
Another alternative is to use bcrypt. See this interesting article.
Can someone reverse this handy hash code I'm using?
using System.Security.Cryptography;
public static string EncodePasswordToBase64(string password)
{ byte[] bytes = Encoding.Unicode.GetBytes(password);
byte[] inArray = HashAlgorithm.Create("SHA1").ComputeHash(bytes);
return Convert.ToBase64String(inArray);
}
Everything I end up doing fails horribly :(.
No, you can't reverse a hash. The typical process is to compare other input to the hash you have, to check if they are the same.
Like (pseudo):
initial = Hash(password);
possible = Hash("test");
if( initial == possible ){
// we infer that password = "test"
}
But note that SHA1, SHA0, and MD5 should no longer be used; (due to various degrees of breaking in each). You should use SHA-2
The only real way of "unhashing" is using a rainbow table, which is a big table of hashes computed for all possible inputs. You look up the hash and get what was probably the original input.
http://en.wikipedia.org/wiki/Rainbow_table
You cannot un-hash SHA1, MD5, or any other one-way hash method unfortunately. Though it is possible to undo BASE-64.
SHA is an NSA acronym for "Secure Hash Algorithm".
Secure Hashes are hard to reverse by definition -- otherwise they would not be Secure.
You need to use a reversible hash function if you want to be able to easily compute sources that will generate the same hash (and even then you might not get the original source due to hash collisions where more than one source input can result in the same hash output).