簡體   English   中英

C#中的Java加密代碼

[英]Java encryption code in c#

我在Android設備上使用以下Java代碼,該設備使用AES加密算法和SHA1PRNG哈希對字符串進行加密和解密。 我希望Android設備調用以C#編寫的.NET WCF服務。 我一直在尋找可以找到與C#類似的方式進行加密和解密的C#等效項,但找不到與之完全相同的方法。 這是兩種語言的Encrypt()方法:

Java:

public static String encrypt(String seed, String cleartext) throws Exception 
{
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    sr.setSeed(seed);
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();

    byte[] rawKey = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(cleartext.getBytes());
    return toHex(encrypted);
}

我在C#中創建了與此類似的東西,它也使用AES和SHA1:

C#:

public static string Encrypt(string seed, string cleartext)
{
  var objAesCrypto = new AesManaged();
  var objHashSha1 = new SHA1Managed();

  var byteHash = objHashSha1.ComputeHash(Encoding.ASCII.GetBytes(seed));
  var truncatedHash = new byte[16];
  Array.Copy(byteHash, truncatedHash, truncatedHash.Length);
  objAesCrypto.Key = truncatedHash;
  objAesCrypto.Mode = CipherMode.ECB;

  var byteBuff = Encoding.ASCII.GetBytes(cleartext);
  return Convert.ToBase64String(objAesCrypto.CreateEncryptor().TransformFinalBlock(byteBuff, 0, byteBuff.Length));
}

但是,這有幾個問題。 如您所見,使用C#版本的SHA1(SHA1Managed),它將返回20字節的哈希,而不是16。將其傳遞給AES算法的唯一方法是首先將哈希截斷為16個字節。

第二個問題是,盡管兩者在各自的環境中都可以正常工作,但是當我嘗試從Java傳遞加密的字符串以及種子時,C#代碼永遠無法正確解密它。 兩種情況下的加密字符串看起來都不相同,甚至長度也不同。 從Java端看,典型的加密字符串看起來像這樣: F7E8758A2E65518FB49C53BC707288FC (32個字符長)。 而從C#端來看具有相同確切種子的相同確切加密字符串如下所示: 3VysgnYgNi9OJBxL2FP+rQ== (24個字符長)。

我確定這與我在C#中將哈希值截斷有關,但這並不能解釋為什么兩個加密字符串看起來如此不同。 (我注意到的另一件有趣的事是,無論我在C#端使用什么字符串和種子,它總是24個字符,並以兩個等號結尾-為什么?)

因此,我的問題是,如何使兩個環境都能夠使用相同的種子值解密彼此的加密字符串? 我不在乎我是否甚至需要在C#端使用與Java端不同的算法,我只需要C#代碼就能讀取Java加密的字符串。

第二個問題是,盡管兩者在各自的環境中都可以正常工作,但是當我嘗試從Java傳遞加密的字符串以及種子時,C#代碼永遠無法正確解密它。

您不應該嘗試解密哈希。 哈希是單向的。

從Java端看,典型的加密字符串看起來像這樣:F7E8758A2E65518FB49C53BC707288FC(32個字符長)。 而從C#端來看具有相同確切種子的相同確切加密字符串如下所示:3VysgnYgNi9OJBxL2FP + rQ ==(24個字符長)。

那是因為您要在Java中轉換為十六進制,但在C#中轉換為Base64:

return toHex(encrypted);

return Convert.ToBase64String(...);

至於種子長度問題-再次,您在Java和C#中做不同的事情。 對我來說一點也不清楚,以這種方式使用SecureRandom目的是生成與使用SHA1中的直接散列相同的密鑰。

我建議您應該重新考慮它,而不是嘗試解決此問題,因為它對我來說似乎並不安全。 您所稱的種子不僅僅是種子,而是一個完整的密鑰。 知道種子的攻擊者實際上知道您系統的“密碼”。 您最好只使用原始字節。

您的toHex(encrypted); 據我所知,它與Convert.ToBase64String()是不同的。

看來Android使用的是SHA1PRNG的固定版本。 對於.NET / Java / Android,SHA1PRNG似乎也有許多實現。

您可能需要查看以下鏈接,以解決一些類似的問題,以及可能存在的Android到C#的SHA1PRNG端口。 Android中的SHA1PRNG-.NET

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM