Size of MD5 hash generated - c#

I would be using MD5 hashing to store encrypted passwords. Password can be 6 to 40 characters long. What is the database column size required for storing the encrypted password. Also, if 40 characters hash size is very large, then how much hash size would a 20 character password take?
I am using FormsAuthentication.HashPasswordForStoringInConfigFile(stringToEncrypt, "MD5"); to generate hash for storing in Database.

A hash algorithm always maps an arbitrary sized message to a fixed-length representation. In other words, you can hash an empty string or many gigabytes of information. The hash size is always fixed.
In your case the hash size is 128 bits. When converted to an ASCII string it would be a 32 character string that contains only hexadecimal digits.

http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx
The hash size for the MD5 algorithm is 128 bits, regardless of the length of the string being hashed.
Consider using a newer hashing functions like SHA 256.

MD5 hashes are always exactly 16 bytes (128 bits) long, no matter how long the input is.

Related

Generate a 128 length of hashed string c#

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).

What is the maximum length of hashed passwords using the HMACSHA1 algorithm

I want to hash passwords before storing them to the database. There are many samples out there on how to hash passwords, the following C# code from the docs relies on the HMACSHA1 algorithm:
public static void Main(string[] args)
{
Console.Write("Enter a password: ");
string password = Console.ReadLine();
// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");
// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA1,
iterationCount: 10000,
numBytesRequested: 256 / 8));
Console.WriteLine($"Hashed: {hashed}");
}
I would like to know if there is a way to determine the length of the password hash based on the length of the password. So if the user has a password with a length of x is there a way to calculate the length of the hash?
I want to know it because in my database the password column currently is a varchar taking 128 characters. The REST API built on top of it should restrict the password length so that the database will never crash because the password is too long and generates a password hash longer than 128 characters.
Or is it best practise to say the database column is a varchar of 256 characters and the API only allows passwords smaller or equal than 30 characters so it will never hit the limit?
It would be nice if the answer is independent from the code language, this is more a question in general.
The output of PBKDF2 can be specified. A PBKDF is a password based key derivation function. Generally those have a key expansion phase that allows the output to be specified.
However, if PBKDF2 is used as password hash rather than for key derivation the size of the configured hash is kept; that provides the maximum security that can be retrieved from the algorithm. In this case that's SHA-1 that generates 160 bits / 20 bytes.
Unless you really need text, the output can be stored as static binary of 20 bytes. In your case you should be storing it as base 64 version of the 20 bytes. That should amount to a fixed 28 bytes: ((20 + 2) / 3) * 4 = 28 to calculate the base 64 expansion. However, your code explicitly specifies the output size to be 256 / 8 = 64 bytes. A quick calculation suggests that it always uses 88 base 64 characters for that size.
Producing 64 bytes while using SHA-1 is not a good setting because it requires the inner function of PBKDF2 to run 4 times, giving you no advantage of running it only once to produce 20 bytes, giving advantage to an attacker. An attacker only has to check the first 20 bytes to make sure a password matches, after all, and for that only one of the four runs is required. The method that PBKDF2 uses to expand the key size over the hash size is really inefficient and may be considered a design flaw.
On the other hand, 10.000 iterations is not very high. You should, for PBKDF2:
specify the output size of the underlying hash as output size (20 bytes instead of 64 bytes for SHA-1) and
use a higher number of iterations (limited by how much CPU time you can spend in PBKDF2).
The size of the password doesn't have any influence on the size of the password hash.
Beware that some password hashes on other runtimes create a password hash string themselves, more compatible with crypt on Unix systems. So they would have a larger output that is not directly compatible.

C# AES-256 Unicode Key

