We have a python web service. It needs a hash as a parameter.
The hash in python is generated this way.
hashed_data = hmac.new("ant", "bat", hashlib.sha1)
print hashed_data.hexdigest()
Now, this is how I generate the hash from C#.
ASCIIEncoding encoder = new ASCIIEncoding();
Byte[] code = encoder.GetBytes("ant");
HMACSHA1 hmSha1 = new HMACSHA1(code);
Byte[] hashMe = encoder.GetBytes("bat");
Byte[] hmBytes = hmSha1.ComputeHash(hashMe);
Console.WriteLine(Convert.ToBase64String(hmBytes));
However, I'm coming out with different result.
Should I change the order of the hashing?
Thank you,
Jon
In order to print the result:
In Python you use: .hexdigest()
In C# you use: Convert.ToBase64String
Those 2 functions don't do the same thing at all. Python's hexdigest simply converts the byte array to a hex string whereas the C# method uses Base64 encoding to convert the byte array. So to get the same output simply define a function:
public static string ToHexString(byte[] array)
{
StringBuilder hex = new StringBuilder(array.Length * 2);
foreach (byte b in array)
{
hex.AppendFormat("{0:x2}", b);
}
return hex.ToString();
}
and then:
ASCIIEncoding encoder = new ASCIIEncoding();
Byte[] code = encoder.GetBytes("ant");
HMACSHA1 hmSha1 = new HMACSHA1(code);
Byte[] hashMe = encoder.GetBytes("bat");
Byte[] hmBytes = hmSha1.ComputeHash(hashMe);
Console.WriteLine(ToHexString(hmBytes));
Now you will get the same output as in Python:
739ebc1e3600d5be6e9fa875bd0a572d6aee9266
Related
My method AESEncrypt(string text) is returning a byte array.
If I encrypt a message, and use the returned byte array as an input for AESDecrypt(byte[] text), everything is working fine. The problem is, that I need to convert it to a string and vice versa, so I tried the following:
byte[] encrypted = enc.AESEncrypt("Testmessage");
string encryptedStr = Convert.ToBase64String(encrypted);
byte[] test = Convert.FromBase64String(encryptedStr);
Console.WriteLine((encrypted == test));
I also tried this with Encoding.ASCII.GetString(), Encoding.UTF8.GetString(),
but encrypted == test returns false everytime...
What method do I need to use to convert the AES byte[] to a string and vice versa?
This is the AESEncrypt method:
public byte[] AESEncrypt(string s)
{
byte[] encrypted;
using (AesManaged aes = new AesManaged()) {
ICryptoTransform encryptor = aes.CreateEncryptor(AESKey, AESIV);
using (MemoryStream ms = new MemoryStream()) {
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) {
using (StreamWriter sw = new StreamWriter(cs)) {
sw.Write(s);
}
encrypted = ms.ToArray();
}
}
}
return encrypted;
}
An encrypted payload held in a byte array is not directly convertible to a string, or at least not without using an ANSI encoding and both sides (encoding and decoding) agreeing on the string's code page. And if you use any Unicode encoding (UTF-8, UTF-16, ...) you're bound to have bytes that contain invalid code points, so who can't be decoded to a character.
That's where base64 comes into play. This is a safe way to represent byte arrays as ASCII strings, a subset implemented by almost every (if not every) encoding. So using that base64 code is fine.
You'll simply want encrypted.SequenceEquals(test), as explained in Comparing two byte arrays in .NET.
The base64 is directly used for this.
here is an example:
Encode
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
Decode
public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
Consider byte[] encrypted and byte[] test, when you test for equality with == by default the references are compared not their content. This explains, why you test encrypted == test fails.
You are also asking about how to convert byte[] into a string, which is not related to your encrypted == test test at all. In general you the various System.Text.Encoding.*.GetString(byteArray); preform the conversion but you need to know what encoding was used for the byteArray. This information has to be passed along separately, you might have a specification which says all byte arrays are encoded in UTF-8 or you might pass the encoding along together with the data but there exists no general answer.
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?
Given the string
KlVkeNK76V27D2MSBOhfNC6eNtA=
This look like base64 encoded. However, I tried using convert to base64 with C# , result is a garbage string.
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
If I use this:
https://hashkiller.co.uk/sha1-decrypter.aspx
then it give a nicely SHA1 hash:
2a556478d2bbe95dbb0f631204e85f342e9e36d0
Can anyone show me how to decrypt it with C#?
Thanks a lot.
They simply print the hex value of the base64-decoded string:
byte[] bytes = Convert.FromBase64String("KlVkeNK76V27D2MSBOhfNC6eNtA=");
string hexString = new SoapHexBinary(bytes).ToString().ToLowerInvariant();
(where SoapHexBinary is a .NET class that converts byte[] to hex string)
This is my PHP code:
<?php
$sig_string = "GET&https%3A%2F%2Fapi.pinterest.com%2Fv3%2Fusers%2Farchimede%2Fboards%2F&client_id=987654×tamp=1391761866";
$secret = "123456";
$sig = hash_hmac("sha256", $sig_string, $secret);
echo $sig;
?>
which returns (correctly) a7918aec50919915f3cefed8622ddbe35448c8f71a54ad115828f07a05930f4c
Now, I want to translate this function inside C#. Code:
signature_base_string = "GET&https%3A%2F%2Fapi.pinterest.com%2Fv3%2Fusers%2Farchimede%2Fboards%2F&client_id=987654×tamp=1391761866";
signing_key = "123456";
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(signing_key);
byte[] messageBytes = encoding.GetBytes(signature_base_string);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
Response.Write(Convert.ToBase64String(hashmessage));
}
but it retuns p5GK7FCRmRXzzv7YYi3b41RIyPcaVK0RWCjwegWTD0w=
Why two different results? Whats wrong in the C# code?
PHP encodes the result in hexadecimal and c# encodes that in base64. But the are same.
Change this line:
Response.Write(Convert.ToBase64String(hashmessage));
To this:
Response.Write(BitConverter.ToString(hashmessage).Replace("-", "").ToLower());
to have the result in hexadecimal encoding.
They are the same:
The result from .NET C# is p5GK7FCRmRXzzv7YYi3b41RIyPcaVK0RWCjwegWTD0w=. This is a base64 string.
You can convert it to hexadecimal using this tool for example. And you'll get the same as PHP after converting:
A7918AEC50919915F3CEFED8622DDBE35448C8F71A54AD115828F07A05930F4C
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);