Hash MD5, Sha1 and Length

S

shapper

Hello,

I created a String extension to hash using MD5 and SHA1:

public static String Hash(this String value, EncryptionType type)
{

// Hash value
Byte[] hash = null;
UTF8Encoding encoder = new UTF8Encoding();
switch (type) {
case EncryptionType.MD5:
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider
();
hash = md5.ComputeHash(encoder.GetBytes(value));
break;
case EncryptionType.SHA1:
SHA1CryptoServiceProvider sha1 = new
SHA1CryptoServiceProvider();
hash = sha1.ComputeHash(encoder.GetBytes(value));
break;
}
return BitConverter.ToString(hash).Replace("-", String.Empty);

} // Hash

What is the relation between the original string length and the hashed
string lenth?

Thanks,
Miguel
 
A

Arne Vajhøj

shapper said:
I created a String extension to hash using MD5 and SHA1:

public static String Hash(this String value, EncryptionType type)
{

// Hash value
Byte[] hash = null;
UTF8Encoding encoder = new UTF8Encoding();
switch (type) {
case EncryptionType.MD5:
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider
();
hash = md5.ComputeHash(encoder.GetBytes(value));
break;
case EncryptionType.SHA1:
SHA1CryptoServiceProvider sha1 = new
SHA1CryptoServiceProvider();
hash = sha1.ComputeHash(encoder.GetBytes(value));
break;
}
return BitConverter.ToString(hash).Replace("-", String.Empty);

} // Hash

What is the relation between the original string length and the hashed
string lenth?

None.

A hash function converts all strings to a fixed length hash that only
depends on the algorithm

MD5 is 16 bytes. SHA1 is 20 bytes.

And you should not use any of those two !

Use SHA-256 (that will return 32 bytes).

Arne
 
T

Tom Spink

Hello Miguel,
Hello,

I created a String extension to hash using MD5 and SHA1:
[snippedy]

In addition to Arne's excellent comment about *not* using MD5 and SHA1,
you should ideally refactor your code a bit to rename the
'EncryptionType' enumeration to 'HashType' - It's a bit misleading
because hashing is certainly not encrypting (as encryption implies the
ability to decrypt).

Also, the optimiser in me spots a way you could reduce code redundancy a
bit.

Since the hashing algorithms all derive from a base class,
'HashAlgorithm', you could do this:

///
HashAlgorithm algo;
switch (hashType) {
case HashType.MD5:
algo = new MD5CryptoServiceProvider();
break;
case HashType.SHA1:
algo = new SHA1CryptoServiceProvider();
break;
default:
throw new ArgumentException();
}

byte[] hash = algo.ComputeHash(encoder.GetBytes(value));
///
 
S

shapper

So for saving user passwords on a database I should use Sha256
correct?
I was using MD5 or Sha1 because those were the options on the ASP.NET
Membership providers.
But now I creating my own custom Membership system based only on
FormsAuthentication.

I did a little search and I found a few more options and updated my
code with your suggestions:

public static String Hash(this String value, HashType hashType) {

HashAlgorithm algorithm;
switch (hashType) {
case HashType.MD5:
algorithm = new MD5CryptoServiceProvider();
break;
case HashType.SHA1:
algorithm = new SHA1CryptoServiceProvider();
break;
case HashType.SHA256:
algorithm = new SHA256CryptoServiceProvider();
break;
case HashType.SHA384:
algorithm = new SHA384CryptoServiceProvider();
break;
case HashType.SHA512:
algorithm = new SHA512CryptoServiceProvider();
break;
default:
throw new ArgumentException("Invalid hash type", "type");
}
UTF8Encoding encoder = new UTF8Encoding();
Byte[] hash = algorithm.ComputeHash(encoder.GetBytes(value));
return BitConverter.ToString(hash).Replace("-", String.Empty);

} // Hash

If you notice something wrong, please, let me know.

Thank You,
Miguel
 
T

Tom Spink

Hi Miguel,
So for saving user passwords on a database I should use Sha256
correct?