I need to make strong key for AES-256 in a) Unicode characters, b) key in bytes.
a) I have to generate 50 random Unicode characters and then convert them to bytes. Is this possible to use Unicode characters as AES256 key?
For e.g. I want to use this page to create password.
is there any way to import all characters from Windows characters table to program in Windows Form App?
b) I'm using this code:
System.Security.Cryptography.AesCryptoServiceProvider key = new System.Security.Cryptography.AesCryptoServiceProvider();
key.KeySize = 256;
key.GenerateKey();
byte[] AESkey = key.Key;
It's enough or I should change something?
Also I have one more question. Making an AES key longer then 43 ASCII characters will be more secure or it will be anyway hashed to 256bit? And there is difference between ASCII key of 43 characters and 100?
a) I have to generate 50 random Unicode characters and then convert them to bytes. Is this possible to use Unicode characters as AES256 key?
Yes, this is possible. Since you have plenty of space for characters you can just encode it. ceil(32 / 3) * 4 = 44, so you'd have enough characters for this. You would not be using the additional space provided by Unicode encoding though. Obviously you would need to convert it back to binary before using it.
b) is aes.GenerateKey "enough"?
Yes, aes.GenerateKey is enough to generate a binary AES key.
c) Making an AES key longer then 43 ASCII characters will be more secure or it will be anyway hashed to 256bit? And there is difference between ASCII key of 43 characters and 100?
An AES key is not hashed at all. It's just 128, 192 or 256 bits (i.e. 16, 24 or 32 bytes) of data that should be indistinguishable from random (to somebody that doesn't know the value, of course). If you want to hash something you'd have to do it yourself - but please read on.
The important thing to understand is that a password is not a key, and that keys for modern ciphers are almost always encoded as binary. For AES there is no such thing as an ASCII key. If you need to encode the key, use base 64.
If you want to use a password then you need to use a key derivation function or KDF. Furthermore, if you want to protect against dictionary and rainbow table attacks you will want to use a password based key derivation function or PBKDF. Such a KDF is also called a "password hash". In case of .NET your best bet is Rfc2898DeriveBytes which implements PBKDF2. PBKDF2 is defined in the RFC
2898 titled: PKCS #5: Password-Based Cryptography Specification Version 2.0 which you may want to read.

Generate a printable HMAC Shared key in .Net

I'm using HMACSHA512 to hash data using a shared key. Since the key is shared I'd like for it to be all printable characters for ease of transport. I'm wondering what the best approach is to generating these keys.
I'm currently using the GetBytes() method of RNGCryptoServiceProvider to generate a key, but the byte array it returns contains non-printable characters. So I'm wondering if it is secure to base64 encode the result or does that erode the randomness too much and make things much less secure? If that isn't a good approach can you suggest one?
I do understand that by limiting the keys to printable characters I am limiting the overall breadth of the key space (ie: lopping off 1 of the 8 bits), but I am OK with that.
If you can handle not auto-generating the key then http://www.grc.com/passwords is a good source of VERY random key material.
Base64 wouldn't reduce the underlying entropy of the byte array. You could generate the key and use it in its raw form, but Base64 encode it to transport it to where you need it to be. You'd then Base64 decode it back to the raw form before you use it in the new location. There is no loss of entropy in this operation. The Base64 encoding reduces the entropy to 6-bits per byte instead of 8, but the result of the coding is longer, so overall the entropy is the same.
The other way you could do it would be to get 24 random bytes for 192-bits worth of entropy. Base64 encoding this would give you a 32 character string (256-bits) which still has the original randomness and 192-bits of entropy. You could use this as your shared key directly.
BASE64 transforms a byte sequence so it uses only certain printable characters.
This transformation does not change the information in any way, just how it is stored. It is also reversible: you can get the original byte sequence by decoding the BASE64 output.
So using BASE64 does not "erode the randomness" or limit the key space in any way.

C#: How to generate short MD5 code?

