C# Faster generation of MD5 hashes - c#

I have a project where I have been given a MD5 hash of a number between 1 and 2 billion, and I have to write a distributed program which obtains the number by brute force. I have successfully coded this program and it works. I was wondering if there is a way to speed up the generation of hashes?
Here is my current function to generate the hashes:
static string generateHash(string input)
{
MD5 md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
return sBuilder.ToString();
}
Thanks for any help

You could use BitConverter.ToString
static string generateHash(string input)
{
MD5 md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
return BitConverter.ToString(data);
}

Related

Generating different keys with Rfc2898DeriveBytes in c# and pbkdf2 in go

Here is the C# sample code to verify the hash password.
Salt size is 8 which generates random bytes, 10000 time Iteration and Hash size is 20.
public static bool VerifyHashedString(string inputString, string hashedString)
{
try
{
byte[] hashBytes = Convert.FromBase64String(hashedString);
var salt = new byte[8];
Array.Copy(hashBytes, 0, salt, 0, 8);
var pbkdf2 = new Rfc2898DeriveBytes(inputString, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
for (var i = 0; i < 20; i++)
{
if (hashBytes[i + 8] != hash[i])
{
return false;
}
}
return true;
}
catch
{
return false;
}
}
And I am using following code to verify in golang - please find the link
https://github.com/anaskhan96/go-password-encoder
but I am not able to match hash text
what could be the reason ?
Following are the observation Hash password length varies.
in C# KwLur0TzENvIVUmvTg0gqPUh+Jkndlu2bH7L8g==
in Golang KETc4Dp1kZzPC6pdePc5OQyDXLA=

MD5 hash special characters

I have tried hashing a string in PHP using MD5 and the same in C#, but the results are different if the string contains special characters. Can someone explain me how to get this matched?
Here is my code in C#:
MD5 md5 = new MD5CryptoServiceProvider();
//compute hash from the bytes of text
md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(text));
//get hash result after compute it
byte[] result = md5.Hash;
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < result.Length; i++)
{
//change it into 2 hexadecimal digits
//for each byte
strBuilder.Append(result[i].ToString("x2"));
}
return strBuilder.ToString();
My string is "Samuel2989&*" as a string.
Outputs:
PHP: 957915b9c9a8fb65e13fe1dc9a8b86d4
C# : f5ee451f7eb4587da00d4aa31ae1c378
Can you try with this method and tell me if it worked out for you?
public static string MD5Hash(string input)
{
System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
bs = x.ComputeHash(bs);
System.Text.StringBuilder s = new System.Text.StringBuilder();
foreach (byte b in bs)
{
s.Append(b.ToString("x2").ToLower());
}
string password = s.ToString();
return password;
}

save hash value in the database

