Шифрование совместимо между Android и C # - PullRequest
19 голосов
/ 19 января 2010

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

Ответы [ 5 ]

39 голосов
/ 06 февраля 2010

Получил помощь от 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);
        }
    }
}

Я действительно надеюсь, что это поможет кому-то еще!

4 голосов
/ 25 июля 2010

В приведенном примере исходного кода c # обратите внимание на следующую строку:

Encoding.ASCII.GetString(newClearData);

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

Encoding.UTF8.GetString(newClearData);

Спасибо!

1 голос
/ 03 июля 2014

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

Для более безопасной (случайной IV + хешированной) кросс-платформенной (android, ios, c #) реализации AES см. Мой ответ здесь - https://stackoverflow.com/a/24561148/2480840

1 голос
/ 20 января 2010

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

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

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

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

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

1 голос
/ 19 января 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...