When I am encrypting 23 using MD5 encryption I am getting 37693cfc748049e45d87b8c7d8b9aacd this 32-character long string which will always be static for 23.
I want the same kind of mechanism but that should generate 18 or less (like: 122ff1e4883358b6) characters long string instead 32.
How I can do that in C#, is there any shorter version of MD5 in c#??
I like #RichieHindle's answer. However, if you're interested in losing fewer bits of fidelity (and thereby decreasing the risk of collisions), you could take the 128 bit value returned by the MD5 Hash, and encode it using ASCII85 (also known as Base85 encoding), instead of a hexadecimal-based encoding. This will give you the whole hash in 20 bytes (which is more than you wanted, but you could chop 2 bytes off, resulting in much less loss than removing 14 of the 32 bytes you'd get using hex encoding).
Edit: Prashant says 20 characters is close enough, and asked for sample code:
After obtaining the MD5 hash from the MD5.ComputeHash call, you can use Jeff Atwood's ASCII85 encoder:
MD5 m = MD5.Create();
byte[] hash = m.ComputeHash(System.Text.Encoding.ASCII.GetBytes("23"));
Ascii85 encoder = new Ascii85();
encoder.EnforceMarks = false;
string hash85 = encoder.Encode(hash);
Console.Out.WriteLine(hash85);
Yields
2ebDPFFZsD?&,r1fX\$,
so you can just use hash85. The encoder.EnforceMarks makes sure that the encoding doesn't include some typical prefix and suffixes that are associated with ASCII85.
You can just take as much of the MD5 hash as you need, and throw the rest away. All the bits have equal value, so there's no difference between doing that and using some hashing algorithm that natively produces fewer bits.
(If you're doing this for security reasons, remember that fewer bits makes hashes easier to crack, regardless of the algorithm. Even outside of security applications, fewer bits increase the risk of collisions. Also bear in mind that MD5 is relative insecure these days - SHA-1 or SHA-2 are considered more secure.)
MD5 always creates a 128 Bit Hash.
Other smaller Hashtypes (taken from Wikipedia)
Fowler-Noll-Vo hash function (32, 64, 128, 256, 512, or 1024 bits)
Jenkins hash function (32 bits)
MurmurHash (32 or 64 bits)
Pearson hashing (8 bits)
But remember hash collisions
I wouldn't use a hash function if you want to be able to map the result back to its original value without collisions.
If your aim is to turn a small decimal number into a long obfuscated string, just invent some mapping algorithm and encode the result with zBase32 or similar.
public string Obfuscate(long x)
{
return ToZBase32(BitConverter.GetBytes(x * 63498398L));
}
public long Deobfuscate(string x)
{
return BitConverter.ToInt64(FromZBase32(x)) / 63498398L;
}
23 gets encoded to "gmuyaiayyyyyy". (63498398 chosen by fair dice roll.)
Use FVNHash - http://www.codeproject.com/KB/security/FnvHash.aspx
You can set the length of your hash, do not use it for security reasons.
shortest useful hash algorithm would be md5 . generates 16 bytes=128 bit hash. if you use base 64 encoding ...that is 6 useful bits per byte/char.
u should be able to reduce the md5 to 22 characters (ascii). what you have is hex version where 2 bytes represent one actual byte
(leaving the trailing padding introduced by b64)
with an added advantage of using the same for legal filenames. (ofcourse u will have to substitute the default / and + characters with any other symbol which does not clash with file naming convention of your os.
base64 (by replacing / and +) ensures your hash doesnot mess up the url with special characters which may mean something else to your webserver
ASCII85 adds characters which are difficult to deal with when using as filenames and in urls
md5 ('This string will be hashed')
'37aa3296c523f6c5a7fd2102a9155dcc' (hex) (32 bytes)
raw md5 ('This string will be hashed')
[55, 170, 50, 150, 197, 35, 246, 197, 167, 253, 33, 2, 169, 21, 93, 204] = (16 Bytes)
base64 of raw md5 string
N6oylsUj9sWn_SECqRVdzA==
My Final Hash
N6oylsUj9sWn_SECqRVdzA this is actually the complete md5 in 22 ascii characters
([you can strip the two trailing = there will always be two for md5-add them later when decoding. also replace + and / characters in b64 with any other i prefer -(dash) and _ (underscore) ]
this 32-character long string are number from hexadecimal : 0-f
you can make it shorter by converting its hexadecimal value to radix of 36 : 0-z

Categories

Resources