im trying to convert a byte array from a hash function into a string, i used a bitconverter.tostring() at first but it just creates a string with all uppercase bytes separated by dashes
This is my basic method
public string Hash(string password)
{
using var hasher = SHA512.Create();
{
var asBytes = Encoding.Default.GetBytes(password);
var hashed = hasher.ComputeHash(asBytes);
string stringhashed = BitConverter.ToString(hashed);
return stringhashed;
}
}
the output hashes correctly, however it gets formated into a string as BYTE-BYTE-BYTE-BYTE-BYTE....
while i needed the output to be a normal string, with lowercase and all.
Is there any way to convert a byte array into a string meeting these requirements?
Either use String.Replace() and String.ToLower() to modify the string output from BitConverter.ToString():
return stringhashed.Replace("-", "").ToLower();
... or implement your own stringification extension method:
public static class BitUtils {
public static string ToHexString(this byte[] bytes)
{
StringBuilder sb = new StringBuilder(bytes.Length * 2);
foreach(byte b in bytes)
{
// use the `x` format string to get lowercase hexadecimal
sb.AppendFormat("{0:x2}", b);
}
return sb.ToString();
}
}
So you can do:
return asBytes.ToHexString();
I have a jpg image that I can convert into a sequence of binary numbers but I can't recover it afterward. It ends up corrupted.
using System;
using System.IO;
using System.Net.Mime;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string inputFilename = "test.jpg";
byte[] fileBytes = File.ReadAllBytes(inputFilename);
var test = ToBinaryString(fileBytes);
byte[] bytes = Encoding.ASCII.GetBytes(test);
string fileresult = Convert.ToBase64String(bytes);
byte[] fileresutl2 = Convert.FromBase64String(fileresult);
File.WriteAllBytes("C:/Users/Florian/RiderProjects/ConsoleApp1/ConsoleApp1/bin/Debug/net5.0/test7.txt", fileresutl2);
string text = System.IO.File.ReadAllText("C:/Users/Florian/RiderProjects/ConsoleApp1/ConsoleApp1/bin/Debug/net5.0/test7.txt");
var result = Convert.ToBase64String(FromBinaryString(text));
File.WriteAllBytes("C:/Users/Florian/RiderProjects/ConsoleApp1/ConsoleApp1/bin/Debug/net5.0/test8.jpg", FromBinaryString(test));
Console.WriteLine(test);
}
public static string ToBinaryString(byte[] array)
{
var s = new StringBuilder();
foreach (byte b in array)
s.Append(Convert.ToString(b, 2));
return s.ToString();
}
public static byte[] FromBinaryString(string s)
{
int count = s.Length / 8;
var b = new byte[count];
for (int i = 0; i < count ; i++)
b[i] = Convert.ToByte(s.Substring(i * 8, 8), 2);
return b;
}
}
}
I don't see what can corrupt my file.
Excuse me for the organization of the file, it is simply a test code coded quickly.
There are some odd things in the code such as uselessly converting to base64 and back, but let's go right to the core of the problem: converting bytes to a binary string
public static string ToBinaryString(byte[] array)
{
var s = new StringBuilder();
foreach (byte b in array)
s.Append(Convert.ToString(b, 2));
return s.ToString();
}
On the face of it, it seems reasonable. Bytes go in, a binary string comes out. But here are some examples that I hope will convince you that there is an issue with this conversion:
Console.WriteLine(ToBinaryString(new byte[]{1, 1}));
Console.WriteLine(ToBinaryString(new byte[]{3}));
( https://ideone.com/y6dB1Z )
These both come out as "11". That's bad, it means the conversion is not reversible. The reason it goes wrong is that the most-significant zeroes are dropped, and then the next byte "shifts into" that position. Every byte should be represented by exactly 8 bits, just as your decoding function expects. For example:
public static string ToBinaryString(byte[] array)
{
var s = new StringBuilder();
foreach (byte b in array)
s.Append(Convert.ToString(b, 2).PadLeft(8, '0'));
return s.ToString();
}
By the way it's not like you should actually ever use something like this (except when experimenting, which it looks like is what you're doing, so it's OK), it inflates the file size by a factor of 8 and doesn't actually do anything useful. If you're going to decode the JPG for example, do that directly with the bytes of the file, not with "the file as a binary string". Even Huffman codes should not be done like that.
How to Hex Encode a SHA-256 hash properly in C#?
private static string ToHex(byte[] bytes, bool upperCase)
{
StringBuilder result = new StringBuilder(bytes.Length * 2);
for (int i = 0; i < bytes.Length; i++)
result.Append(bytes[i].ToString(upperCase ? "X2" : "x2"));
return result.ToString();
}
private string hashRequestBody(string reqBody)
{
string hashString;
using (var sha256 = SHA256Managed.Create())
{
var hash = sha256.ComputeHash(Encoding.Default.GetBytes(reqBody));
hashString = ToHex(hash, false);
}
MessageBox.Show(hashString);
return hashString;
}
I did this, but the result is different with bank's sandbox I worked with.
TEST DATA:
{"CorporateID":"BCAAPI2016","SourceAccountNumber":"0201245680","TransactionID":"00000001","TransactionDate":"2017-09-13","ReferenceID":"refID","CurrencyCode":"IDR","Amount":"10000","BeneficiaryAccountNumber":"0201245681","Remark1":"Transfer Test","Remark2":"Online Transfer"}
Bank's sandbox result: e9d06986c1ed6b063bf59aa873030013725c518631deef2b2147e614017c2141
Mine: 1c83acc42cf905ca8afba27ef0640c70ad2856a366b57c17cf16f2894327676e
I've seen several solutions to this problem, but your code is the most elegant. I slightly re-factored it and tested it for this answer. I also get the hash:
1c83acc42cf905ca8afba27ef0640c70ad2856a366b57c17cf16f2894327676e
See working fiddle here: https://dotnetfiddle.net/QbsKTc
Perhaps this hash is different to the bank's because you changed the JSON string to remove private data?
using System;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
Console.WriteLine(SHA256HexHashString("{\"CorporateID\":\"BCAAPI2016\",\"SourceAccountNumber\":\"0201245680\",\"TransactionID\":\"00000001\",\"TransactionDate\":\"2017-09-13\",\"ReferenceID\":\"refID\",\"CurrencyCode\":\"IDR\",\"Amount\":\"10000\",\"BeneficiaryAccountNumber\":\"0201245681\",\"Remark1\":\"Transfer Test\",\"Remark2\":\"Online Transfer\"}"));
}
private static string ToHex(byte[] bytes, bool upperCase)
{
StringBuilder result = new StringBuilder(bytes.Length * 2);
for (int i = 0; i < bytes.Length; i++)
result.Append(bytes[i].ToString(upperCase ? "X2" : "x2"));
return result.ToString();
}
private static string SHA256HexHashString(string StringIn)
{
string hashString;
using (var sha256 = SHA256Managed.Create())
{
var hash = sha256.ComputeHash(Encoding.Default.GetBytes(StringIn));
hashString = ToHex(hash, false);
}
return hashString;
}
}
More simple solution
public string SHA256HexHashString(string input)
{
using var sha256 = SHA256.Create();
var bytes = Encoding.UTF8.GetBytes(input);
var hash = sha256.ComputeHash(bytes);
var hex = BitConverter.ToString(hash).Replace("-", "").ToLower();
return hex;
}
I'd like to ask for the equivalents of the following VB6 code in C#
As you can see here, I'm trying to make a basic encryption code which converts each letter to bytes and then again convert to Hexadecimal...
Public Function Encrypt(s As String) As String
Dim bytArray() As Byte
bytArray = StrConv(s, vbFromUnicode)
For i = LBound(bytArray) To UBound(bytArray)
Encrypt = Encrypt & Hex(bytArray(i))
Next i
End Function
I've tried a little bit of C# but I can't figure it out...
private string encrypt(string s, byte[] bytArray, string t)
{
bytArray = ????;
for(int i = 0; i < s.Length ????; i++{
t += Hex(bytArray[i]); ????
}
return t;
}
I'm sorry I am really a novice in C# and I've gotten so adapted in BASIC that I don't know how to get used in other languages... please help... thanks!
if you want to encrypt the string i think you'd better use XOR (^ in C#) than &.
Here is the example of something like you've wrote:
using System.IO;
using System;
using System.Text;
class Program
{
static void Main()
{
string input = "test input";
byte[] key = new byte[input.Length];
Random r = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < key.Length; i++)
{
key[i] = (byte)r.Next();
}
var result = Encrypt(input, key);
Console.WriteLine(result);
}
static string Encrypt(string inp, byte[] key){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < inp.Length; i++)
{
sb.Append(inp[i] & key[i]);
}
return sb.ToString();
}
}
you will not be able to decode the string using &
C# has System.Security.Cryptography namespace with encryption algorithms
Define "encrypt". Do you really just mean "obfuscate"? Are you trying to replicate the original VB6 exactly? Or simply achieve a similar effect?
One possible approach (this will encode to Unicode bytes):
using System.Text;
string Encrypt(string text)
{
return string.Concat(
Encoding.Unicode.GetBytes(text).Select(b => b.ToString("x2")));
}
Another possibility (this will be exactly the same result as the VB6 code):
using System.Text;
string Encrypt(string text)
{
return string.Concat(
Encoding.Default.GetBytes(text).Select(b => b.ToString("x2")));
}
The only difference between the two is which text encoding is used to convert to bytes.
exact version
VB.NET
Public Function Encrypt(s As String) As String
Encrypt = String.Empty
Dim byteArray() As Byte = System.Text.Encoding.Unicode.GetBytes(s)
For Each b As Byte In byteArray
Encrypt &= Hex(b)
Next
End Function
C#
static string Encrypt(string s)
{
string encrypt = "";
byte[] byteArray = System.Text.Encoding.Unicode.GetBytes(s);
foreach (byte b in byteArray)
{
encrypt += String.Format("{0:x}", System.Convert.ToInt64(b));
}
return encrypt;
}
short version - requires string formatting
VB.NET
Public Function Encrypt(s As String) As String
Dim byteArray() As Byte = System.Text.Encoding.Unicode.GetBytes(s)
Encrypt = BitConverter.ToString(byteArray)
End Function
C#
static string Encrypt(string s)
{
byte[] byteArray = System.Text.Encoding.Unicode.GetBytes(s);
string encrypt = BitConverter.ToString(byteArray);
return encrypt;
}
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")));
}