Generate SHA1 Hash in Portable Class Library

蓝咒 提交于 2019-12-01 02:36:59

Mono provides a managed implementation of SHA1 for it's own mscorlib.dll (but it's not located in Mono.Security.dll like @CodeInChaos suggested).

It's open source, very well tested and meant to behave exactly like Microsoft implementation (e.g. it derives from SHA1, HashAlgorith... implements ICryptoTransform...) so it should be an easy drop-in replacement.

I think the easiest way is to use the PCLCrypto nuget package. Then you can do:

private static string CalculateSha1Hash(string input)
{
        // step 1, calculate MD5 hash from input
        var hasher = WinRTCrypto.HashAlgorithmProvider.OpenAlgorithm(HashAlgorithm.Sha1);
        byte[] inputBytes = Encoding.UTF8.GetBytes(input);
        byte[] hash = hasher.HashData(inputBytes);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {
            sb.Append(hash[i].ToString("X2"));
        }
        return sb.ToString();
}

Well I needed this too recently and I found much easier to take SHA1 implementation from HashLib : http://hashlib.codeplex.com/

Mono implementation have some far-going dependencies (localization of exceptions, etc.), while from HashLib you need only to copy few files without any changes in them:

Converters.cs
Hash.cs
HashBuffer.cs
HashCryptoNotBuildIn.cs
HashResult.cs
IHash.cs
SHA0.cs
SHA1.cs

55 KB of code total, so nothing too heavy.

I have used this BouncyCastle Nuget package: https://www.nuget.org/packages/BouncyCastle-PCL/ and it works just fine for me (cross platforms Windows Store App, .Net Framework 4.5, Silverlight 5, Windows Phone 8, Xamarin.Android, Xamarin.iOS)

Use HMACSHA1 to generate signature like this:

public string GenerateSignature(string key, string signatureBase)
{
   var keyBytes = Encoding.UTF8.GetBytes(key);
   HMACSHA1 hashAlgorithm = new HMACSHA1(keyBytes);            
   byte[] dataBuffer = Encoding.UTF8.GetBytes(signatureBase);
   byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer);
   return Convert.ToBase64String(hashBytes);
}

The SHA-1 Wikipedia article contains pseudocode that you could use as a guideline for your own implementation. But, as always with cryptographic functions, I strongly advise to use a tried and tested implementation.

Assuming you want a SHA-256 implementation, you can find one in BouncyCastle, which is available in source code form. The relevant class there is called Org.BouncyCastle.Crypto.Digests.Sha256Digest (here's its source).

uluorta

You might want to check out the new .NET Standard library:

https://docs.microsoft.com/en-us/dotnet/articles/standard/library

It is portable, and System.Security.Cryptography is included.

    /// <summary>
    /// Compute hash for string encoded as UTF8
    /// </summary>
    /// <param name="input">String to be hashed.</param>
    /// <returns>40-character hex string.</returns>
    public static string GetSha1(string input)
    {
        using (var sha1 = System.Security.Cryptography.SHA1.Create())
        {
            byte[] inputBytes = Encoding.UTF8.GetBytes(input);
            byte[] hash = sha1.ComputeHash(inputBytes);

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hash.Length; i++)
            {
                sb.Append(hash[i].ToString("X2"));
            }
            return sb.ToString();
        }
    }

You might also get some help (for creating a PCL project with .NET Standard Library) here:

https://xamarinhelp.com/dot-net-standard-pcl-xamarin-forms/

I wanted sign OAuth also, and am looking at PCL Crypto - this test shows creation of a HmacSha1 hash, and compares the result to the standard .NET Framework way.

    [Test]
    public void CreateHash_VersusComputeHash_ReturnsEquivalent()
    {
        // USING TRADITIONAL .NET:
        var key = new byte[32];
        var contentBytes = Encoding.UTF8.GetBytes("some kind of content to hash");
        new RNGCryptoServiceProvider().GetBytes(key);

        var alg = new HMACSHA1(key); // Bouncy castle usage does not differ from this
        var result = alg.ComputeHash(contentBytes);




        // USING PCL CRYPTO:
        var algorithm = WinRTCrypto.MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha1);

        byte[] mac;
        using (var hasher = algorithm.CreateHash(key))
        {
            hasher.Append(contentBytes);
            mac = hasher.GetValueAndReset();
        }




        // Assert results:
        Assert.AreEqual(result.Length, mac.Length);

        for (var i = 0; i < result.Length; i++)
        {
            Assert.AreEqual(result[i], mac[i]);
        }
    }

This worked for me when I had to achieve the same outcome. You can do this with SHA512 and others too.

using System.Security.Cryptography;

public static string HashSHA1(this string value)
{
    using (var sha = SHA1.Create())
    {
       return Convert.ToBase64String(sha.ComputeHash(System.Text.Encoding.UTF8.GetBytes(value)));
    }
}

Code cited from: https://xamarinhelp.com/cryptography-in-xamarin-forms/

Here is an example using BouncyCastle

    public static string ComputeSha1(string data)
    {
        var sha1Digest = new Org.BouncyCastle.Crypto.Digests.Sha1Digest();
        var hash = new byte[sha1Digest.GetDigestSize()];

        var dataBytes = Encoding.UTF8.GetBytes(data);
        foreach (var b in dataBytes)
        {
            sha1Digest.Update(b);
        }
        sha1Digest.DoFinal(hash, 0);

        return string.Join("", hash.Select(b => b.ToString("x2")).ToArray());
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!