2012-11-24 85 views
3

我想轉換一個基於java的代碼爲c#,如下所示;無法獲得相同的hmac_sha1結果爲java和c#(winrt)

原始的java代碼;

String str2 = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*" 

Mac localMac = Mac.getInstance("HmacSHA1"); 
localMac.init(new SecretKeySpec("Wd75Yj9sS26Lmhve".getBytes(), localMac.getAlgorithm())); 
String str3 = new BigInteger(1, localMac.doFinal(str2.getBytes())).toString(16); 
Object[] arrayOfObject2 = new Object[2]; 
arrayOfObject2[0] = str3; 
arrayOfObject2[1] = URLEncoder.encode(str2); 
String str4 = String.format("%s:%s", arrayOfObject2); 

這裏是我的基於WinRT的C#代碼

var token="5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*"; 

var encoding = new System.Text.UTF8Encoding(); 
var key = encoding.GetBytes("Wd75Yj9sS26Lmhve"); 
//var key = Convert.FromBase64String("Wd75Yj9sS26Lmhve"); 

var tokenData = encoding.GetBytes(token); 

var result = HmacSha1(key, tokenData); 

var hexString = new BigInteger(result).ToString("x"); 
var urlEncoded = System.Net.WebUtility.UrlEncode(token); 

var combined = String.Format("{0}:{1}", hexString, urlEncoded); 

和我在WinRT中運行HMACSHA1功能;

public static byte[] HmacSha1(byte[] key, byte[] data) 
    { 
     var crypt = Windows.Security.Cryptography.Core.MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1"); 
     var keyBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(key); 
     var cryptKey = crypt.CreateKey(keyBuffer); 

     var dataBuffer = Windows.Security.Cryptography.CryptographicBuffer.CreateFromByteArray(data); 
     var signBuffer = Windows.Security.Cryptography.Core.CryptographicEngine.Sign(cryptKey, dataBuffer); 

     byte[] result; 
     Windows.Security.Cryptography.CryptographicBuffer.CopyToByteArray(signBuffer, out result); 

     return result; 
    } 

所以這裏是相應的outpus;

(JAVA) 92e893efe72a2f7df6ed409ce35819faba191a63:5f1fa09364a6ae7e35a090b434f182652ab8dd76%3A%7B%22expiration%22%3A+1353759442.0991001%2C+%22channel%22%3A+%22dreamhacksc2%22%2C+%22user_agent%22%3A+%22.* 
    (C#) 63b10e1d8e9f99cd7fba2ed46fe8e4a4a40222f5:5f1fa09364a6ae7e35a090b434f182652ab8dd76%3A%7B%22expiration%22%3A+1353759442.0991001%2C+%22channel%22%3A+%22dreamhacksc2%22%2C+%22user_agent%22%3A+%22.* 

如上所示,來自java和c#的HMAC_SHA1的輸出不相等。有任何想法嗎?我運行編碼問題?

+0

我會是怎樣寫評論我如果你對這個問題投了反對票。 – HuseyinUslu

+0

對於不清楚C#和Java輸出可能不正確的情況,不要修改您的問題。這是一個相當本地化的問題。調試的最佳方法是在將其傳遞到HMAC代碼之前,使用(更好的)十六進制編碼打印出所有密鑰和數據。 –

回答

4

只是保持簡單,代碼相同。

的Java:

public static String toHexString(byte[] bytes) { 
    StringBuilder sb = new StringBuilder(bytes.length * 2); 
    for (int i = 0; i < bytes.length; ++i) { 
     sb.append(String.format("%02x", bytes[i])); 
    } 
    return sb.toString(); 
} 

public static void main(String[] args) { 
    String str2 = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*"; 
    Mac localMac; 
    try { 
     localMac = Mac.getInstance("HmacSHA1"); 

     localMac.init(new SecretKeySpec("Wd75Yj9sS26Lmhve" 
       .getBytes("UTF-8"), localMac.getAlgorithm())); 
     byte[] result = localMac.doFinal(str2.getBytes("UTF-8")); 
     String hexString = toHexString(result); 
     System.out.println(hexString); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } catch (InvalidKeyException e) { 
     e.printStackTrace(); 
    } catch (IllegalStateException e) { 
     e.printStackTrace(); 
    } catch (UnsupportedEncodingException e) { 
     e.printStackTrace(); 
    } 

} 

結果:

f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163 

C#:

var token = "5f1fa09364a6ae7e35a090b434f182652ab8dd76:{\"expiration\": 1353759442.0991001, \"channel\": \"dreamhacksc2\", \"user_agent\": \".*"; 

var encoding = new System.Text.UTF8Encoding(); 
var privateKey = "Wd75Yj9sS26Lmhve"; 
HMACSHA1 hmac_sha1 = new HMACSHA1(encoding.GetBytes(privateKey)); 
hmac_sha1.Initialize(); 
byte[] result = hmac_sha1.ComputeHash(encoding.GetBytes(token)); 

string hexString = String.Join("", result.Select(a => a.ToString("x2"))); 

Console.WriteLine(hexString); 

結果:

f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163 
4

的三大祕訣:

  1. 當我測試你的Java代碼,我收到了STR3這個值:f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163這不同於Java和C#的結果發表你。 (This online tool也計算我的結果。)

  2. Wikipedia包含一個example,它似乎是正確的基於Java代碼和在線計算器。在第一步中,使用"The quick brown fox jumps over the lazy dog", "key", "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"三元組測試Java和C#代碼。

  3. 使用BigInterger.toString(16)將字節數組轉換爲十六進制字符串不是一個好主意,因爲當字節數組以一個或多個零位(或hexit?)開頭時,轉換後的十六進制字符串將不會包含前導0個字符。

+0

你是對的,[代碼](https://compilr.com/raistlinthewiz/hmac-sha1-test)計算f52202a4a4e4e86fd42eba7fcd999f8e1d0eb163作爲輸出。現在嘗試修復我的C#代碼。 – HuseyinUslu

+0

現在我得到一個完全不同的哈希70F4E22B2600225A3151727323B0CAB40B325045與[c#代碼](https://compilr.com/raistlinthewiz/hmac-sha1-csharp-test)使用.net 4.0的System.Security.Cryptography的東西。我現在完全困惑.. – HuseyinUslu

1

你正在混淆字節與字符串。 getBytes()的結果取決於默認,這可能因系統而異。

+0

所以任何想法在基於Windows的主機上的Java的默認編碼? – HuseyinUslu

+0

@HuseyinUslu它依賴於它似乎的語言設置。一般而言,它不是* UTF-8,而是基於ISO 8859標準的Windows專有方案之一,用於8位字符編碼。對於任何ASCII碼,它們和UTF-8應該是兼容的。沒有其他的東西(包含相當常見的基於UTF-16的方案)。 –

相關問題