代码之家  ›  专栏  ›  技术社区  ›  Jess

Android和C之间的加密兼容#

  •  19
  • Jess  · 技术社区  · 15 年前

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

    5 回复  |  直到 8 年前
        1
  •  40
  •   Jess    15 年前

    得到了我的一些帮助 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/

    这是我的课程:

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

    我真的希望这能帮助别人!

        2
  •  4
  •   wye    14 年前

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

    Encoding.ASCII.GetString(newClearData);
    

    UTF-8是Android的默认编码,因此加密字符串(特别是非ASCII字符,如中文)将传递给C#,假设为UTF-8。如果使用ASCII编码解码回字符串,文本将被置乱。这是一个更好的,

    Encoding.UTF8.GetString(newClearData);
    

    谢谢

        3
  •  1
  •   Jonathan Holloway    15 年前

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

        4
  •  1
  •   anelson    15 年前

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

    你可以从这个开始 wikipedia article Practical Cryptography' 对于任何实现加密安全的人来说都是非常有价值的。

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

        5
  •  1
  •   Community CDub    8 年前

    internet上的大多数示例都是AES的弱实现。为了使实现强大,应该始终使用random IV,并对密钥进行散列。

    有关AES更安全(随机IV+散列密钥)的跨平台(android、ios、c#)实现,请参见我的答案- https://stackoverflow.com/a/24561148/2480840