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?
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).
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:
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());
}
来源:https://stackoverflow.com/questions/10254369/generate-sha1-hash-in-portable-class-library