I have a string that I need to hash in order to access an API. The API-creator has provided a codesnippet in Python, which hashes the code like this:
hashed_string = hashlib.sha1(string_to_hash).hexdigest()
When using this hashed string to access the API, everything is fine. I have tried to get the same hashed string result in C#, but without success. I have tried incredibly many ways but nothing has worked so far. I am aware about the hexdigest part aswell and I have kept that in mind when trying to mimic the behaviour.
Does anyone know how to get the same result in C#?
EDIT:
This is one of the many ways I have tried to reproduce the same result in C#:
public string Hash(string input)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
var sb = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
{
sb.Append(b.ToString("X2"));
}
return sb.ToString().ToLower();
}
}
This code is taken from: Hashing with SHA1 Algorithm in C#
Another way
public string ToHexString(string myString)
{
HMACSHA1 hmSha1 = new HMACSHA1();
Byte[] hashMe = new ASCIIEncoding().GetBytes(myString);
Byte[] hmBytes = hmSha1.ComputeHash(hashMe);
StringBuilder hex = new StringBuilder(hmBytes.Length * 2);
foreach (byte b in hmBytes)
{
hex.AppendFormat("{0:x2}", b);
}
return hex.ToString();
}
This code is taken from: Python hmac and C# hmac
EDIT 2
Some input/output:
C# (using second method provided in above description)
input: callerId1495610997apiKey3*_&E#N#B1)O)-1Y
output: 1ecded2b66e152f0965adb96727d96b8f5db588a
Python
input: callerId1495610997apiKey3*_&E#N#B1)O)-1Y
output: bf11a12bbac84737a39152048e299fa54710d24e
C# (using first method provided in above description)
input: callerId1495611935apiKey{[B{+%P)s;WD5&5x
output: 7e81e0d40ff83faf1173394930443654a2b39cb3
Python
input: callerId1495611935apiKey{[B{+%P)s;WD5&5x
output: 512158bbdbc78b1f25f67e963fefdc8b6cbcd741
C#:
public static string Hash(string input)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
var sb = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
{
sb.Append(b.ToString("x2")); // x2 is lowercase
}
return sb.ToString().ToLower();
}
}
public static void Main()
{
var x ="callerId1495611935apiKey{[B{+%P)s;WD5&5x";
Console.WriteLine(Hash(x)); // prints 7e81e0d40ff83faf1173394930443654a2b39cb3
}
Python
import hashlib
s = u'callerId1495611935apiKey{[B{+%P)s;WD5&5x'
enc = s.encode('utf-8') # encode in utf8
hash = hashlib.sha1(enc)
formatted = h.hexdigest()
print(formatted) # prints 7e81e0d40ff83faf1173394930443654a2b39cb3
Your main problem is that you are using different encodings for the same string in C# and Python. Use UTF8 in both languages and use the same casing. The output is the same.
Note that inside your input string (between callerId1495611935 and apiKey{[B{+%P)s;WD5&5x) there is an hidden \u200b character. That's why encoding your string in UTF-8 gives a different result than encoding it using ASCII. Does that character have to be inside your string?
Related
I've ran into a curious behaviour when trying to hash a string password and then display the hash in console.
My code is:
static void Main(string[] args)
{
string password = "password";
ConvertPasswordToHash(password);
}
private static void ConvertPasswordToHash(string password)
{
using (HashAlgorithm sha = SHA256.Create())
{
byte[] result = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
string hashText = Encoding.UTF8.GetString(result);
Console.WriteLine(hashText);
StringBuilder sb = new StringBuilder();
foreach (var item in result)
{
sb.Append((char)item);
}
Console.WriteLine(sb);
}
}
The problem is two fold:
The hashTest and sb contain different values (both are 32 characters long before outputting) and 2) Console outputs are even stranger. They are not 32 characters in length and second the outputs are slightly different:
When examining the strings before outputting them, I've noticed that hashText contains for instance \u0004, which could be a unicode character of some sort while sb does not contain that at all (that is before outputting the values into the console).
My questions are:
Which way is the correct way of getting a string of chars from the provided array of bytes?
Why are the console outputs different but only so slightly? It does not look like it is the fault of using the wrong Encoding.
How do I output the correct hash (32 symbols) into the console? Ive tried adding '#' before the strings to cancel any possible carriage returns etc... Pretty much without any result.
Maybe I am missing something obvious. Thank you.
The correct logic should be as follows:
private static void ConvertPasswordToHash(string password)
{
using (HashAlgorithm sha = SHA256.Create())
{
byte[] result = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
StringBuilder sb = new StringBuilder();
foreach (var item in result)
{
sb.Append(item.ToString("x2"));
}
Console.WriteLine(sb);
}
}
ToString("x2") formats the string as two hexadecimal characters.
Live example: https://dotnetfiddle.net/QkREkX
Another way is just to represent your byte[] array as a base 64 string, no StringBuilder required.
byte[] result = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
Console.WriteLine(Convert.ToBase64String(result));
Below is the code I use for hashing and I am trying to store the hash in a string(strSHA256) with UTF-8 encoding.
using (SHA256 sha256Hash = SHA256.Create())
{
bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(utf8EncodedString));
strSHA256 = Encoding.UTF8.GetString(bytes);
}
When I inspect the string variable I see "�u��Ou\u0004����O��zA�\u0002��\0�\a�}\u0012�L�Dr�"
type of value. My question is regarding to ? character marked in bold. They should be UTF-8 chars.
Why cant I view the UTF-8 special chars when I inspect from visual studio. The string o/p contains this weird char as well.
Note: I tried SHA256 with Node Js and I tend to see perfect UTF-8 special chars.
As #user2864740 mentioned bytes are not UTF8. Use base64 for bytes string representation.
var hello = "Hello world!";
using (var sha256Hash = SHA256.Create())
{
var bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(hello));
// String representation
var stringForBytes = Convert.ToBase64String(bytes);
// HEX string representation
var str = new StringBuilder(bytes.Length * 2);
foreach (var b in bytes)
{
str.Append(b.ToString("X2"));
}
var hexString = str.ToString();
}
Here is code of C#
public static string GetMD5Hash(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());
}
return s.ToString();
}
Here is code of Ruby
def getMD5Hash(str)
bs = Digest::MD5.digest( str.encode( 'UTF-8' ) ).bytes.to_a
bs = bs.map { |b| b.to_s(16).downcase }
str_bs = bs.join
return str_bs
end
When I am running ruby code and C# code to encrypt the same string, the result from Ruby is not the same result as C# provided.
How to modify Ruby code? Thanks a lot
I'm not a ruby programmer, but there is something wrong with how you are converting to hex. It looks like values such as '0a' are rendering as 'a' making the output incorrect. Ruby already has a method for this though, Digest::MD5.hexdigest, so I'm not sure why anyone would roll their own.
I would write the ruby function:
def getMD5Hash(str)
return Digest::MD5.hexdigest(str.encode( 'UTF-8' ))
end
I have simple encrypt function which takes string, convert it to bytes, xor it and apply base64.
JAVA:
String key = "1234";
public String encrypt(String plainText) throws Exception {
byte [] input = plainText.getBytes("UTF8");
byte [] output = new byte[input.length];
for(int i=0; i<input.length; i++)
output[i] = ((byte)(input[i] ^ key.charAt(i % key.length())));
String utf8 = new String(output);
return Utils.encode(utf8);
}
Then I save it to a file and open it in another application in C# using this decrypting method:
C#:
string key="1234";
public string Decrypt(string CipherText)
{
var decoded = System.Convert.FromBase64String(CipherText);
var dexored = xor(decoded, key);
return Encoding.UTF8.GetString(dexored);
}
byte[] xor(byte[] text, string key)
{
byte[] res = new byte[text.Length];
for (int c = 0; c < text.Length; c++)
{
res[c] = (byte)((uint)text[c] ^ (uint)key[c % key.Length]);
}
return res;
}
Problem is that accented characters like ěščřžýáí fail to decode.
Do you have any idea how to determine from which part the problem comes from or how to find it out? Looks to me that it has something to do with UTF-8.
I don't need suggestions for a better encryption. I have already working AES but I want to switch to xored base64 due to performance issues.
Thank you.
This is the problem:
String utf8 = new String(output);
return Utils.encode(utf8);
You should be using base64 here on output, rather than constructing a string out of the now-not-really-text data. It's possible that Utils.encode performs base64 encoding, having converted the input string back to byte for some reason - but fundamentally you shouldn't be constructing a string with your encrypted bytes using the String constructor.
If your Utils class has an encode(byte[]) method - and if that really does base64-encode the data (it's very frustrating to only have half of the code you're using) then you can just use:
return Utils.encode(output);
I am trying to read a String in UTF-16 encoding scheme and perform MD5 hashing on it. But strangely, Java and C# are returning different results when I try to do it.
The following is the piece of code in Java:
public static void main(String[] args) {
String str = "preparar mantecado con coca cola";
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(str.getBytes("UTF-16"));
byte[] hash = digest.digest();
String output = "";
for(byte b: hash){
output += Integer.toString( ( b & 0xff ) + 0x100, 16).substring( 1 );
}
System.out.println(output);
} catch (Exception e) {
}
}
The output for this is: 249ece65145dca34ed310445758e5504
The following is the piece of code in C#:
public static string GetMD5Hash()
{
string input = "preparar mantecado con coca cola";
System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] bs = System.Text.Encoding.Unicode.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 output= s.ToString();
Console.WriteLine(output);
}
The output for this is: c04d0f518ba2555977fa1ed7f93ae2b3
I am not sure, why the outputs are not the same. How do we change the above piece of code, so that both of them return the same output?
UTF-16 != UTF-16.
In Java, getBytes("UTF-16") returns an a big-endian representation with optional byte-ordering mark. C#'s System.Text.Encoding.Unicode.GetBytes returns a little-endian representation. I can't check your code from here, but I think you'll need to specify the conversion precisely.
Try getBytes("UTF-16LE") in the Java version.
The first thing I can find, and this might not be the only problem, is that C#'s Encoding.Unicode.GetBytes() is littleendian, while Java's natural byte order is bigendian.
You could use the System.Text.Enconding.Unicode.GetString(byte[]) to convert back from byte to string. In this way you're sure that all happens in Unicode encoding.