Подтвердить что ты не робот

Шифрование, совместимое между Android и С#

Я нашел множество примеров, как делать шифрование на С#, и пару для Android, но я особенно ищу способ обработки шифрования (используя что-то вроде AES, TripleDES и т.д.) с Android, и в конечном итоге заканчивается расшифровкой на С#. Я нашел пример для кодирования AES в Android и кодирование/декодирование AES в С# но я не уверен, совместимы ли они (для С# требуется IV, для Android в этом случае ничего не указано). Кроме того, была бы полезной рекомендация по хорошему способу кодирования зашифрованной строки для передачи по HTTP (Base64?). Спасибо.

4b9b3361

Ответ 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.

Здесь мой класс С#:

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

В представленном примере исходного кода С# следите за этой строкой:

Encoding.ASCII.GetString(newClearData);

UTF-8 является кодировкой по умолчанию для Android, поэтому зашифрованная строка (особенно символы, отличные от ASCII, такие как китайский) будут переданы на С#, предполагая UTF-8. Текст становится скремблированным, если декодируется обратно в строку с использованием кодировки ASCII. Вот лучший,

Encoding.UTF8.GetString(newClearData);

Спасибо!

Ответ 3

Да, это должно быть хорошо, так как мы ключи одинаковы - 128 бит AES и правильный режим блочного шифрования (CBC). Вы можете столкнуться с проблемами с заполнением, но это должно быть довольно легко разобраться. Недавно я столкнулся с этими проблемами с Java и Python, но в итоге все работало. Base64 для кодирования должен быть в порядке по HTTP. Удачи!

Ответ 4

Если вы правильно реализуете один и тот же шифр (например, AES) и режим (например, CTR, CFB, CCM и т.д.) на обоих концах, зашифрованный текст с одного конца может быть расшифрован другим концом независимо от платформы.

Приведенный вами пример Android, похоже, используется в режиме ECB и, таким образом, не защищен для ваших целей. Крайне важно, чтобы вы понимали последствия выбранного вами блочного режима. Очень легко получить криптограмму на этом уровне, в результате чего система не так безопасна, как вы думаете.

РЕДАКТИРОВАТЬ: Я беру это обратно, это не использование ECB, но способ, которым он генерирует IV, не является практичным. В любом случае, моя точка зрения о понимании последствий блочных режимов стоит.

Вы можете начать с этой статьи wikipedia. Книга Брюса Шнайера "" Практическая криптография" также чрезвычайно ценна для тех, кто внедряет криптографическую безопасность.

Что касается кодирования строки, если вы должны преобразовать строку в ASCII-текст, Base64 будет таким же хорошим способом, как любой, но я бы предложил вам изучить использование HTTP PUT или POST, чтобы избавить вас от этого дополнительного шага.

Ответ 5

Большинство примеров в Интернете - это слабая реализация AES. Чтобы реализация была сильной, случайный IV должен использоваться все время, а ключ должен быть хэширован.

Для более безопасного (случайного IV + хэшированного ключа) кросс-платформенная (android, ios, С#) реализация AES см. мой ответ здесь - fooobar.com/info/139158/...