Well... Arne's point was that MD5 and SHA1 are rubbish. And they are.
So you *should* use something stronger. SHA256 is a good choice.
I did a little search and I found a few more options and updated my
code with your suggestions:

[snip]

Looking good! Just a wee operational comment about extensibility:

I'd allow the caller to specify the encoding to use, then make an
overload that uses a default encoding:

/// (mind out for wrapped lines)
public static String Hash(this String value,
HashType hashType, Encoding encoding)
{
...
}

public static String Hash(this String value, HashType hashType)
{
return Hash(value, hashType, new UTF8Encoding());
}
///

That way, if in the future you want to use ASCII encoding, or whatever,
you don't have to break existing code.
 
S

shapper

Hi Miguel,
So for saving user passwords on a database I should use Sha256
correct?

Well... Arne's point was that MD5 and SHA1 are rubbish.  And they are.
So you *should* use something stronger.  SHA256 is a good choice.
I did a little search and I found a few more options and updated my
code with your suggestions:

[snip]

Looking good!  Just a wee operational comment about extensibility:

I'd allow the caller to specify the encoding to use, then make an
overload that uses a default encoding:

/// (mind out for wrapped lines)
public static String Hash(this String value,
    HashType hashType, Encoding encoding)
{
    ...

}

public static String Hash(this String value, HashType hashType)
{
    return Hash(value, hashType, new UTF8Encoding());}

///

That way, if in the future you want to use ASCII encoding, or whatever,
you don't have to break existing code.
Thank You,
Miguel

That is a nice tip. So then I use, if I am not wrong:
Byte[] hash = algorithm.ComputeHash(encoding.GetBytes(value));

And for my password scenario what encoding would you use?
The password might have latin characters like ã, á, etc.

Thank You,
Miguel
 
S

shapper

So for saving user passwords on a database I should use Sha256
correct?

For saving passwords on a database you need to use SHA-256,
cryptographic salt (http://en.wikipedia.org/wiki/Salt_(cryptography))
and stretching (http://en.wikipedia.org/wiki/Key_strengthening).
These are standard cryptographic methods for protecting bulk passwords
in a database or similar.  See PKCS#5
(ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2-0.pdf), sections
4 and 5 for more detail.

If you are doing security then it is critical to get it right.


I was using MD5 or Sha1 because those were the options on the ASP.NET
Membership providers.
But now I creating my own custom Membership system based only on
FormsAuthentication.
I did a little search and I found a few more options and updated my
code with your suggestions:
  public static String Hash(this String value, HashType hashType) {
     HashAlgorithm algorithm;
     switch (hashType) {
       case HashType.MD5:
         algorithm = new MD5CryptoServiceProvider();
         break;
       case HashType.SHA1:
         algorithm = new SHA1CryptoServiceProvider();
         break;
       case HashType.SHA256:
         algorithm = new SHA256CryptoServiceProvider();
         break;
       case HashType.SHA384:
         algorithm = new SHA384CryptoServiceProvider();
         break;
       case HashType.SHA512:
         algorithm = new SHA512CryptoServiceProvider();
         break;
       default:
         throw new ArgumentException("Invalid hash type", "type");
     }
     UTF8Encoding encoder = new UTF8Encoding();
     Byte[] hash = algorithm.ComputeHash(encoder.GetBytes(value));

This is insufficient.  Use something more like:

  Byte[] hash = ComputeHash( password | salt );  // | = concatenate
  for (int 1 = 0; i < 10000; ++i)
    hash = ComputeHash( hash | salt );  // | = concatenate

The salt prevents two people using the same password having the same
hash and also stops an attacker pre-calculating hashes for commonly
used passwords.  The repeats (10,000 or whatever) increase the
workload for any attacker trying to guess passwords.  Aim to set the
number of repeats so that it takes about 0.25 seconds to calculate a
hash.  That way the attacker can only try guessing four possible
passwords per second per PC, while users only get a minor delay when
signing on.

You will need to store the salts alongside the hashes as they are all
different.  The repeat count is a single variable.  It theory it
should be reviewed every few years and increased in line with
computing power.  You should also review the hash function used to see
if it has become obsolete.  NIST is currently running a competition to
find a new hash algorithm to replace the SHA2 series, which includes
SHA-256.  Google "SHA 3 competition" if you are interested.

rossum
     return BitConverter.ToString(hash).Replace("-", String.Empty);
   } // Hash
If you notice something wrong, please, let me know.
Thank You,
Miguel

Hi,

What you mean is the following correct:
http://www.obviex.com/samples/hash.aspx

Please, if you know better code to do this let me know.
I am not very familiar with this but I have been reading the links you
sent me and searched for the competition.

Then for each user I save in the database along with the resulting
password hash, its salt to I can use it later to compare the passwords
on authentication, correct?

Thanks,
Miguel
 
S

shapper

Hello,

I tried to create the extension with and without salt and with
optional encoding.
I also made the salt as OUT so if the user does not provide a salt
value then it will be generated and updated.
This is useful to save the Salt in a database.

1. Can the salt parameter be a String?
Then inside the extension I would convert the salt to bytes[] or
create a random in bytes and at the end convert it to string.
I think it would be more user friendly.

2. What is the difference between using SHA256Managed() or
SHA256CryptoServiceProvider() ?
Which one should I use?

Could someone, please, help me improve my code?
I am not so familiar with Cryptography ...

This is the code I have so far:

public static String Hash(this String value, HashType type) {
return Hash(value, type, new UTF8Encoding());
} // Hash

public static String Hash(this String value, HashType type,
Encoding encoding) {

// Hash value
HashAlgorithm algorithm;
switch (type) {
case HashType.MD5:
algorithm = new MD5CryptoServiceProvider();
break;
case HashType.SHA1:
algorithm = new SHA1CryptoServiceProvider();
break;
case HashType.SHA256:
algorithm = new SHA256CryptoServiceProvider();
break;
case HashType.SHA384:
algorithm = new SHA384CryptoServiceProvider();
break;
case HashType.SHA512:
algorithm = new SHA512CryptoServiceProvider();
break;
default:
throw new ArgumentException("Invalid hash type", "type");
}
Byte[] hash = algorithm.ComputeHash(encoding.GetBytes(value));
return BitConverter.ToString(hash).Replace("-", String.Empty);

} // Hash

public static String Hash(this String value, HashType type, out
Byte[] salt) {
return Hash(value, type, out salt, new UTF8Encoding());
} // Hash

public static String Hash(this String value, HashType type, out
Byte[] salt, Encoding encoding) {

// Check salt
if (salt == null) {

// Define a random salt
Random random = new Random();
Int32 size = random.Next(4, 8);
salt = new Byte[size];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(salt);

}

// Define salted
Byte[] valueBytes = encoding.GetBytes(value);
Byte[] valueSaltedBytes = new Byte[valueBytes.Length +
valueBytes.Length];
for (Int32 i = 0; i < valueBytes.Length; i++)
valueSaltedBytes = valueBytes;
for (Int32 i = 0; i < salt.Length; i++)
valueSaltedBytes[valueBytes.Length + i] = salt;

// Hash value
HashAlgorithm algorithm;
switch (type) {
case HashType.MD5:
algorithm = new MD5CryptoServiceProvider();
break;
case HashType.SHA1:
algorithm = new SHA1CryptoServiceProvider();
break;
case HashType.SHA256:
algorithm = new SHA256CryptoServiceProvider();
break;
case HashType.SHA384:
algorithm = new SHA384CryptoServiceProvider();
break;
case HashType.SHA512:
algorithm = new SHA512CryptoServiceProvider();
break;
default:
throw new ArgumentException("Invalid hash type", "type");
}

// Define hash
Byte[] hash = algorithm.ComputeHash(valueSaltedBytes);
Byte[] hashSalted = new Byte[hash.Length + salt.Length];
for (Int32 i = 0; i < hash.Length; i++)
hashSalted = hash;
for (Int32 i = 0; i < salt.Length; i++)
hashSalted[hash.Length + i] = salt;

// Return hash
return Convert.ToBase64String(hashSalted);

} // Hash

Thank You!
Miguel
 
A

Arne Vajhøj

shapper said:
So for saving user passwords on a database I should use Sha256
correct?

I think so.

Several serious weaknesses have been found in MD5, some has been found
in SHA1 and more are expected for SHA1.

Most of these vulnerabilities does not apply to your context of
hashed passwords.

But given that SHA256 is just as easy to use as MD5 and SHA1, then I
would say that: unless you are an expert in cryptography and has read
and understood all the vulnerabilities and are sure they do not apply,
then you should go for a hash algorithm that is considered safe in
general.
UTF8Encoding encoder = new UTF8Encoding();
Byte[] hash = algorithm.ComputeHash(encoder.GetBytes(value));
return BitConverter.ToString(hash).Replace("-", String.Empty);

You could use Encoding.UTF8 instead of new UTF8Encoding.

And you could store the hash as a binary instead of as a string.

Or you could do as you do.

Arne
 
A

Arne Vajhøj

shapper said:
I tried to create the extension with and without salt and with
optional encoding.
I also made the salt as OUT so if the user does not provide a salt
value then it will be generated and updated.
This is useful to save the Salt in a database.

The salt should not be provided by the user. It should be
unpredictable random.
1. Can the salt parameter be a String?

It can.

Just be sure that it can and will take a lot of different values.
Then inside the extension I would convert the salt to bytes[] or
create a random in bytes and at the end convert it to string.
I think it would be more user friendly.

The user should never see that salt, so it does not matter.
2. What is the difference between using SHA256Managed() or
SHA256CryptoServiceProvider() ?

The first is pure .NET while the second calls some Win32 native code.
Which one should I use?

I would use the pure .NET, but I don't think it matters much.

Arne
 
J

Jesse Houwing

* shapper wrote, On 13-9-2009 17:42:
So for saving user passwords on a database I should use Sha256
correct?
I was using MD5 or Sha1 because those were the options on the ASP.NET
Membership providers.
But now I creating my own custom Membership system based only on
FormsAuthentication.

I did a little search and I found a few more options and updated my
code with your suggestions:

public static String Hash(this String value, HashType hashType) {

HashAlgorithm algorithm;
switch (hashType) {
case HashType.MD5:
algorithm = new MD5CryptoServiceProvider();
break;
case HashType.SHA1:
algorithm = new SHA1CryptoServiceProvider();
break;
case HashType.SHA256:
algorithm = new SHA256CryptoServiceProvider();
break;
case HashType.SHA384:
algorithm = new SHA384CryptoServiceProvider();
break;
case HashType.SHA512:
algorithm = new SHA512CryptoServiceProvider();
break;
default:
throw new ArgumentException("Invalid hash type", "type");
}
UTF8Encoding encoder = new UTF8Encoding();
Byte[] hash = algorithm.ComputeHash(encoder.GetBytes(value));
return BitConverter.ToString(hash).Replace("-", String.Empty);

} // Hash

If you notice something wrong, please, let me know.

Thank You,
Miguel

Don't forget that *CryptoServiceProvider classes all implement
IDisposable and should be properly disposed after use!

so

HashAlgorithm algorithm = null;
try
{
.... your code
} finally
{
if (algorithm != mull)
{
algorithm.Dispose();
}
}
 
S

shapper

The salt should not be provided by the user. It should be
unpredictable random.

Yes, I know. When I said provided I meant provided from outside the
extension and not generated inside the extension.
I could also create a new extension/method to create random salts
given a minimum and maximum length.
The user should never see that salt, so it does not matter.

Yes, my intention is more to save it as byte or string in the
database.
I was thinking in string because in ASP.NET Membership providers they
use nvarchar to save the salt.
I would use the pure .NET, but I don't think it matters much.

Ok, I will use the pure.

Thanks,
Miguel
 
S

shapper

This is not good cryptographically, though it is a reasonable teaching
example.  It gives too many options for hash functions, it contains no
stretching/strengthening and it is weak on salts by allowing short
salts and less than random contents.

It is difficult for me to identify what a good example is to follow.
Is this closer of what you mean:
http://www.dijksterhuis.org/creating-salted-hash-values-in-c/

And what do you mean with stretching/strengthening?
In pseudocode:

  generateHashAndSalt( user, password )
    salt <- generateRandomSalt()
    save salt to database indexed by user
    finalHash <- calculateHash( password, salt )
    overwrite password array with zeros
    save finalHash to database indexed by user
  end generateHash

Got it ... At the moment my main problem is creating the Hash / Salt
Algorithm.
What do you mean overwrite password array with zeros? I got lost.
  REPEATS <- 10,000

  byte[] calculateHash( password, salt )
    hash <- SHA256( concatenate( password, salt ) )
    for REPEATS times do
       hash <- SHA256( concatenate( hash, salt ) )
    end for
    return hash
  end calculateHash  

Got it.
All salts should be the same length, 128 bits (16 bytes) is fine.  If
space is very tight in your database then you could drop as far as 64
bits (8 bytes) but that is much less secure.  

I don't have a problem with space. Will follow your advice.
Use a cryptographic RNG; RNGCryptoServiceProvider.GetBytes() is the
obvious method.  Do not use the ordinary Random as that is not
cryptographically secure.

I was am using it on my code taken from the first url I posted:

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(salt);
The value of REPEATS needs to be set so that the hash calculation
takes about 0.25 second on whatever machine you are using.

Ok. First let me try to create the Hash code.
Overwriting the password array is a standard security precaution.  It
is the rough equivalent of displaying the password as asterisks on
screen.

I don't understand ...
To check a hash:

  boolean checkHash( user, password )
    salt <- retrieveSalt( user )
    newHash <- calculateHash( password, salt )
    overwrite password array with zeros
        oldHash <- retrieveHash( user )
    return ( oldHash = newHash )
  end checkHash

Will try when I have the code made.

Thanks,
Miguel
 
S

shapper

Salt must always be present, either generated or retrieved form the
database.  Reduce the number of options available, that way the users
have less chances of picking the wrong options.

I am creating a simple console application and following what you told
me but until now I don't get two equal hashes:

using System;
using System.Text;
using System.Security.Cryptography;

public class Program {

public static void Main(String[] args) {

String password = "password";
Byte[] hash;
Byte[] salt;
Hash(password, out hash, out salt);

String resultHash = Convert.ToBase64String(hash);
String resultSalt = Convert.ToBase64String(salt);

Console.WriteLine("Hash:");
Console.WriteLine(resultHash);
Console.WriteLine("Salt:");
Console.WriteLine(resultSalt);

Byte[] hash2;
Hash(password, out hash2, out salt);

Console.WriteLine("Compares hashes:");
Console.WriteLine((hash == hash2).ToString());
Console.WriteLine("Press any key...");
Console.ReadLine();

} // Main

public static void Hash(String password, out Byte[] hash, out Byte
[] salt) {

Int32 saltLength = 32;

Byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
salt = new Byte[saltLength];

RNGCryptoServiceProvider random = new RNGCryptoServiceProvider
();
random.GetBytes(salt);

Byte[] passwordAndSalt = new Byte[password.Length + saltLength];

Array.Copy(passwordBytes, passwordAndSalt,
passwordBytes.Length);
Array.Copy(salt, 0, passwordAndSalt, passwordBytes.Length,
saltLength);

for (Int32 i = 1; i < 10000; i++) {

}

HashAlgorithm algorithm = new SHA256CryptoServiceProvider();
hash = algorithm.ComputeHash(passwordAndSalt);

} // Hash

} // Program

I am not really sure what I am doing wrong and I am not sure about the
loop you mentioned.
 
S

shapper

Hi,

I added a StopWatch to check the time that it takes in calculation to
check as you mention for 0.25s and tried to implement the loop and
correct the errors but I keep having different hashes at the end.

At the moment this is what I have:


// Namespaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

using System.Security.Cryptography;

public class Program {

public static void Main(String[] args) {

String password = "password";

Byte[] hash = new Byte[32];
Byte[] salt = new Byte[64];

Stopwatch watch = new Stopwatch();
for (Int32 i = 1; i < 10000; i++) {
if (i == 200) watch.Start();
Hash(password, out hash, out salt);
}
watch.Stop();
TimeSpan ts = watch.Elapsed;
String time = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);

Console.WriteLine("");
Console.WriteLine(time);
Console.WriteLine((ts.TotalMilliseconds / (20000 - 200)).ToString
());
Console.WriteLine("");

String resultHash = Convert.ToBase64String(hash);
String resultSalt = Convert.ToBase64String(salt);

Console.WriteLine("");
Console.WriteLine("Hash:");
Console.WriteLine(resultHash);
Console.WriteLine("");
Console.WriteLine("Salt:");
Console.WriteLine(resultSalt);
Console.WriteLine("");

Byte[] hash2;
Hash(password, out hash2, out salt);

Console.WriteLine("");
Console.WriteLine("Compares hashes:");
Console.WriteLine((hash == hash2).ToString());
Console.WriteLine("Press any key...");
Console.ReadLine();

} // Main

public static void Hash(String password, out Byte[] hash, out Byte
[] salt) {

Int32 saltLength = 32;

Byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
salt = new Byte[saltLength];

RNGCryptoServiceProvider random = new RNGCryptoServiceProvider
();
random.GetBytes(salt);

Byte[] passwordAndSalt = new Byte[password.Length + saltLength];

Array.Copy(passwordBytes, passwordAndSalt,
passwordBytes.Length);
Array.Copy(salt, 0, passwordAndSalt, passwordBytes.Length,
saltLength);

HashAlgorithm algorithm = new SHA256CryptoServiceProvider();
hash = algorithm.ComputeHash(passwordAndSalt);

for (Int32 i = 1; i < 10000; i++) {

Array.Copy(salt, hash, salt.Length);
hash = algorithm.ComputeHash(hash);

}
} // Hash
} // Program

Does anyone knows what am I doing wrong?

Thanks,
Miguel
 
P

Peter Duniho

I am creating a simple console application and following what you told
me but until now I don't get two equal hashes:

Why should you get two equal hashes? The input to the hash function isn't
the same (different "salt" each time), so the likelihood of the output
being the same is incredibly low.
[...]
I am not really sure what I am doing wrong and I am not sure about the
loop you mentioned.

He's saying that once you've hashed the original password, to repeat the
algorithm on the hash itself as many times as it takes to spend roughly
1/4 second on the repetitions.

Pete
 
P

Peter Duniho

[...]
HashAlgorithm algorithm = null;
try
{
... your code
} finally
{
if (algorithm != mull)
{
algorithm.Dispose();
}
}

For what it's worth, this is a perfect example of when the "using"
statement is useful. :)

