我正在尝试构建一个可移植的类库,为其他类/应用程序生成OAuth URL。这个使用OAuth的类库必须是一个可移植的类库,因此它可以与我正在构建的DropBox API的不同版本一起使用。
此类的一部分需要生成SHA1哈希以生成oauth_signature。
我知道可移植类库不支持System.Security.Cryptography,所以无论如何这个类可以生成没有该类的SHA1哈希?
Mono为它自己的managed implementation of SHA1提供了mscorlib.dll
(但它不像@CodeInChaos建议的那样位于Mono.Security.dll
)。
它是开源的,经过严格测试,意味着完全像微软的实现(例如它来自SHA1
,HashAlgorith
......实现ICryptoTransform
......)所以它应该是一个简单的替代品。
我认为最简单的方法是使用PCLCrypto nuget包。然后你可以这样做:
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();
}
好吧,我最近也需要这个,我发现从HashLib中获取SHA1实现要容易得多:http://hashlib.codeplex.com/
Mono实现具有一些远程依赖(异常的本地化等),而从HashLib,您只需要复制几个文件而不需要对它们进行任何更改:
Converters.cs
Hash.cs
HashBuffer.cs
HashCryptoNotBuildIn.cs
HashResult.cs
IHash.cs
SHA0.cs
SHA1.cs
总共55 KB的代码,所以没有太重。
我使用过这个BouncyCastle Nuget包:https://www.nuget.org/packages/BouncyCastle-PCL/,它对我来说很好用(跨平台Windows应用商店应用,.Net Framework 4.5,Silverlight 5,Windows Phone 8,Xamarin.Android,Xamarin.iOS)
使用HMACSHA1生成如下签名:
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);
}
SHA-1 Wikipedia article包含伪代码,您可以将其用作自己实现的指南。但是,与加密函数一样,我强烈建议使用经过试验和测试的实现。
假设您需要SHA-256实现,可以在BouncyCastle中找到一个,它以源代码形式提供。那里的相关课叫做Org.BouncyCastle.Crypto.Digests.Sha256Digest(这里是它的source)。
您可能想要查看新的.NET标准库:
https://docs.microsoft.com/en-us/dotnet/articles/standard/library
它是便携式的,包括System.Security.Cryptography
。
/// <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();
}
}
您也可以在这里获得一些帮助(用于创建带有.NET标准库的PCL项目):
我也希望签署OAuth,并且正在查看PCL加密 - 此测试显示了HmacSha1哈希的创建,并将结果与标准.NET Framework方式进行了比较。
[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]);
}
}
当我必须达到同样的结果时,这对我有用。你可以用SHA512
和其他人这样做。
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)));
}
}
以下是使用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());
}