2011-05-20 112 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); 
} 
}