For example:

HashAlgorithm algorithm;

// initialize "algorithm" as needed

using (algorithm)
{
// use "algorithm"
}

Even better is if the selection is factored out into a separate method,
then the initialization of the "algorithm" variable can take place in the
"using" statement itself. (This latter point may be moot once Miguel has
changed his implementation to always use SHA256 :) ).

Pete
 
S

shapper

What do you mean overwrite password array with zeros? I got lost.

Whoops, I missed that bit.

Very simple:

  for (int i = 0; i < password.Length; ++i) {
    password = 0;
  }

Jesse and Peter's suggestion about using using {} or Dispose() is also
excellent.  The general idea is to leave as little as possible
sensitive information in your computer's memory when your program
terminates.

rossum


I am completely lost ... I have been following your tips but I am not
sure if what I have done is ok ... I suspect it isn't.
I am not able to use the watch to check the performance.
I tried to implement the stretching/strengthening by recalling the
ComputHash method.
I implemented IDisposable ... well I tried. :)

I allow to pass the algorithm. Yes, I will use Sha256 but I would like
to leave that option. The same with length.
But I am testing and will use what you suggested me: Sha256 and Salt
with 16 bits

Could, someone, please help me? I am really lost on this.

// Namespaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

// Test
namespace Test {

// Program
public class Program {

// Main
public static void Main(String[] args) {

String password = "hello";
Byte[] data = Encoding.UTF8.GetBytes(password);
Byte[] hash;
Byte[] salt;
SaltedHash test = new SaltedHash(new SHA256CryptoServiceProvider
(), 16);

//Stopwatch watch = new Stopwatch();
//for (Int32 i = 1; i < 1; i++) {
// if (i == 200) watch.Start();
// test.GetHashAndSalt(data, out hash, out salt);
//}
//watch.Stop();
//TimeSpan ts = watch.Elapsed;
//String time = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
//Console.WriteLine("");
//Console.WriteLine(time);
//Console.WriteLine((ts.TotalMilliseconds / (20000 -
200)).ToString());
//Console.WriteLine("");

