Android和C#之间的加密兼容

时间:2010-01-19 03:00:50

标签: c# java .net android encryption

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

5 个答案:

答案 0 :(得分:39)

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);
        }
    }
}

我真的希望这有助于其他人!

答案 1 :(得分:4)

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

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

您可以从wikipedia article开始。 Bruce Schneier的书“Practical Cryptography'对于实施加密安全性的人来说也是非常有价值的。

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

答案 4 :(得分:1)

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

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