简体   繁体   English

使用 Sha256 散列字符串

[英]Hashing a string with Sha256

I try to hash a string using SHA256, I'm using the following code:我尝试使用 SHA256 hash 字符串,我使用以下代码:

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 )但是,与我的朋友 php 以及在线生成器(例如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). Encoding.Unicode是 Microsoft 对 UTF-16(一种双宽编码,由于历史原因在 Windows 世界中使用,但未被其他任何人使用)的误导性名称。 http://msdn.microsoft.com/en-us/library/system.text.encoding.unicode.aspx 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).如果你检查你的bytes数组,你会看到每第二个字节都是0x00 (因为双宽编码)。

You should be using Encoding.UTF8.GetBytes instead.您应该改用Encoding.UTF8.GetBytes

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.而且,根据您是否认为终止'\\0'字节是您正在散列的数据的一部分,您将看到不同的结果。 Hashing the two bytes "Hi" will give a different result from hashing the three bytes "Hi" .散列两个字节"Hi"将给出与散列三个字节"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.) (想必你想做你朋友的 PHP 代码正在做的任何一个。)

For ASCII text, Encoding.UTF8 will definitely be suitable.对于 ASCII 文本, Encoding.UTF8绝对适合。 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 é andand see whether your results still match up.如果您的目标是与您朋友的代码完美兼容,即使是在非 ASCII 输入上,您最好尝试一些带有非 ASCII 字符(例如é测试用例,看看您的结果是否仍然匹配。 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.它可能是在 Unicode 发明之前曾经流行的 8 位“代码页”之一。 (Again, I think Windows is the main reason that anyone still needs to worry about "code pages".) (同样,我认为 Windows 是任何人仍然需要担心“代码页”的主要原因。)

I also had this problem with another style of implementation but I forgot where I got it since it was 2 years ago.我在使用另一种实现方式时也遇到了这个问题,但我忘记了从 2 年前得到它的地方。

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.当我出于某种原因输入类似abcdefghi2013 ,它会给出不同的结果并导致我的登录模块出现错误。 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!然后我尝试按照 Quuxplusone 建议的相同方式修改代码并将编码从ASCII更改为UTF8然后它终于起作用了!

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!再次感谢 Quuxplusone 精彩而详细的回答! :) :)

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.您为计算 SHA256 的在线网站放置的链接使用 UTF8 编码,而在您的示例中,您使用了 Unicode 编码。 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.通过上面的示例,您将获得链接网站的相同 SHA256 哈希值。 You need to use the same encoding also in PHP.您还需要在 PHP 中使用相同的编码。

The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)每个软件开发人员绝对必须了解 Unicode 和字符集的绝对最低要求(没有任何借口!)

https://www.joelonsoftware.com/2003/10/08/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/

In the PHP version you can send 'true' in the last parameter, but the default is 'false'.在 PHP 版本中,您可以在最后一个参数中发送“true”,但默认值为“false”。 The following algorithm is equivalent to the default PHP's hash function when passing 'sha256' as the first parameter:以下算法等效于传递 'sha256' 作为第一个参数时的默认 PHP 哈希函数:

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;
    }
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));
            }
        }

The shortest and fastest way ever.有史以来最短和最快的方式。 Only 1 line!只有1行!

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);

I was looking and testing theses answers, and Visual Studio showed me that SHA256Managed is now Obsolete ( here )我正在寻找和测试这些答案,Visual Studio 向我展示了 SHA256Managed 现在已过时( 此处

So, I used the SHA256 class instead:所以,我使用了 SHA256 class 代替:

Encoding enc = Encoding.UTF8;
var hashBuilder = new StringBuilder();
using var hash = SHA256.Create();
byte[] result = hash.ComputeHash(enc.GetBytes(value));
foreach (var b in result)
    hashBuilder.Append(b.ToString("x2"));
string result = hashBuilder.ToString();

New .NET 5+ solution:全新 .NET 5+ 解决方案:

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;如果您使用的是 .NET 5 或更高版本,则可以使用新的Convert.ToHexString方法将 hash 字节数组转换为十六进制字符串; removing the hassle of using string builders and so on.消除使用字符串生成器等的麻烦。

The following also uses the using block so that SHA256 instance gets disposed.以下还使用using块,以便处置SHA256实例。 It also turns the password (which is passed in as a string) into a byte array using the UTF8 encoding, which was suggested by the accepted answer .它还使用接受的答案建议的 UTF8 编码将密码(作为字符串传入)转换为字节数组。 Furthermore, we're also using the new SHA256 class as opposed to the old (now obselete) SHA256Managed class.此外,我们还使用新的SHA256 class,而不是旧的(现已过时的) 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. SHA-256 等通用散列函数不再适合用于密码,即使您添加了盐。 This is useful for hashing strings that you know have high entropy, such as long randomly generated session tokens and whatnot.这对于散列您知道具有高熵的字符串很有用,例如长时间随机生成的 session 令牌等等。 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 )为了存储密码,您必须查看专门为此目的设计的较慢的散列函数,例如 Bcrypt、Scrypt 或 PBKDF2(后者在 .NET 中原生可用 - 请参阅

This work for me in .NET Core 3.1.这在 .NET Core 3.1 中对我有用。
But not in .NET 5 preview 7.但不在 .NET 5 预览版 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);
            }
        }  
    }
}
 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM