2011-05-20 107 views
37

我想利用使用C#的REST API。 API创建者已经提供了PHP,Ruby和Java中的示例库。我正在挂上它的一部分,我需要生成一个HMAC如何在C#中生成HMAC-SHA1?

下面是他们提供的示例库中的工作方式。

PHP

hash_hmac('sha1', $signatureString, $secretKey, false); 

红宝石

digest = OpenSSL::Digest::Digest.new('sha1') 
return OpenSSL::HMAC.hexdigest(digest, secretKey, signatureString) 

的Java

SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(), HMAC_SHA1_ALGORITHM); 

Mac mac = null; 
mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); 
mac.init(signingKey); 

byte[] bytes = mac.doFinal(signatureString.getBytes()); 

String form = ""; 
for (int i = 0; i < bytes.length; i++) 
{ 
    String str = Integer.toHexString(((int)bytes[i]) & 0xff); 
    if (str.length() == 1) 
    { 
     str = "0" + str; 
    } 

    form = form + str; 
} 
return form; 

这里是我的ATT在C#中抢占。 它不工作。 更新:下面的C#示例工作得很好。我发现真正的问题是由于我的signatureString中的换行字符存在一些跨平台差异。

var enc = Encoding.ASCII; 
HMACSHA1 hmac = new HMACSHA1(enc.GetBytes(secretKey)); 
hmac.Initialize(); 

byte[] buffer = enc.GetBytes(signatureString); 
return BitConverter.ToString(hmac.ComputeHash(buffer)).Replace("-", "").ToLower(); 
+1

原来我的C#代码工作得很好。真正的问题是由于我的'signatureString'中的换行字符存在一些跨平台差异。我会将此问题标记为删除。 – jessegavin 2011-05-20 17:07:25

+4

不要删除问题,而是将您的代码作为答案发布并接受它。这个问题在寻求做同样的事情时非常有用。 – 2015-12-04 11:08:26

+0

我在文本“The API responds ...”上添加了更多更新以避免潜在的误解 – 2016-10-27 09:39:00

回答

5

试试这个:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha1.aspx

快速和肮脏的代码:

public string Encode(string input, byte [] key) 
{ 
     HMACSHA1 myhmacsha1 = new HMACSHA1(key); 
     byte[] byteArray = Encoding.ASCII.GetBytes(input); 
     MemoryStream stream = new MemoryStream(byteArray); 
     byte[] hashValue = myhmacsha1.ComputeHash(stream); 
     return hashValue.ToString(); 
} 
+1

感谢您的答复。但是,你的代码返回字符串'System.Byte []'。所以我将最后一行修改为'返回BitConverter.ToString(hashValue).Replace(“ - ”,“”)。ToLower()'但我仍然无法获得这个c#代码来生成与其他语言相同的散列。 – jessegavin 2011-05-20 15:54:46

+6

超级晚但'string.Join(“”,Array.ConvertAll(hashValue,b => b.ToString(“x2”)))'应该工作。 – 2013-01-31 04:43:43

25

的扩展,Vimvq1987's answer

return hashValue.ToString();不会产生你想要的输出/需要。您必须将数组hashValue中的字节转换为它们的十六进制字符串表示形式。
可以简单的return BitConverter.toString(hashValue);(打印大写字母AF),或者如果你喜欢复杂一点:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Security.Cryptography; 
using System.IO; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     public static string Encode(string input, byte[] key) 
     { 
      HMACSHA1 myhmacsha1 = new HMACSHA1(key); 
      byte[] byteArray = Encoding.ASCII.GetBytes(input); 
      MemoryStream stream = new MemoryStream(byteArray); 
      return myhmacsha1.ComputeHash(stream).Aggregate("", (s, e) => s + String.Format("{0:x2}",e), s => s); 
     } 


     static void Main(string[] args) 
     { 
      byte[] key = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwxyz"); 
      string input = ""; 
      foreach (string s in new string[] { "Marry", " had", " a", " little", " lamb" }) 
      { 
       input += s; 
       System.Console.WriteLine(Encode(input, key)); 
      } 
      return; 
     } 
    } 
} 

它打印

3545e064fb59bc4bfc02b6e1c3d4925c898aa504 
3249f4c8468d4d67f465937da05b809eaff22fdb 
87baaadf5d096677f944015e53d283834eb1e943 
6325376820c29a09e3ab30db000033aa71d6927d 
54579b0146e2476595381d837ee38863be358213 

,我得到了完全相同的结果

<?php 
$secretKey = 'abcdefghijklmnopqrstuvwxyz'; 

$signatureString = ''; 
foreach(array('Marry',' had',' a',' little',' lamb') as $s) { 
    $signatureString .= $s; 
    echo hash_hmac('sha1', $signatureString, $secretKey, false), "\n"; 
} 

编辑:Dmitriy Nemykin建议以下编辑

被拒绝。但正如詹姆斯在评论这个答案时已经指出的那样,至少using statement的一个好点。

+0

'myhmacsha1.ComputeHash(stream).Aggregate'给出错误:Aggregate没有为System.array定义。我错过了什么? – 2011-12-26 13:20:32

+0

取决于您使用的.net版本,请参阅http://msdn.microsoft.com/en-us/library/bb548651%28v=VS.90%29.aspx – VolkerK 2011-12-26 20:23:43

+0

ho。就是这样。谢谢。 – 2011-12-27 06:44:56

15

这个网站有不同的语言一些不错的例子:http://jokecamp.wordpress.com/2012/10/21/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/

在写作时的C#实现是:

private string CreateToken(string message, string secret) 
{ 
secret = secret ?? ""; 
var encoding = new System.Text.ASCIIEncoding(); 
byte[] keyByte = encoding.GetBytes(secret); 
byte[] messageBytes = encoding.GetBytes(message); 
using (var hmacsha256 = new HMACSHA256(keyByte)) 
{ 
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); 
return Convert.ToBase64String(hashmessage); 
} 
}