C#: How to generate short MD5 code? - c#

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

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.

Size of MD5 hash generated

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.

Can someone explain how BCrypt verifies a hash?

I'm using C# and BCrypt.Net to hash my passwords.
For example:
string salt = BCrypt.Net.BCrypt.GenerateSalt(6);
var hashedPassword = BCrypt.Net.BCrypt.HashPassword("password", salt);
//This evaluates to True. How? I'm not telling it the salt anywhere, nor
//is it a member of a BCrypt instance because there IS NO BCRYPT INSTANCE.
Console.WriteLine(BCrypt.Net.BCrypt.Verify("password", hashedPassword));
Console.WriteLine(hashedPassword);
How is BCrypt verifying the password with the hash if it's not saving the salt anywhere. The only idea I have is that it's somehow appending the salt at the end of the hash.
Is this a correct assumption?
A BCrypt hash string looks like:
$2a$10$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
\__/\/ \____________________/\_____________________________/
| | Salt Hash
| Cost
Version
Where
2a: Algorithm Identifier (BCrypt, UTF8 encoded password, null terminated)
10: Cost Factor (210 = 1,024 rounds)
Ro0CUfOqk6cXEKf3dyaM7O: OpenBSD-Base64 encoded salt (22 characters, 16 bytes)
hSCvnwM9s4wIX9JeLapehKK5YdLxKcm: OpenBSD-Base64 encoded hash (31 characters, 24 bytes)
Edit: i just noticed these words fit exactly. i had to share:
$2a$10$TwentytwocharactersaltThirtyonecharacterspasswordhash
$==$==$======================-------------------------------
BCrypt does create a 24-byte binary hash, using 16-byte salt. You're free to store the binary hash and the salt however you like; nothing says you have to base-64 encode it into a string.
But BCrypt was created by guys who were working on OpenBSD. OpenBSD already defines a format for their password file:
$[HashAlgorithmIdentifier]$[AlgorithmSpecificData]
This means that the "bcrypt specification" is inexorably linked to the OpenBSD password file format. And whenever anyone creates a "bcrypt hash" they always convert it to an ISO-8859-1 string of the format:
$2a$[Cost]$[Base64Salt][Base64Hash]
A few important points:
2a is the algorithm identifier
1: MD5
2: early bcrypt, which had confusion over which encoding passwords are in (obsolete)
2a: current bcrypt, which specifies passwords as UTF-8 encoded
Cost is a cost factor used when computing the hash. The "current" value is 10, meaning the internal key setup goes through 1,024 rounds
10: 210 = 1,024 iterations
11: 211 = 2,048 iterations
12: 212 = 4,096 iterations
the base64 algorithm used by the OpenBSD password file is not the same Base64 encoding that everybody else uses; they have their own:
Regular Base64 Alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
BSD Base64 Alphabet: ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
So any implementations of bcrypt cannot use any built-in, or standard, base64 library
Armed with this knowledge, you can now verify a password correctbatteryhorsestapler against the saved hash:
$2a$12$mACnM5lzNigHMaf7O1py1O3vlf6.BA8k8x3IoJ.Tq3IB/2e7g61Km
BCrypt variants
There is a lot of confusion around the bcrypt versions.
$2$
BCrypt was designed by the OpenBSD people. It was designed to hash passwords for storage in the OpenBSD password file. Hashed passwords are stored with a prefix to identify the algorithm used. BCrypt got the prefix $2$.
This was in contrast to the other algorithm prefixes:
$1$: MD5
$5$: SHA-256
$6$: SHA-512
$2a$
The original BCrypt specification did not define how to handle non-ASCII characters, or how to handle a null terminator. The specification was revised to specify that when hashing strings:
the string must be UTF-8 encoded
the null terminator must be included
$2x$, $2y$ (June 2011)
A bug was discovered in crypt_blowfish🕗, a PHP implementation of BCrypt. It was mis-handling characters with the 8th bit set.
They suggested that system administrators update their existing password database, replacing $2a$ with $2x$, to indicate that those hashes are bad (and need to use the old broken algorithm). They also suggested the idea of having crypt_blowfish emit $2y$ for hashes generated by the fixed algorithm. Nobody else, including canonical OpenBSD, adopted the idea of 2x/2y. This version marker was was limited to crypt_blowfish🕗.
The versions $2x$ and $2y$ are not "better" or "stronger" than $2a$. They are remnants of one particular buggy implementation of BCrypt.
$2b$ (February 2014)
A bug was discovered in the OpenBSD implementation of BCrypt. They wrote their implementation in a language that doesn't have support strings - so they were faking it with a length-prefix, a pointer to a character, and then indexing that pointer with []. Unfortunately they were storing the length of their strings in an unsigned char. If a password was longer than 255 characters, it would overflow and wrap at 255. BCrypt was created for OpenBSD. When they have a bug in their library, they decided its ok to bump the version. This means that everyone else needs to follow suit if you want to remain current to "their" specification.
http://undeadly.org/cgi?action=article&sid=20140224132743 🕗
http://marc.info/?l=openbsd-misc&m=139320023202696 🕗
There is no difference between 2a, 2x, 2y, and 2b. If you wrote your implementation correctly, they all output the same result.
If you were doing the right thing from the beginning (storing strings in utf8 and also hashing the null terminator) then: there is no difference between 2, 2a, 2x, 2y, and 2b. If you wrote your implementation correctly, they all output the same result.
The version $2b$ is not "better" or "stronger" than $2a$. It is a remnant of one particular buggy implementation of BCrypt. But since BCrypt canonically belongs to OpenBSD, they get to change the version marker to whatever they want.
The versions $2x$ and $2y$ are not better, or even preferable, to anything. They are remnants of a buggy implementation - and should summarily forgotten.
The only people who need to care about 2x and 2y are those you may have been using crypt_blowfish back in 2011. And the only people who need to care about 2b are those who may have been running OpenBSD.
All other correct implementations are identical and correct.
How is BCrypt verifying the password with the hash if it's not saving the salt anywhere?
Clearly it is not doing any such thing. The salt has to be saved somewhere.
Let's look up password encryption schemes on Wikipedia. From http://en.wikipedia.org/wiki/Crypt_(Unix) :
The output of the function is not merely the hash: it is a text string which also encodes the salt and identifies the hash algorithm used.
Alternatively, an answer to your previous question on this subject included a link to the source code. The relevant section of the source code is:
StringBuilder rs = new StringBuilder();
rs.Append("$2");
if (minor >= 'a') {
rs.Append(minor);
}
rs.Append('$');
if (rounds < 10) {
rs.Append('0');
}
rs.Append(rounds);
rs.Append('$');
rs.Append(EncodeBase64(saltBytes, saltBytes.Length));
rs.Append(EncodeBase64(hashed,(bf_crypt_ciphertext.Length * 4) - 1));
return rs.ToString();
Clearly the returned string is version information, followed by the number of rounds used, followed by the salt encoded as base64, followed by the hash encoded as base64.

Categories

Resources