Android 和 C# 之间的加密兼容
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2090765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Encryption compatible between Android and C#
提问by Jess
I've found plenty of examples how to do encryption in C#, and a couple for Android, but I'm particularly looking for a way to handle encrypting (using something like AES, TripleDES, etc.) from Android, and eventually wind up being decrypted in C#. I found an example for encoding AESin Android and encoding/decoding AESin C# but am not sure if these are compatible (C# requires an IV, nothing is specified for this in the Android example). Also, a recommendation on a good way of encoding the encrypted string for transmission over HTTP (Base64?) would be helpful. Thanks.
我找到了很多如何在 C# 中进行加密的示例,还有一些用于 Android 的示例,但我特别在寻找一种方法来处理来自 Android 的加密(使用 AES、TripleDES 等),并最终结束在 C# 中解密。我找到了一个在 Android 中编码 AES和在 C# 中编码/解码 AES的示例,但我不确定它们是否兼容(C# 需要一个 IV,在 Android 示例中没有为此指定任何内容)。此外,关于对通过 HTTP(Base64?)传输的加密字符串进行编码的好方法的建议会有所帮助。谢谢。
采纳答案by Jess
Got some help from http://oogifu.blogspot.com/2009/01/aes-in-java-and-c.html.
从http://oogifu.blogspot.com/2009/01/aes-in-java-and-c.html得到了一些帮助。
Here is my Java class:
这是我的 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;
}
}
I used http://iharder.sourceforge.net/current/java/base64/for the base64 encoding.
我使用http://iharder.sourceforge.net/current/java/base64/作为 base64 编码。
Here's my C# class:
这是我的 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);
}
}
}
I really hope this helps someone else!
我真的希望这可以帮助别人!
回答by Jon
Yes it should be fine, as long we the keysize is the same - 128 bit AES and the correct block cipher mode (CBC). You might run into issues with padding, but that should be fairly easy to sort out. I ran into these issues with Java and Python recently, but got everything working in the end. Base64 for encoding should be fine over HTTP. Good luck!
是的,应该没问题,只要我们的密钥大小相同 - 128 位 AES 和正确的分组密码模式 (CBC)。您可能会遇到填充问题,但这应该很容易解决。我最近在使用 Java 和 Python 时遇到了这些问题,但最终一切正常。用于编码的 Base64 在 HTTP 上应该没问题。祝你好运!
回答by anelson
If you correctly implement the same cipher (like AES) and mode (like CTR, CFB, CCM, etc) on both ends, the ciphertext from one end can be decrypted by the other end regardless of platform.
如果您在两端正确实现相同的密码(如 AES)和模式(如 CTR、CFB、CCM 等),则无论平台如何,一端的密文都可以被另一端解密。
The Android example you linked to appears to use the ECB mode, and thus is not secure for your purposes. It's critically important that you understand the implications of the block mode you select. It's very easy to get crypto wrong at this level, resulting in a system that's not as secure as you think it is.
您链接到的 Android 示例似乎使用 ECB 模式,因此对您而言不安全。了解所选块模式的含义至关重要。在这个级别上很容易弄错加密,导致系统不像你想象的那么安全。
EDIT: I take that back, it's not using ECB, but the way it generates the IV is not practical. In any case, my point about understanding the implications of the block modes stands.
编辑:我收回,它没有使用欧洲央行,但它生成 IV 的方式不切实际。无论如何,我关于理解块模式的含义的观点是站得住脚的。
You can start with this wikipedia article. Bruce Schneier's book 'Practical Cryptography'is also hugely valuable to anyone implementing cryptographic security.
您可以从这篇维基百科文章开始。Bruce Schneier 的《实用密码学》一书对任何实施密码安全的人也非常有价值。
As to encoding the string, if you must convert the string into ASCII text Base64 is as good a way as any, but I would suggest you investigate use of HTTP PUT or POST to spare you this additional step.
至于对字符串进行编码,如果您必须将字符串转换为 ASCII 文本,Base64 与任何方法一样好,但我建议您研究使用 HTTP PUT 或 POST 来省去这个额外的步骤。
回答by wye
In the provided c# source code sample, watch out this line:
在提供的 c# 源代码示例中,注意这一行:
Encoding.ASCII.GetString(newClearData);
UTF-8 is the default encoding for Android, so encrypted string (especially non-ASCII chars such as Chinese) will be passed to C# assuming UTF-8. The text becomes scrambled if decoded back to string using ASCII encoding. Here is a better one,
UTF-8 是 Android 的默认编码,因此加密的字符串(尤其是非 ASCII 字符,如中文)将被传递给 C# 假设 UTF-8。如果使用 ASCII 编码将文本解码回字符串,则文本会被打乱。这是一个更好的,
Encoding.UTF8.GetString(newClearData);
Thanks!
谢谢!
回答by Navneet Kumar
Most of the examples on internet are weak implementation of AES. For an implementation to be strong, random IV should be used all the time and key should be hashed.
互联网上的大多数示例都是 AES 的弱实现。为了实现强大的功能,应该一直使用随机 IV,并且应该对密钥进行散列。
For more secure(random IV + hashed key) cross platform (android, ios, c#) implementation of AES see my answer here - https://stackoverflow.com/a/24561148/2480840
有关 AES 的更安全(随机 IV + 散列密钥)跨平台(android、ios、c#)实现,请在此处查看我的答案 - https://stackoverflow.com/a/24561148/2480840