i used this functions to compute the hash value:
public string GetSHA512(string input)
{
byte[] data, result;
StringBuilder hash = new StringBuilder();
data = Encoding.UTF8.GetBytes(input);
using (SHA512 shaM = new SHA512Managed())
{
result = shaM.ComputeHash(data);
}
for (int i = 0; i < result.Length; i++)
{
hash.Append(result[i].ToString());
}
return hash.ToString();
}
public string GetSHA256(string input)
{
byte[] data, result;
StringBuilder hash = new StringBuilder();
data = Encoding.UTF8.GetBytes(input);
using (SHA256 shaM = new SHA256Managed())
{
result = shaM.ComputeHash(data);
}
for (int i = 0; i < result.Length; i++)
{
hash.Append(result[i].ToString());
}
return hash.ToString();
}
public string GetSHA1(string input)
{
byte[] data, result;
StringBuilder hash = new StringBuilder();
data = Encoding.UTF8.GetBytes(input);
using (SHA1 shaM = new SHA1Managed())
{
result = shaM.ComputeHash(data);
}
for (int i = 0; i < result.Length; i++)
{
hash.Append(result[i].ToString());
}
return hash.ToString();
}
public string GetMD5(string input)
{
byte[] data, result;
StringBuilder hash = new StringBuilder();
data = Encoding.UTF8.GetBytes(input);
using (MD5 shaM = new MD5CryptoServiceProvider())
{
result = shaM.ComputeHash(data);
}
for (int i = 0; i < result.Length; i++)
{
hash.Append(result[i].ToString());
}
return hash.ToString();
}
but now i have few questions:
hash functions are supposed to create the fix output length for any kind of strings.(no matter my input length is 4 or 10000 the output always has a fix size) aren't they? but when my input length changes the output length changes too!! i guess my hash functions doesn't work.
if i want save the result in the database, my hash value filed type should be what?
which one of the hash functions usually used in web applications?
thank you.
Currently you're just returning the decimal representation of all the bytes, concatenated together. So { 0, 0, 0 } ends up as "000" whereas { 123, 123, 123 } ends up as "123123123". So yes, both those hashes will give the same output size for any input (SHA-1 will give 20 bytes; MD5 will give 16) but your string representations will currently vary in length.
I would recommend using either a hex representation or base64 - in particular, base64 requires rather less work:
public string GetSHA1(string input)
{
byte[] data = Encoding.UTF8.GetBytes(input);
using (SHA512 shaM = new SHA512Managed())
{
byte[] result = shaM.ComputeHash(data);
return Convert.ToBase64String(result);
}
}
Hex has the advantage of being a more common way of representing hashes. (Base64 is more usually used for transporting arbitrary binary data, e.g. images.) For hex, you could use:
return BitConverter.ToString(result).Replace("-", "");
(Note that I've declared local variables - you appear to be using fields for data and result, which is a bad idea - calling these methods shouldn't affect the state of the instance, IMO.)
Alternatively, you could just return a byte[] and store that directly in the database as a blob. Using base64 or hex is probably simpler though - it's easier to examine the data that way, and frankly easier to query. Strings are just simpler to handle :)
In terms of which hash you should use - I probably wouldn't use either SHA-1 or MD5 unless I had to; I'd default to SHA-256, although it depends on what you're trying to do. If this is hashing passwords for example, you probably want an HMAC of some description - or better yet, don't roll your own, and use an off-the-shelf authentication package.
Each hash algorithm (md5/sha1/etc) has its own fixed size;
Don't convert the output hash to string, keep it as byte[].
In order to store the hash, create a blob column in your db and use SQLParameter to insert it properly
The common practise is to convert the byte array of the hashcode to a base64 encoding, with ToBase64String()
This is how passwords are stored too. The base64 encoding is a string of fixed length, given a fixed number of bytes. It takes 4 characters for each 3 bytes, plus some padding

Convert string with HASH MD5 to ToBase64String

this is my problem,
i have this code that accepts clean text with passwords and returns Base64MD5 hashes
private static string GetMd5Base64Pass(string userpwd)
{
MD5 md5 = new MD5CryptoServiceProvider();
return Convert.ToBase64String(md5.ComputeHash(Encoding.ASCII.GetBytes(userpwd)));
}
And i need to reuse it to accept MD5 string hashes and return in Base64MD5.
i tried to do this:
private static string GetMd5Base64PassMD5(string userpwd)
{
MD5 md5 = new MD5CryptoServiceProvider();
return Convert.ToBase64String(Encoding.ASCII.GetBytes(userpwd));
}
but the returns are completely different.
already tried to convert the string to bytearray, didn't work.
I need to insert one string with 32bits MD5, and return it in Base64String.
thks
------------------------------ Edited
Example:
Password is 123123:
MD5 is: 4297f44b13955235245b2497399d7a93
Base64String of MD5 is: Qpf0SxOVUjUkWySXOZ16kw==
I need to get
this: Qpf0SxOVUjUkWySXOZ16kw==
from
this hash string
4297f44b13955235245b2497399d7a93
public static string ConvertHexStringToBase64(string hexString)
{
byte[] buffer = new byte[hexString.Length / 2];
for (int i = 0; i < hexString.Length; i++)
{
buffer[i / 2] = Convert.ToByte(Convert.ToInt32(hexString.Substring(i, 2), 16));
i += 1;
}
string res = Convert.ToBase64String(buffer);
return res;
}
this receives md5 string hashes and transforms it to Base64 Hex

Calculate a MD5 hash from a string

