106

I want to hash given byte[] array with using SHA1 Algorithm with the use of SHA1Managed.
The byte[] hash will come from unit test.
Expected hash is 0d71ee4472658cd5874c5578410a9d8611fc9aef (case sensitive).

How can I achieve this?

public string Hash(byte [] temp)
{
    using (SHA1Managed sha1 = new SHA1Managed())
    {

    }
}
knocte
  • 16,941
  • 11
  • 79
  • 125
Merve Kaya
  • 1,219
  • 2
  • 10
  • 16
  • 2
    Your excpected hash is a hexadecimal value, so it doesnt matter if it's case sensitive e.g. `hex(e) == hex(E)` – jAC Jun 25 '13 at 08:24
  • https://stackoverflow.com/questions/4819794/sha1-c-sharp-equivalent-of-this-java – TarekSiala Apr 14 '19 at 20:55

6 Answers6

213

For those who want a "standard" text formatting of the hash, you can use something like the following:

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)
        {
            // can be "x2" if you want lowercase
            sb.Append(b.ToString("X2"));
        }

        return sb.ToString();
    }
}

This will produce a hash like 0C2E99D0949684278C30B9369B82638E1CEAD415.

Or for a code golfed version:

static string Hash(string input)
{
    var hash = new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input));
    return string.Concat(hash.Select(b => b.ToString("x2")));
}

For .Net 5 and above, the built-in Convert.ToHexString gives a nice solution with no compromises:

static string Hash(string input)
{
    using var sha1 = SHA1.Create();
    return Convert.ToHexString(sha1.ComputeHash(Encoding.UTF8.GetBytes(input)));
}
Mitch
  • 21,223
  • 6
  • 63
  • 86
  • 1
    It bugs me that this solution doesn't dispose the SHA1Managed object, because it is marked as Disposable. This post could be handy when optimizing: http://stackoverflow.com/a/624379/991863 – sky-dev Dec 21 '15 at 16:38
  • @sky-dev, I usually agree with `IDisposable`, but a quick trip to [the reference source](http://referencesource.microsoft.com/#mscorlib/system/security/cryptography/sha1managed.cs,5d9dbfaea57ea7b8) shows that nothing interesting happens in `.Dispose()` – Mitch Dec 21 '15 at 22:54
  • Yeah, I looked at the Dispose implementation as well. It would just speed GarbageCollection a tad. It probably isn't a big deal in the grand scheme of things. – sky-dev Dec 22 '15 at 15:22
  • 32
    @Mitch If it implements the IDisposable interface then what happens in the reference source shouldn't matter. Should they ever change it for any reason such that the .Dispose() call becomes important, your previously working code is now causing a problem. Relying on looking into the bowels of a framework to determine what you can get away with is a path to a maintenance nightmare. I highly suggest following the documentation and correctly handling disposable objects, it'll save you pain in the long term. – unenthusiasticuser Dec 16 '16 at 15:19
  • @unenthusiastic use, Haha, thanks. I wasn't sure what the purpose of documentation was... (The code in my production applications is the one from the top, but the circumstances of the second make me comfortable enough that it would be equally supportable in all but the tightest loops. `IDisposable` is semi-optional when dealing with non-side-effecting classes.) – Mitch Dec 16 '16 at 15:32
  • just because something is IDisposable doesn't mean you should call Dispose() on it. source: I've done server-side SharePoint development. – Vince Sep 13 '18 at 14:08
  • For the second version, you can also replace the select + concat logic with aggregate: `new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input)).Aggregate(string.Empty, (x, y) => x + y.ToString("x2"))` – aloisdg Jan 22 '19 at 16:56
  • 1
    What is the "X2" for? – ijt Jul 26 '20 at 23:27
  • 3
    @ijt, X2 tells it to use two hexadecimal digits per byte. `x2` means lowercase, `X2` is uppercase – Mitch Jul 27 '20 at 00:16
  • If you need to support machines set to FIPS 140-2 compliance, replace `SHA1Managed` with `SHA1CryptoServiceProvider` instead (but keep the rest the same). But to future-proof your code, use a stronger hashing algorithm. Even if your use case is not security-sensitive, these methods can be disabled through system policy. – Joey Adams Sep 01 '20 at 15:53
  • @JoeyAdams, sure. That is only needed for .Net 2 through .Net 4.7.2, though. .Net 4.8 make the change automatically for you ([Managed cryptography classes do not throw a CryptographyException in FIPS mode](https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/retargeting/4.7.2-4.8#managed-cryptography-classes-do-not-throw-a-cryptographyexception-in-fips-mode)) – Mitch Sep 01 '20 at 17:03
  • @Mitch: Thanks for the refinement. Though this only applies if the application *targets* .NET 4.8, or if the app config uses `UseLegacyFipsThrow=false` as described in your link. – Joey Adams Sep 04 '20 at 17:27
41
public string Hash(byte [] temp)
{
    using (SHA1Managed sha1 = new SHA1Managed())
    {
        var hash = sha1.ComputeHash(temp);
        return Convert.ToBase64String(hash);
    }
}

EDIT:

You could also specify the encoding when converting the byte array to string as follows:

return System.Text.Encoding.UTF8.GetString(hash);

or

return System.Text.Encoding.Unicode.GetString(hash);
John Gathogo
  • 4,495
  • 3
  • 32
  • 48
  • 3
    If they want a hex string then Base64 is probably the wrong choice. – Joey Jun 25 '13 at 08:32
  • @Joey: Against the answer given by GrantThomas, the member indicated that they need to return a string – John Gathogo Jun 25 '13 at 08:35
  • @MerveKaya: Perhaps you should explain what you mean by "it didnt work". What does the incoming byte array represent? How did you determine "SHA1Managed"-hashing the incoming byte array should give you `0d71ee4472658cd5874c5578410a9d8611fc9aef` as the output? – John Gathogo Jun 25 '13 at 08:40
  • Byte[] hash comes from unit test. In the question they wrote that expected hash is 0d71ee4472658cd5874c5578410a9d8611fc9aef. It comes from unit test – Merve Kaya Jun 25 '13 at 08:43
  • @MerveKaya: See my update on how to use `Encoding` when converting the hash to a string – John Gathogo Jun 25 '13 at 08:46
  • No, unfortunately it failed again – Merve Kaya Jun 25 '13 at 08:51
19

This is what I went with. For those of you who want to optimize, check out https://stackoverflow.com/a/624379/991863.

    public static string Hash(string stringToHash)
    {
        using (var sha1 = new SHA1Managed())
        {
            return BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(stringToHash)));
        }
    }
Community
  • 1
  • 1
sky-dev
  • 6,190
  • 2
  • 33
  • 32
  • 1
    I had to use BitConverter.ToString(sha1.ComputeHash(bytes)).Replace("-", "") since I didn't want the dashes introduced by BitConverter. After that it worked like a charm! Thanks! – Sam Aug 20 '18 at 18:00
9

You can "compute the value for the specified byte array" using ComputeHash:

var hash = sha1.ComputeHash(temp);

If you want to analyse the result in string representation, then you will need to format the bytes using the {0:X2} format specifier.

Grant Thomas
  • 44,454
  • 10
  • 85
  • 129
9

Fastest way is this :

    public static string GetHash(string input)
    {
        return string.Join("", (new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input))).Select(x => x.ToString("X2")).ToArray());
    }

For Small character output use x2 in replace of of X2

alireza amini
  • 1,712
  • 1
  • 18
  • 33
4

I'll throw my hat in here:

(as part of a static class, as this snippet is two extensions)

//hex encoding of the hash, in uppercase.
public static string Sha1Hash (this string str)
{
    byte[] data = UTF8Encoding.UTF8.GetBytes (str);
    data = data.Sha1Hash ();
    return BitConverter.ToString (data).Replace ("-", "");
}
// Do the actual hashing
public static byte[] Sha1Hash (this byte[] data)
{
    using (SHA1Managed sha1 = new SHA1Managed ()) {
    return sha1.ComputeHash (data);
}
oPless
  • 618
  • 1
  • 8
  • 18