64

I am trying to write a function to take a string and sha512 it like so?

public string SHA512(string input)
{
     string hash;

     ~magic~

     return hash;
}

What should the magic be?

James
  • 30,496
  • 19
  • 86
  • 113

13 Answers13

94

Your code is correct, but you should dispose of the SHA512Managed instance:

using (SHA512 shaM = new SHA512Managed())
{
   hash = shaM.ComputeHash(data);
}

512 bits are 64 bytes.

To convert a string to a byte array, you need to specify an encoding. UTF8 is okay if you want to create a hash code:

var data = Encoding.UTF8.GetBytes("text");    
using (...
AlG
  • 14,697
  • 4
  • 41
  • 54
Carsten Schütte
  • 4,408
  • 1
  • 20
  • 24
  • 17
    The number of examples that don't utilize dispose in any fashion whatsoever is astounding. Kudos for showing the idiomatic manner with `using`. – Jesse C. Slicer Jul 06 '12 at 18:36
  • 4
    Instead of `var data = Encoding.UTF8.GetByteCount(foo)`, use `var data = Encoding.UTF8.GetBytes(foo)`. – luiscubal Jul 06 '12 at 20:52
  • 1
    Why do you need the "using" clause? Won't the default C# garbage collection kick in and get rid of the shaM variable? Why is explicit garbage collection like this necessary? – Brian Birtle Nov 29 '15 at 10:44
  • 7
    Do not mix up carbage collection and freeing/disposing unused unmanaged objects. Using "using" makes sure that Dispose is called when the using block ends. This will release unmanaged resources - otherwise they will be released when the GC cleans up the object (and calls the finalizer internally). The class SHA512Managed is disposable, so I prefer to use using. For more information about the Dispose pattern, take a look at https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx – Carsten Schütte Dec 29 '15 at 15:27
  • In .NET 6 it throws warning `Warning SYSLIB0021 'SHA512Managed' is obsolete: 'Derived cryptographic types are obsolete. Use the Create method on the base type instead.'` How to use this in .NET 6 ? There is separate question in https://stackoverflow.com/questions/70109573/how-to-calculate-sha-512-hash-properly-in-net-6 – Andrus Nov 25 '21 at 10:36
43

This is from one of my projects:

public static string SHA512(string input)
{
    var bytes = System.Text.Encoding.UTF8.GetBytes(input);
    using (var hash = System.Security.Cryptography.SHA512.Create())
    {
        var hashedInputBytes = hash.ComputeHash(bytes);

        // Convert to text
        // StringBuilder Capacity is 128, because 512 bits / 8 bits in byte * 2 symbols for byte 
        var hashedInputStringBuilder = new System.Text.StringBuilder(128);
        foreach (var b in hashedInputBytes)
            hashedInputStringBuilder.Append(b.ToString("X2"));
        return hashedInputStringBuilder.ToString();
    }
}

Please, note:

  1. SHA512 object is disposed ('using' section), so we do not have any resource leaks.
  2. StringBuilder is used for efficient hex string building.
Nazar
  • 624
  • 6
  • 7
  • 9
    The StringBuilder code can be replaced by a single line   ‘var hash = BitConverter.ToString(hashedInputBytes).Replace("-", "");’ https://msdn.microsoft.com/en-us/library/system.bitconverter.tostring(v=vs.110).aspx – Michael Freidgeim Apr 13 '18 at 21:09
8

512/8 = 64, so 64 is indeed the correct size. Perhaps you want to convert it to hexadecimal after the SHA512 algorithm.

See also: How do you convert Byte Array to Hexadecimal String, and vice versa?

Community
  • 1
  • 1
luiscubal
  • 24,773
  • 9
  • 57
  • 83
  • Yes, you are absolutely right. I just used an online generator to compare against, which made hex. Thanks :) – James Jul 06 '12 at 18:33
  • The link does not convert a string to a byte array, it converts hex string to bytes. To convert a string to a byte array, use something like `Encoding.UTF8.GetByteCount("text")` – Carsten Schütte Jul 06 '12 at 18:38
  • @CarstenSchütte Well, UTF-8 is for text encoding, which is not related to this question. And either way, GetByteCount wouldn't convert the string to a byte array. It'd only get the *length* of the byte array. – luiscubal Jul 06 '12 at 18:51
  • @CarstenSchütte Oh, wait. I think I know what you meant. You're talking about obtaining the initial "data" variable, right? In that case, yes, UTF-8 is fine. Still, GetByteCount is still not the appropriate function. – luiscubal Jul 06 '12 at 20:51
  • @luiscubal: Sorry, GetByteCount was my fault (and copy/paste error). Of course you need to use GetBytes() to get the data. – Carsten Schütte Jan 18 '14 at 21:50
4

You might try these lines:

public static string GenSHA512(string s, bool l = false)
{
    string r = "";

    try
    {
        byte[] d = Encoding.UTF8.GetBytes(s);

        using (SHA512 a = new SHA512Managed())
        {
            byte[] h = a.ComputeHash(d);
            r = BitConverter.ToString(h).Replace("-", "");
        }

        r = (l ? r.ToLowerInvariant() : r);
    }
    catch
    {

    }

    return r;
}
  1. It is disposed at the end
  2. It's safe
  3. Supports lower case
Artfaith
  • 1,183
  • 4
  • 19
  • 29
2

Instead of WinCrypt-API using System.Security.Cryptography, you can also use BouncyCastle:

public static byte[] SHA512(string text)
{
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(text);

    Org.BouncyCastle.Crypto.Digests.Sha512Digest digester = new Org.BouncyCastle.Crypto.Digests.Sha512Digest();
    byte[] retValue = new byte[digester.GetDigestSize()];
    digester.BlockUpdate(bytes, 0, bytes.Length);
    digester.DoFinal(retValue, 0);
    return retValue;
}

If you need the HMAC-version (to add authentication to the hash)

public static byte[] HmacSha512(string text, string key)
{
    byte[] bytes = Encoding.UTF8.GetBytes(text);

    var hmac = new Org.BouncyCastle.Crypto.Macs.HMac(new Org.BouncyCastle.Crypto.Digests.Sha512Digest());
    hmac.Init(new Org.BouncyCastle.Crypto.Parameters.KeyParameter(System.Text.Encoding.UTF8.GetBytes(key)));

    byte[] result = new byte[hmac.GetMacSize()];
    hmac.BlockUpdate(bytes, 0, bytes.Length);
    hmac.DoFinal(result, 0);

    return result;
}
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
2

Keeping it simple:

using (SHA512 sha512 = new SHA512Managed())
{
    password = Encoding.UTF8.GetString(sha512.ComputeHash(Encoding.UTF8.GetBytes(password)));
}
alansiqueira27
  • 8,129
  • 15
  • 67
  • 111
1

I'm not sure why you are expecting 128.

8 bits in a byte. 64 bytes. 8 * 64 = 512 bit hash.

Andrew T Finnell
  • 13,417
  • 3
  • 33
  • 49
1

From the MSDN Documentation:
The hash size for the SHA512Managed algorithm is 512 bits.

Joel Rondeau
  • 7,486
  • 2
  • 42
  • 54
1

You could use the System.Security.Cryptography.SHA512 class

MSDN on SHA512

Here is an example, straigt from the MSDN

byte[] data = new byte[DATA_SIZE];
byte[] result;
SHA512 shaM = new SHA512Managed();
result = shaM.ComputeHash(data);
Mare Infinitus
  • 8,024
  • 8
  • 64
  • 113
0
UnicodeEncoding UE = new UnicodeEncoding();            
        byte[] message = UE.GetBytes(password);
        SHA512Managed hashString = new SHA512Managed();
        string hexNumber = "";
        byte[]  hashValue = hashString.ComputeHash(message);
        foreach (byte x in hashValue)
        {
            hexNumber += String.Format("{0:x2}", x);
        }
        string hashData = hexNumber;
Mahesh.P
  • 271
  • 3
  • 4
0

I used the following

public static string ToSha512(this string inputString)
{
        if (string.IsNullOrWhiteSpace(inputString)) return string.Empty;
        using (SHA512 shaM = new SHA512Managed())
        {
            return Convert.ToBase64String(shaM.ComputeHash(Encoding.UTF8.GetBytes(inputString)));
        }
}
Mohammad Dayyan
  • 21,578
  • 41
  • 164
  • 232
0

Made it into an extension method in my ExtensionUtility.cs class

public static string SHA512(this string plainText)
    {
      
        using (SHA512 shaM = new SHA512Managed())
        {
            var buffer = Encoding.UTF8.GetBytes(plainText);
            var hashedInputBytes = shaM.ComputeHash(buffer);

           return BitConverter.ToString(hashedInputBytes).Replace("-", "");

        }
    }
oliverdejohnson
  • 1,512
  • 2
  • 14
  • 22
0

Update:

new SHA512Managed() is depricated and SHA512.Create() should be used instead.

There is also a static Function availible since .NET5+. The static Version is slightly faster and allocates less Memory compared to SHA512.Create().

So the last up to date version would be:

using System.Security.Cryptography;
using System.Text;

namespace Common;
public class Hash
{
    public static string Sha512(string text) => Convert.ToHexString(SHA512.HashData(Encoding.UTF8.GetBytes(text)));

    public static string Sha512(byte[] data) => Convert.ToHexString(SHA512.HashData(data));
}

Note: this functions are ThreadSafe.

This will return an uppercase 128 Byte-long Hexstring (each of the 64 Bytes is represented by 2 Byte (00 - FF).

So this code:

var theHash = Common.Hash.Sha512("this is to be hashed");

would result in:

3C1E5B4C27F3FD8D297000A74FFA04B0EA310E61E7043E85CB9EFDE55C00E730549D76DBB97864A4791F40DA27C4C292E40EF76BCEE5E88CAEA6E48E79E635B5

if you want to do some performance test on you own you can use this:

using BenchmarkDotNet.Attributes;
using System.Security.Cryptography;
using System.Text;

namespace PerformanceTests
{
    [MemoryDiagnoser]
    [Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)]
    [RankColumn]
    public class Hashes
    {
        private string _inputText;
        private byte[] _inputByte;

        [Params(1_000, 10_000)]
        public int N;

        [GlobalSetup]
        public void Setup()
        {
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            _inputText = new string(Enumerable.Repeat(chars, N).Select(s => s[new Random().Next(s.Length)]).ToArray());

            _inputByte = new byte[N];
            new Random(42).NextBytes(_inputByte);
        }

        [Benchmark]
        public string Sha512StaticInputString() => Convert.ToHexString(SHA512.HashData(Encoding.UTF8.GetBytes(_inputText)));

        [Benchmark]
        public string Sha512NonStaticInputString()
        {
            using var sha512 = SHA512.Create();
            return Convert.ToHexString(sha512.ComputeHash(Encoding.UTF8.GetBytes(_inputText)));
        }

        [Benchmark]
        public string Sha512StaticInputByte() => Convert.ToHexString(SHA512.HashData(_inputByte));

        [Benchmark]
        public string Sha512NonStaticInputByte()
        {
            using var sha512 = SHA512.Create();
            return Convert.ToHexString(sha512.ComputeHash(_inputByte));
        }
    }
}

results on my machine:enter image description here Note: N is the len of the input data in bytes.

Marcel Haldemann
  • 671
  • 6
  • 11