Console.WriteLine("");
test.GetHashAndSalt(data, out hash, out salt);
Console.WriteLine("Password = {0} , Hash = {1} , Salt = {2}",
Convert.ToBase64String(data), Convert.ToBase64String(hash),
Convert.ToBase64String(salt));
Console.WriteLine("");
Console.WriteLine("");
SaltedHash confirm = new SaltedHash(new
SHA256CryptoServiceProvider(), 32);
confirm.GetHashAndSalt(data, out hash, out salt);
Console.WriteLine("Password = {0} , Hash = {1} , Salt = {2}",
Convert.ToBase64String(data), Convert.ToBase64String(hash),
Convert.ToBase64String(salt));
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("Press any key...");
Console.ReadLine();

} // Main


public class SaltedHash : IDisposable {

private HashAlgorithm HashProvider;
private Int32 SalthLength;

public SaltedHash(HashAlgorithm hashAlgorithm, Int32 saltLength)
{
HashProvider = hashAlgorithm;
SalthLength = saltLength;
}

public SaltedHash() : this(new SHA256Managed(), 16) { }

// GetHashAndSalt
public void GetHashAndSalt(Byte[] Data, out Byte[] Hash, out Byte
[] Salt) {

using (HashProvider) {

Salt = new byte[SalthLength];
RNGCryptoServiceProvider random = new
RNGCryptoServiceProvider();
random.GetNonZeroBytes(Salt);
Hash = ComputeHash(Data, Salt);

for (Int32 i = 1; i < 1000; i++) {
Hash = ComputeHash(Hash, Salt);
}

for (Int32 j = 0; j < Data.Length; ++j) {
Data[j] = 0;
}

}
} // GetHashAndSalt

// ComputeHash
private Byte[] ComputeHash(Byte[] Data, Byte[] Salt) {

Byte[] DataAndSalt = new Byte[Data.Length + SalthLength];

Array.Copy(Data, DataAndSalt, Data.Length);
Array.Copy(Salt, 0, DataAndSalt, Data.Length, SalthLength);

return HashProvider.ComputeHash(DataAndSalt);

} // ComputeHash

// Dispose
public void Dispose() {
this.Dispose();
GC.SuppressFinalize(this);
} // Dispose

}

} // Program
} // Test
 
S

shapper

A side note adding to the code I just posted:

I will save the password and salt as binary on Users SQL table as
suggested before. I am planning to use the following:
Password varbinary(128) not null,
Salt varbinary(128) not null

Do you think it is ok?

Thanks,
Miguel
 
A

Arne Vajhøj

rossum said:
The value of REPEATS needs to be set so that the hash calculation
takes about 0.25 second on whatever machine you are using.

That comes as a cost.

4 logins (attempts) per second cost a CPU core.

For high volume it costs. And besides the increase in DoS
vulnerability may be more important than the added protection
against exploiting a stolen database.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top