I have C# code, which computes SHA1 and I want to know how to rewrite it to Python.
My Python code doesn't give the same output as C#
C#:
protected override string GetSign(string str)
{
var UE = new UnicodeEncoding();
var MessageBytes = UE.GetBytes(str);
var SHhash = new SHA1Managed();
m_signature = SHhash.ComputeHash(MessageBytes);
return Encoding.UTF8.GetString(m_signature);
}
Python:
sha_1 = hashlib.sha1()
sha_1.update(tmp.encode('utf-8'))
result = sha_1.hexdigest()
like #xdtTransform said sha1 is obsolete. I assume your c# code is way too old. If you are refactoring it in python, it's better to go with SHA256 like below.
result = hashlib.sha256(tmp.encode('utf-8')).hexdigest()
Related
We are trying to implement the SHA256 Base64 hash in ruby which is not returning the expected results as in C#.
Below is our C# sample code.
public static string HashSHA256ToBase64(string phrase)
{
if (phrase == null)
return null;
var encoder = new UTF8Encoding();
var sha256Hasher = new SHA256CryptoServiceProvider();
var hashedDataBytes = sha256Hasher.ComputeHash(encoder.GetBytes(phrase));
return Convert.ToBase64String(hashedDataBytes);
}
For this, we need to write equivalent code in ruby. For which we are trying as follows.
Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), "", phrase))
It is not providing the same results as C#.
Test phrase : V2dcZBpzzglD1ynW5ZAyFocs9wtpR624wlla9gujw0I=RquZ/QzazPM=
Expected Result : utXwt733s9FmiSM69o2zGOm0IT42FjthbB0oquIuPak=
Can someone help me with the equivalent ruby code to resolve this
Below code fixed this
Digest::SHA256.base64digest(phrase)
I have to replicate C# hash from the code below into PHP. I have been searching but didn't find a solution so far.
From this article on creating an md5 hash string:
using System;
using System.Text;
using System.Security.Cryptography;
// Create an md5 sum string of this string
static public string GetMd5Sum(string str)
{
// First we need to convert the string into bytes, which
// means using a text encoder.
Encoder enc = System.Text.Encoding.Unicode.GetEncoder();
// Create a buffer large enough to hold the string
byte[] unicodeText = new byte[str.Length * 2];
enc.GetBytes(str.ToCharArray(), 0, str.Length, unicodeText, 0, true);
// Now that we have a byte array we can ask the CSP to hash it
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(unicodeText);
// Build the final string by converting each byte
// into hex and appending it to a StringBuilder
StringBuilder sb = new StringBuilder();
for (int i=0;i<result.Length;i++)
{
sb.Append(result[i].ToString("X2"));
}
// And return it
return sb.ToString();
}
For input = "123", the above code gives me "5FA285E1BEBE0A6623E33AFC04A1FBD5"
I have tried the following PHP code but it does not give the same output.
From the SO question PHP MD5 not matching C# MD5:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-32LE");
echo md5($strUtf32);
This code has the result = "a0d5c8a4d386f15284ec25fe1eeeb426". By the way, changing UTF-32LE to utf-8 or utf-16 still does not give me the same result.
Can anyone help?
Yep, as CodesInChaos suggests, you got the encodings wrong.
On php side try this:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-16LE");
echo md5($strUtf32);
This will give you 5FA285E1BEBE0A6623E33AFC04A1FBD5. This will match System.Text.Encoding.Unicode on the c# side.
Otherwise change System.Text.Encoding.Unicode to System.Text.Encoding.UTF32 on the c# side. This will give you A0D5C8A4D386F15284EC25FE1EEEB426.
Uhh, the C# code creates a MD5 hash and the PHP mb_convert_encoding function just encodes the string...
Plus, this is NOT THE FULL CODE from the link you gave. You are missing the important MD5 function:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-16");
echo md5($strUtf32); <=====
If that code matches there should be NO REASON why that shouldn't work, as the MD5 algorithm is still the same and does not vary from language to language.
I have looked and found code to take a PHP sha512 hash and match it inside C#. I am currently looking for a way to go from a hash that was made in C# and get the same result in PHP. We are slowly moving away from asp.net to PHP and need a way to check our passwords in the database. Here is the C# code used to make the hash.
// Create a hash from a pwd and salt using sha512
public static string CreatePasswordHash(string _password, string _salt)
{
string saltAndPwd = String.Concat(_password, _salt);
SHA512 sha512 = new System.Security.Cryptography.SHA512Managed();
byte[] sha512Bytes = System.Text.Encoding.Default.GetBytes(saltAndPwd);
byte[] cryString = sha512.ComputeHash(sha512Bytes);
string hashedPwd = string.Empty;
for (int i = 0; i < cryString.Length; i++)
{
hashedPwd += cryString[i].ToString("X");
}
return hashedPwd;
}
In PHP I have tried to get it to match but it is off by just a few bytes it seems.
function CreatePasswordHash($_password, $_salt)
{
$saltAndPwd = $_password . $_salt;
$hashedPwd = hash('sha512', $saltAndPwd);
return strtoupper($hashedPwd);
}
When using the above with the same salt and password here is the results I get.
The first result is from C#, and the second result is from PHP:
60BB73FDA3FF7A444870C6D0DBC7C6966F8D5AD632B0A02762E0283051D7C54A5F4B01571D1A5BC8C689DBC411FEB92158383A56AFC6AE6074696AF36E16
60BB73FDA3FF7A444870C6D0DBC7C609066F8D5AD632B0A02762E0283051D7C54A5F4B001571D1A5BC8C689DBC411FEB092158383A56AFC6AE6074696AF36E16
Any ideas on why these are not matching up? Does it have to do with endian byte order?
try
hashedPwd += cryString[i].ToString("X2");
Editing PHP:
function CreatePasswordHash($_password, $_salt)
{
$saltAndPwd = $_password . $_salt;
$hashedPwd = hash('sha512', $saltAndPwd);
$hex_strs = str_split($hashedPwd,2);
foreach($hex_strs as &$hex) {
$hex = preg_replace('/^0/', '', $hex);
}
$hashedPwd = implode('', $hex_strs);
return strtoupper($hashedPwd);
}
The C# print out is not including leading zeros.
Replace
hashedPwd += cryString[i].ToString("X");
with
hashedPwd += cryString[i].ToString("X2");
Double check that you use the same character encoding in C# and PHP. GetBytes returns different results, depending on the encoding. System.Text.Encoding.Default depends on the localization of the OS.
You can try open_ssl_digest
echo openssl_digest($saltAndPwd, 'sha512');
if you have PHP >= 5.3
You could also use the hash_algos function to see which algorithms are supported in your system.
HTH
I try to hash a string using SHA256, I'm using the following code:
using System;
using System.Security.Cryptography;
using System.Text;
public class Hash
{
public static string getHashSha256(string text)
{
byte[] bytes = Encoding.Unicode.GetBytes(text);
SHA256Managed hashstring = new SHA256Managed();
byte[] hash = hashstring.ComputeHash(bytes);
string hashString = string.Empty;
foreach (byte x in hash)
{
hashString += String.Format("{0:x2}", x);
}
return hashString;
}
}
However, this code gives significantly different results compared to my friends php, as well as online generators (such as This generator)
Does anyone know what the error is? Different bases?
Encoding.Unicode is Microsoft's misleading name for UTF-16 (a double-wide encoding, used in the Windows world for historical reasons but not used by anyone else). http://msdn.microsoft.com/en-us/library/system.text.encoding.unicode.aspx
If you inspect your bytes array, you'll see that every second byte is 0x00 (because of the double-wide encoding).
You should be using Encoding.UTF8.GetBytes instead.
But also, you will see different results depending on whether or not you consider the terminating '\0' byte to be part of the data you're hashing. Hashing the two bytes "Hi" will give a different result from hashing the three bytes "Hi". You'll have to decide which you want to do. (Presumably you want to do whichever one your friend's PHP code is doing.)
For ASCII text, Encoding.UTF8 will definitely be suitable. If you're aiming for perfect compatibility with your friend's code, even on non-ASCII inputs, you'd better try a few test cases with non-ASCII characters such as é and 家 and see whether your results still match up. If not, you'll have to figure out what encoding your friend is really using; it might be one of the 8-bit "code pages" that used to be popular before the invention of Unicode. (Again, I think Windows is the main reason that anyone still needs to worry about "code pages".)
I also had this problem with another style of implementation but I forgot where I got it since it was 2 years ago.
static string sha256(string randomString)
{
var crypt = new SHA256Managed();
string hash = String.Empty;
byte[] crypto = crypt.ComputeHash(Encoding.ASCII.GetBytes(randomString));
foreach (byte theByte in crypto)
{
hash += theByte.ToString("x2");
}
return hash;
}
When I input something like abcdefghi2013 for some reason it gives different results and results in errors in my login module.
Then I tried modifying the code the same way as suggested by Quuxplusone and changed the encoding from ASCII to UTF8 then it finally worked!
static string sha256(string randomString)
{
var crypt = new System.Security.Cryptography.SHA256Managed();
var hash = new System.Text.StringBuilder();
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomString));
foreach (byte theByte in crypto)
{
hash.Append(theByte.ToString("x2"));
}
return hash.ToString();
}
Thanks again Quuxplusone for the wonderful and detailed answer! :)
public static string ComputeSHA256Hash(string text)
{
using (var sha256 = new SHA256Managed())
{
return BitConverter.ToString(sha256.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "");
}
}
The reason why you get different results is because you don't use the same string encoding. The link you put for the on-line web site that computes SHA256 uses UTF8 Encoding, while in your example you used Unicode Encoding. They are two different encodings, so you don't get the same result. With the example above you get the same SHA256 hash of the linked web site. You need to use the same encoding also in PHP.
The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
public string EncryptPassword(string password, string saltorusername)
{
using (var sha256 = SHA256.Create())
{
var saltedPassword = string.Format("{0}{1}", salt, password);
byte[] saltedPasswordAsBytes = Encoding.UTF8.GetBytes(saltedPassword);
return Convert.ToBase64String(sha256.ComputeHash(saltedPasswordAsBytes));
}
}
New .NET 5+ solution:
If you're using .NET 5 or above, you can use the new Convert.ToHexString method to convert the hash byte array into a hexadecimal string; eliminating the hassle of using string builders and so on.
The following method also uses the using block so that the SHA256 instance gets disposed.
It also turns the password (which is passed in as a string) into a byte array using UTF-8 encoding, which was recommended by the accepted answer. Furthermore, we're also using the new SHA256 class as opposed to the old (now obselete) SHA256Managed class.
public string QuickHash(string secret)
{
using var sha256 = SHA256.Create();
var secretBytes = Encoding.UTF8.GetBytes(secret);
var secretHash = sha256.ComputeHash(secretBytes);
return Convert.ToHexString(secretHash);
}
Note: You should NOT use this method for hashing user passwords. General-purpose hashing functions such as SHA-256 aren't suited for use for passwords anymore, even if you add salts. This is useful for hashing strings that you know have high entropy, such as long randomly generated session tokens and whatnot. For storing passwords, you must look into slower hashing functions that were specifically designed for this purpose, such as Bcrypt, Scrypt, or PBKDF2 (the latter is available natively in .NET — see this)
The shortest and fastest way ever. Only 1 line!
public static string StringSha256Hash(string text) =>
string.IsNullOrEmpty(text) ? string.Empty : BitConverter.ToString(new System.Security.Cryptography.SHA256Managed().ComputeHash(System.Text.Encoding.UTF8.GetBytes(text))).Replace("-", string.Empty);
In the PHP version you can send 'true' in the last parameter, but the default is 'false'. The following algorithm is equivalent to the default PHP's hash function when passing 'sha256' as the first parameter:
public static string GetSha256FromString(string strData)
{
var message = Encoding.ASCII.GetBytes(strData);
SHA256Managed hashString = new SHA256Managed();
string hex = "";
var hashValue = hashString.ComputeHash(message);
foreach (byte x in hashValue)
{
hex += String.Format("{0:x2}", x);
}
return hex;
}
I was looking and testing theses answers, and Visual Studio showed me that SHA256Managed is now Obsolete (here)
So, I used the SHA256 class instead:
Encoding enc = Encoding.UTF8;
var hashBuilder = new StringBuilder();
using var hash = SHA256.Create();
byte[] result = hash.ComputeHash(enc.GetBytes(yourStringToHash));
foreach (var b in result)
hashBuilder.Append(b.ToString("x2"));
string result = hashBuilder.ToString();
This work for me in .NET Core 3.1.
But not in .NET 5 preview 7.
using System;
using System.Security.Cryptography;
using System.Text;
namespace PortalAplicaciones.Shared.Models
{
public class Encriptar
{
public static string EncriptaPassWord(string Password)
{
try
{
SHA256Managed hasher = new SHA256Managed();
byte[] pwdBytes = new UTF8Encoding().GetBytes(Password);
byte[] keyBytes = hasher.ComputeHash(pwdBytes);
hasher.Dispose();
return Convert.ToBase64String(keyBytes);
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
}
}
I am converting my Java code to C#. I am not able to convert the following function from Java to C#. The fumction is calling the Update method twice. I have tried the C# code in following manner
SHA256 sh = SHA256.Create();
Encoding shEncoding = Encoding.UTF7;
byte[] data = shEncoding.GetBytes(sn);
byte hash = sh.ComputeHash(data);
But I don't know how to convert two consecutive update function call in C#.
String getSHA(byte[] sf,String sn,byte[] mac) throws NoSuchAlgorithmException
{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(sf);
md.update(sn.getBytes());
byte[] hash = md.digest(mac);
StringBuilder sb = new StringBuilder();
for(byte b : hash) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
Thanks in Advance.
Your help/guidance will help me lot.
You can use TransformBlock and TransformFinalBlock on SHA256 (~update and digest in Java) and retrieve the hash using the Hash property.