首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c#中的Java加密代码

c#中的Java加密代码
EN

Stack Overflow用户
提问于 2012-08-30 13:31:38
回答 3查看 2.5K关注 0票数 0

我在安卓设备上使用了以下Java代码,这些代码使用AES加密算法和SHA1PRNG散列对字符串进行加密和解密。我希望Android设备调用用C#编写的.NET WCF服务。我一直在到处寻找,试图在C#中找到一个可以用类似于Java代码的方式进行加密和解密的等价物,但找不到完全相同的方法。下面是这两种语言的Encrypt()方法:

Java:

代码语言:javascript
复制
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#:

代码语言:javascript
复制
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个字节。

第二个问题是,尽管它们在各自的环境中都工作得很好,但当我尝试传递来自Java的加密字符串和种子时,C#代码永远无法正确解密它。这两种情况下的加密字符串看起来一点也不相似,甚至长度也不一样。Java端的典型加密字符串如下所示:F7E8758A2E65518FB49C53BC707288FC (32个字符)。而相同的加密字符串和来自C#端的相同种子看起来像这样:3VysgnYgNi9OJBxL2FP+rQ== (24个字符长度)。

我确信这与我在C#中截断散列的事实有关,但这并不能解释为什么两个加密字符串看起来有如此大的不同。(我注意到的另一件有趣的事情是,无论我在C#端使用什么字符串和种子,它总是有24个字符,并以两个等号结尾-为什么?)

因此,我的问题是,如何让两种环境都能够使用相同的种子值来解密彼此的加密字符串?我甚至不关心是否需要在Java端使用与Java端不同的算法,我只需要C#代码能够读取C#加密的字符串。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-08-30 13:45:06

第二个问题是,虽然两者在各自的环境中都能很好地工作,但当我尝试传递来自

的加密字符串以及种子时,C#代码永远无法正确解密它。

您不应该尝试解密散列。散列是单向的。

来自Java端的典型加密字符串类似于: F7E8758A2E65518FB49C53BC707288FC (32个字符)。而相同的加密字符串和来自C#端的相同种子看起来像这样: 3VysgnYgNi9OJBxL2FP+rQ== (24个字符长度)。

这是因为您在Java语言中转换为十六进制,而在C#中转换为Base64:

代码语言:javascript
复制
return toHex(encrypted);

vs

代码语言:javascript
复制
return Convert.ToBase64String(...);

至于种子长度问题--同样,您在Java和C#中做的事情是不同的。我一点也不清楚,以这种方式使用SecureRandom意味着要生成与使用来自SHA1的直接散列相同的密钥。

我建议你应该重新考虑它,而不是试图修复这种方法-它在我看来一点也不安全。你所说的种子不仅仅是一个种子--它基本上是一个完整的密钥。知道种子的攻击者有效地知道您系统的“密码”;您也可以只使用原始字节。

票数 1
EN

Stack Overflow用户

发布于 2012-08-30 15:42:40

看起来安卓使用的是SHA1PRNG的一个固定版本。此外,似乎有许多用于.NET/Java/Android的SHA1PRNG实现。

你可能想看看下面的链接,了解一些类似的问题,以及安卓系统中SHA1PRNG连接到C#的可能端口。SHA1PRNG in Android - .NET

票数 1
EN

Stack Overflow用户

发布于 2012-08-30 13:44:43

据我所知,你的toHex(encrypted);Convert.ToBase64String()不是一回事。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12190435

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档