Android和C#之间的加密兼容

我已经find了很多关于如何在C#中进行加密的示例,以及一对用于Android的加密,但我特别想find一种方法来处理来自Android的加密(使用类似AES,TripleDES等),并最终结束在C#中解密。 我find了一个在Android中编码AES和在C#中编码/解码AES的示例,但我不确定它们是否兼容(C#需要IV,在Android示例中没有为此指定)。 另外,关于编码加密字符串以便通过HTTP(Base64?)传输的好方法的建议会很有帮助。 谢谢。

Related of "Android和C#之间的加密兼容"

从http://oogifu.blogspot.com/2009/01/aes-in-java-and-c.html获得了一些帮助。

这是我的Java类:

package com.neocodenetworks.smsfwd; import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; import android.util.Log; public class Crypto { public static final String TAG = "smsfwd"; private static Cipher aesCipher; private static SecretKey secretKey; private static IvParameterSpec ivParameterSpec; private static String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding"; private static String CIPHER_ALGORITHM = "AES"; // Replace me with a 16-byte key, share between Java and C# private static byte[] rawSecretKey = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; private static String MESSAGEDIGEST_ALGORITHM = "MD5"; public Crypto(String passphrase) { byte[] passwordKey = encodeDigest(passphrase); try { aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION); } catch (NoSuchAlgorithmException e) { Log.e(TAG, "No such algorithm " + CIPHER_ALGORITHM, e); } catch (NoSuchPaddingException e) { Log.e(TAG, "No such padding PKCS5", e); } secretKey = new SecretKeySpec(passwordKey, CIPHER_ALGORITHM); ivParameterSpec = new IvParameterSpec(rawSecretKey); } public String encryptAsBase64(byte[] clearData) { byte[] encryptedData = encrypt(clearData); return net.iharder.base64.Base64.encodeBytes(encryptedData); } public byte[] encrypt(byte[] clearData) { try { aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec); } catch (InvalidKeyException e) { Log.e(TAG, "Invalid key", e); return null; } catch (InvalidAlgorithmParameterException e) { Log.e(TAG, "Invalid algorithm " + CIPHER_ALGORITHM, e); return null; } byte[] encryptedData; try { encryptedData = aesCipher.doFinal(clearData); } catch (IllegalBlockSizeException e) { Log.e(TAG, "Illegal block size", e); return null; } catch (BadPaddingException e) { Log.e(TAG, "Bad padding", e); return null; } return encryptedData; } private byte[] encodeDigest(String text) { MessageDigest digest; try { digest = MessageDigest.getInstance(MESSAGEDIGEST_ALGORITHM); return digest.digest(text.getBytes()); } catch (NoSuchAlgorithmException e) { Log.e(TAG, "No such algorithm " + MESSAGEDIGEST_ALGORITHM, e); } return null; } } 

我使用http://iharder.sourceforge.net/current/java/base64/作为base64编码。

这是我的C#类:

 using System; using System.Text; using System.Security.Cryptography; namespace smsfwdClient { public class Crypto { private ICryptoTransform rijndaelDecryptor; // Replace me with a 16-byte key, share between Java and C# private static byte[] rawSecretKey = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; public Crypto(string passphrase) { byte[] passwordKey = encodeDigest(passphrase); RijndaelManaged rijndael = new RijndaelManaged(); rijndaelDecryptor = rijndael.CreateDecryptor(passwordKey, rawSecretKey); } public string Decrypt(byte[] encryptedData) { byte[] newClearData = rijndaelDecryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length); return Encoding.ASCII.GetString(newClearData); } public string DecryptFromBase64(string encryptedBase64) { return Decrypt(Convert.FromBase64String(encryptedBase64)); } private byte[] encodeDigest(string text) { MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] data = Encoding.ASCII.GetBytes(text); return x.ComputeHash(data); } } } 

我真的希望这可以帮助别人!

在提供的c#源代码示例中,请注意以下行:

 Encoding.ASCII.GetString(newClearData); 

UTF-8是Android的默认编码,因此加密字符串(尤其是非ASCII字符,如中文)将传递给C#,假定为UTF-8。 如果使用ASCII编码解码回字符串,则文本变得混乱。 这是一个更好的,

 Encoding.UTF8.GetString(newClearData); 

谢谢!

是的,它应该没问题,只要我们的密钥大小相同 – 128位AES和正确的分组密码模式(CBC)。 您可能会遇到填充问题,但这应该很容易理清。 我最近遇到了Java和Python的这些问题,但最终得到了一切。 用于编码的Base64应该可以胜过HTTP。 祝你好运!

如果您在两端正确实现相同的密码(如AES)和模式(如CTR,CFB,CCM等),则无论平台如何,一端的密文都可以被另一端解密。

您链接到的Android示例似乎使用ECB模式,因此对您的目的而言并不安全。 了解所选块模式的含义至关重要。 在这个级别上很容易出现加密错误,导致系统不像你想象的那么安全。

编辑:我把它拿回来,它不使用ECB,但它产生IV的方式是不实际的。 无论如何,我关于理解块模式含义的观点是有道理的。

你可以从这篇维基百科文章开始。 Bruce Schneier的书“ Practical Cryptography”对于实现加密安全性的任何人来说都是非常有价值的。

至于对字符串进行编码,如果必须将字符串转换为ASCII文本,Base64就像任何一种方式一样好,但我建议您调查使用HTTP PUT或POST来为您节省额外的步骤。

互联网上的大多数例子都是AES的弱实现。 为了实现强大,应始终使用随机IV,并且应对密钥进行哈希处理。

对于更安全(随机IV +哈希键)跨平台(android,ios,c#)的AES实现,请参阅我的答案 – https://stackoverflow.com/a/24561148/2480840