Generate SHA1 Hash in Portable Class Library
Asked Answered
I

9

16

I'm trying to build a portable class library that generates OAuth urls for other classes/applications to use. This class library using OAuth has to be a portable class library so it can work with different versions of a DropBox API I'm building.

Part of this class needs to generate an SHA1 hash to generate the oauth_signature with.

I'm aware that portable class library doesn't support System.Security.Cryptography, so is there anyway that this class can generate an SHA1 hash without that class?

Implode answered 20/4, 2012 at 22:28 Comment(3)
You could copy over some code from Mono.Security.Excrescency
I don't see any troublesome dependencies in the SHA1Managed class. Portable strikes me as just unfinished whenever I take a look.Delanos
That would be an issue but its a pretty simple string building class with a couple of methods, so as long as they do their job being unfinished isn't a problem.Implode
W
6

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.

Wennerholn answered 20/4, 2012 at 23:10 Comment(3)
Could you give me some help with using it to simply hash a string? The code has virtually no commenting on it so I'm finding it hard to understand.Implode
You need to transform the string into bytes, e.g. System.Text.XXXEncoding.GetBytes(). Take great care wrt encodings (e.g. UTF8 is much better than ASCII) since different bytes will results in different hash values.Wennerholn
I dont know how to use this. Someone can help me to generate a SHA1 hash from some string?Hutchinson
A
16

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();
}
Aceves answered 23/11, 2014 at 10:28 Comment(2)
I agree - but you may want to alter the example to show a key being used: byte[] keyMaterial; byte[] data; var algorithm = WinRTCrypto.MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha1); CryptographicHash hasher = algorithm.CreateHash(keyMaterial); hasher.Append(data); byte[] mac = hasher.GetValueAndReset(); string macBase64 = Convert.ToBase64String(mac);Witty
Great example! I have a small addition. Creating Hex string in one row instead 5: return string.Join("", hash.Select(b => b.ToString("x2")).ToArray());Retrogradation
D
8

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.

Dormitory answered 14/3, 2014 at 14:45 Comment(2)
Worked for me. I did have to add some additional files to your list though. IHashInfo.cs (not everything was needed). ArrayExtentions.cs was also needed for .SubArray() extension method used in one of the above referenced class. The HashFactory class I shrunk down to match the ported classes -- but it does get the job done. Thanks for the hints. Originally my head was spinning looking at all the classes. Your list really helped.Deming
This works pretty good, thank you! Like rouen mentioned, IHashInfo.cs is missing in your list. Since I only needed a string to SHA1 conversion, I was able to shrink the code size to ~ 26 KB.Serum
D
7

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);
}
Dodiedodo answered 9/1, 2015 at 13:43 Comment(0)
W
6

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.

Wennerholn answered 20/4, 2012 at 23:10 Comment(3)
Could you give me some help with using it to simply hash a string? The code has virtually no commenting on it so I'm finding it hard to understand.Implode
You need to transform the string into bytes, e.g. System.Text.XXXEncoding.GetBytes(). Take great care wrt encodings (e.g. UTF8 is much better than ASCII) since different bytes will results in different hash values.Wennerholn
I dont know how to use this. Someone can help me to generate a SHA1 hash from some string?Hutchinson
D
2

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

Detrimental answered 20/4, 2012 at 23:1 Comment(0)
S
2

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

https://learn.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/

Sailing answered 19/4, 2017 at 8:33 Comment(0)
C
1

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());
    }
Carmen answered 2/3, 2018 at 13:50 Comment(0)
P
0

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]);
        }
    }
Pinion answered 11/1, 2017 at 6:10 Comment(0)
O
0

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/

Owing answered 14/8, 2017 at 18:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.