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

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

19
задан Community 23 May 2017 в 12:25
поделиться

4 ответа

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

Я очень надеюсь, что это поможет кому-то другому!

40
ответ дан 30 November 2019 в 02:48
поделиться

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

1
ответ дан 30 November 2019 в 02:48
поделиться

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

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

Редактировать: Я беру это обратно, он не использует ECB, но так, как он генерирует IV, не является практичным. В любом случае, моя точка зрения о понимании последствий мод блока стендует.

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

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

1
ответ дан 30 November 2019 в 02:48
поделиться

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

Encoding.ASCII.GetString(newClearData);

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

Encoding.UTF8.GetString(newClearData);

Спасибо!

4
ответ дан 30 November 2019 в 02:48
поделиться