【问题标题】:Encryption compatible between Android and C#Android和C#之间的加密兼容
【发布时间】:2011-01-06 15:21:49
【问题描述】:

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

【问题讨论】:

  • 链接已失效。你能添加你用于Android的代码sn-p吗?

标签: c# java .net android encryption


【解决方案1】:

得到了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);
        }
    }
}

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

【讨论】:

  • 是的......我喜欢人们用一堆“哦,你应该这样做”或“哦,你应该这样做”来回答我的技术问题。感谢您的实际操作并离开您的课程实施。
  • 我已经用你的 Java 代码加密了我的文件内容,并将加密的内容保存到 encrypted.txt 中。现在我想使用以下命令使用 openssl 工具对其进行解密: openssl enc -d -a -p -aes-256-cbc -salt -in encrypted.txt -out decrypted.txt -pass pass:myPassword 但我收到错误:糟糕的幻数。知道有什么问题吗?即使我从命令中删除 -salt 参数,我仍然会收到同样的错误。
  • @uerceg:您将要为此提出一个新问题。这个解决方案不使用 OpenSSL,所以我不希望它起作用。
  • 你有没有使用 Base64.encodeToString(encryptedData, Base64.DEFAULT) 而不是 net.iharder.base64.Base64.encodeBytes(encryptedData) 的原因?
  • @user1105748 Base64 引入了 API 级别 8,该级别在此答案后三个月发布。
【解决方案2】:

在提供的 c# 源代码示例中,注意这一行:

Encoding.ASCII.GetString(newClearData);

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

Encoding.UTF8.GetString(newClearData);

谢谢!

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

      编辑:我收回这一点,它没有使用 ECB,但它生成 IV 的方式是不切实际的。无论如何,我关于理解块模式含义的观点是站得住脚的。

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

      至于对字符串进行编码,如果必须将字符串转换为 ASCII 文本,Base64 也是一种不错的方法,但我建议您研究使用 HTTP PUT 或 POST 来省去这额外的步骤。

      【讨论】:

        【解决方案5】:

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

        如需更安全(随机 IV + 散列密钥)跨平台(android、ios、c#)实现 AES,请在此处查看我的答案 - https://stackoverflow.com/a/24561148/2480840

        【讨论】:

          猜你喜欢
          • 2010-09-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-02
          相关资源
          最近更新 更多