I use the following C# code to calculate a MD5 hash from a string.
It works well and generates a 32-character hex string like this:
900150983cd24fb0d6963f7d28e17f72
string sSourceData;
byte[] tmpSource;
byte[] tmpHash;
sSourceData = "MySourceData";
//Create a byte array from source data.
tmpSource = ASCIIEncoding.ASCII.GetBytes(sSourceData);
tmpHash = new MD5CryptoServiceProvider().ComputeHash(tmpSource);
// and then convert tmpHash to string...
Is there a way to use code like this to generate a 16-character hex string (or 12-character string)? A 32-character hex string is good but I think it'll be boring for the customer to enter the code!
As per MSDN
Create MD5:
public static string CreateMD5(string input)
{
// Use input string to calculate MD5 hash
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
return Convert.ToHexString(hashBytes); // .NET 5 +
// Convert the byte array to hexadecimal string prior to .NET 5
// StringBuilder sb = new System.Text.StringBuilder();
// for (int i = 0; i < hashBytes.Length; i++)
// {
// sb.Append(hashBytes[i].ToString("X2"));
// }
// return sb.ToString();
}
}
// given, a password in a string
string password = #"1234abcd";
// byte array representation of that string
byte[] encodedPassword = new UTF8Encoding().GetBytes(password);
// need MD5 to calculate the hash
byte[] hash = ((HashAlgorithm) CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);
// string representation (similar to UNIX format)
string encoded = BitConverter.ToString(hash)
// without dashes
.Replace("-", string.Empty)
// make lowercase
.ToLower();
// encoded contains the hash you want
Was trying to create a string representation of MD5 hash using LINQ, however, none of the answers were LINQ solutions, therefore adding this to the smorgasbord of available solutions.
string result;
using (MD5 hash = MD5.Create())
{
result = String.Join
(
"",
from ba in hash.ComputeHash
(
Encoding.UTF8.GetBytes(observedText)
)
select ba.ToString("x2")
);
}
You can use Convert.ToBase64String to convert 16 byte output of MD5 to a ~24 char string. A little bit better without reducing security. (j9JIbSY8HuT89/pwdC8jlw== for your example)
Depends entirely on what you are trying to achieve. Technically, you could just take the first 12 characters from the result of the MD5 hash, but the specification of MD5 is to generate a 32 char one.
Reducing the size of the hash reduces the security, and increases the chance of collisions and the system being broken.
Perhaps if you let us know more about what you are trying to achieve we may be able to assist more.
I suppose it is better to use UTF-8 encoding in the string MD5.
public static string MD5(this string s)
{
using var provider = System.Security.Cryptography.MD5.Create();
StringBuilder builder = new StringBuilder();
foreach (byte b in provider.ComputeHash(Encoding.UTF8.GetBytes(s)))
builder.Append(b.ToString("x2").ToLower());
return builder.ToString();
}
public static string Md5(string input, bool isLowercase = false)
{
using (var md5 = MD5.Create())
{
var byteHash = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
var hash = BitConverter.ToString(byteHash).Replace("-", "");
return (isLowercase) ? hash.ToLower() : hash;
}
}
Support string and file stream.
examples
string hashString = EasyMD5.Hash("My String");
string hashFile = EasyMD5.Hash(System.IO.File.OpenRead("myFile.txt"));
-
class EasyMD5
{
private static string GetMd5Hash(byte[] data)
{
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
sBuilder.Append(data[i].ToString("x2"));
return sBuilder.ToString();
}
private static bool VerifyMd5Hash(byte[] data, string hash)
{
return 0 == StringComparer.OrdinalIgnoreCase.Compare(GetMd5Hash(data), hash);
}
public static string Hash(string data)
{
using (var md5 = MD5.Create())
return GetMd5Hash(md5.ComputeHash(Encoding.UTF8.GetBytes(data)));
}
public static string Hash(FileStream data)
{
using (var md5 = MD5.Create())
return GetMd5Hash(md5.ComputeHash(data));
}
public static bool Verify(string data, string hash)
{
using (var md5 = MD5.Create())
return VerifyMd5Hash(md5.ComputeHash(Encoding.UTF8.GetBytes(data)), hash);
}
public static bool Verify(FileStream data, string hash)
{
using (var md5 = MD5.Create())
return VerifyMd5Hash(md5.ComputeHash(data), hash);
}
}
Idk anything about 16 character hex strings....
using System;
using System.Security.Cryptography;
using System.Text;
But here is mine for creating MD5 hash in one line.
string hash = BitConverter.ToString(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes("THIS STRING TO MD5"))).Replace("-","");
This solution requires c# 8 and takes advantage of Span<T>. Note, you would still need to call .Replace("-", string.Empty).ToLowerInvariant() to format the result if necessary.
public static string CreateMD5(ReadOnlySpan<char> input)
{
var encoding = System.Text.Encoding.UTF8;
var inputByteCount = encoding.GetByteCount(input);
using var md5 = System.Security.Cryptography.MD5.Create();
Span<byte> bytes = inputByteCount < 1024
? stackalloc byte[inputByteCount]
: new byte[inputByteCount];
Span<byte> destination = stackalloc byte[md5.HashSize / 8];
encoding.GetBytes(input, bytes);
// checking the result is not required because this only returns false if "(destination.Length < HashSizeValue/8)", which is never true in this case
md5.TryComputeHash(bytes, destination, out int _bytesWritten);
return BitConverter.ToString(destination.ToArray());
}
Here is my utility function for UTF8, which can be replaced with ASCII if desired:
public static byte[] MD5Hash(string message)
{
return MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(message));
}
A MD5 hash is 128 bits, so you can't represent it in hex with less than 32 characters...
System.Text.StringBuilder hash = new System.Text.StringBuilder();
System.Security.Cryptography.MD5CryptoServiceProvider md5provider = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] bytes = md5provider.ComputeHash(new System.Text.UTF8Encoding().GetBytes(YourEntryString));
for (int i = 0; i < bytes.Length; i++)
{
hash.Append(bytes[i].ToString("x2")); //lowerCase; X2 if uppercase desired
}
return hash.ToString();
A faster alternative of existing answer for .NET Core 2.1 and higher:
public static string CreateMD5(string s)
{
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
var encoding = Encoding.ASCII;
var data = encoding.GetBytes(s);
Span<byte> hashBytes = stackalloc byte[16];
md5.TryComputeHash(data, hashBytes, out int written);
if(written != hashBytes.Length)
throw new OverflowException();
Span<char> stringBuffer = stackalloc char[32];
for (int i = 0; i < hashBytes.Length; i++)
{
hashBytes[i].TryFormat(stringBuffer.Slice(2 * i), out _, "x2");
}
return new string(stringBuffer);
}
}
You can optimize it even more if you are sure that your strings are small enough and replace encoding.GetBytes by unsafe int GetBytes(ReadOnlySpan chars, Span bytes) alternative.
Extending Anant Dabhi's answer
a helper method:
using System.Text;
namespace XYZ.Helpers
{
public static class EncryptionHelper
{
public static string ToMD5(this string input)
{
// Use input string to calculate MD5 hash
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
}
return sb.ToString();
}
}
}
}
I'd like to offer an alternative that appears to perform at least 10% faster than craigdfrench's answer in my tests (.NET 4.7.2):
public static string GetMD5Hash(string text)
{
using ( var md5 = MD5.Create() )
{
byte[] computedHash = md5.ComputeHash( Encoding.UTF8.GetBytes(text) );
return new System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary(computedHash).ToString();
}
}
If you prefer to have using System.Runtime.Remoting.Metadata.W3cXsd2001; at the top, the method body can be made an easier to read one-liner:
using ( var md5 = MD5.Create() )
{
return new SoapHexBinary( md5.ComputeHash( Encoding.UTF8.GetBytes(text) ) ).ToString();
}
Obvious enough, but for completeness, in OP's context it would be used as:
sSourceData = "MySourceData";
tmpHash = GetMD5Hash(sSourceData);
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.md5?view=netframework-4.7.2
using System;
using System.Security.Cryptography;
using System.Text;
static string GetMd5Hash(string input)
{
using (MD5 md5Hash = MD5.Create())
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
}
// Verify a hash against a string.
static bool VerifyMd5Hash(string input, string hash)
{
// Hash the input.
string hashOfInput = GetMd5Hash(input);
// Create a StringComparer an compare the hashes.
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
return 0 == comparer.Compare(hashOfInput, hash);
}
StringBuilder sb= new StringBuilder();
for (int i = 0; i < tmpHash.Length; i++)
{
sb.Append(tmpHash[i].ToString("x2"));
}
public static string GetMD5(string encryptString)
{
var passByteCrypt = new MD5CryptoServiceProvider().ComputeHash(Encoding.UTF8.GetBytes(encryptString));
return ByteArrayToString(passByteCrypt);
}
public static string ByteArrayToString(byte[] bytes)
{
var output = new StringBuilder(bytes.Length);
foreach (var t in bytes)
{
output.Append(t.ToString("X2"));
}
return output.ToString().ToLower();
}
this is simple md5 ByteCrypt
If you are using a version lower than .NET5 this is a neat way to write it
string.Concat(yourHashBytes.Select(x => x.ToString("X2")))
Here is a condensed version.
private string CreateMD5(string myText)
{
var hash = System.Security.Cryptography.MD5.Create()
.ComputeHash(System.Text.Encoding.ASCII.GetBytes(myText ?? ""));
return string.Join("", Enumerable.Range(0, hash.Length).Select(i => hash[i].ToString("x2")));
}

Categories