Android: расшифровать текст RSA с помощью открытого ключа, хранящегося в файле - программирование
Подтвердить что ты не робот

Android: расшифровать текст RSA с помощью открытого ключа, хранящегося в файле

Я несколько дней пытался сделать это без успеха.

В StackOverflow есть много подобных вопросов, и даже два из них точно такие же, как мои, но не ответили и не были решены: 1) Преобразование PHP RSA PublicKey в Android PublicKey 2) Android: как расшифровать зашифрованный файл openssl с ключом RSA?

Мой сценарий: У меня есть текст, зашифрованный с помощью RSA (не зашифрованный мной). У меня есть файл public.key в моей папке res/raw с открытым ключом, необходимым для его расшифровки (открытый ключ, связанный с закрытым ключом, используемым для шифрования сообщения), с таким форматом, как в следующем примере: enter image description here

Я вижу много примеров того, как расшифровать текст RSA, например следующий:

public static byte[] decryptRSA( PublicKey key, byte[] text) throws Exception
      { 
          byte[] dectyptedText = null;

          Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
          cipher.init(Cipher.DECRYPT_MODE, key);
          dectyptedText = cipher.doFinal(text);
          return dectyptedText;
      }

Но мой вопрос: как получить правильный экземпляр PublicKey из файла? Нет примеров этого.

Если я просто попробую:

    InputStream is = getResources().openRawResource(R.raw.public);
    DataInputStream dis = new DataInputStream(is);
    byte [] keyBytes = new byte [(int) is.available()];
    dis.readFully(keyBytes);
    dis.close();
    X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePublic(spec);

Я получаю InvalidKeyException в возвращаемом предложении. Должен ли я декодировать Hex или Base64? Не проблема в первой и последней строках файла открытого ключа (те, у кого есть "---- BEGIN PUBLIC KEY ----" и т.д.)?

Возможно, мы можем получить ответ об этом в первый раз в StackOverflow: -)

4b9b3361

Ответ 1

Наконец-то решил!!! Барабаны, трубы и симфония феерических звуков!!!

public static byte[] decryptRSA(Context mContext, byte[] message) throws Exception { 

    // reads the public key stored in a file
    InputStream is = mContext.getResources().openRawResource(R.raw.sm_public);
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    List<String> lines = new ArrayList<String>();
    String line = null;
    while ((line = br.readLine()) != null)
        lines.add(line);

    // removes the first and last lines of the file (comments)
    if (lines.size() > 1 && lines.get(0).startsWith("-----") && lines.get(lines.size()-1).startsWith("-----")) {
        lines.remove(0);
        lines.remove(lines.size()-1);
    }

    // concats the remaining lines to a single String
    StringBuilder sb = new StringBuilder();
    for (String aLine: lines)
        sb.append(aLine);
    String keyString = sb.toString();
    Log.d("log", "keyString:"+keyString);

    // converts the String to a PublicKey instance
    byte[] keyBytes = Base64.decodeBase64(keyString.getBytes("utf-8"));
    X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey key = keyFactory.generatePublic(spec);

    // decrypts the message
    byte[] dectyptedText = null;
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, key);
    dectyptedText = cipher.doFinal(Base64.decodeBase64(message));
    return dectyptedText;
}

Решение состояло в том, чтобы Base64 декодировал не только открытый ключ, прочитанный из файла, но и само зашифрованное сообщение!

Кстати, я прочитал открытый ключ из файла так, как предложил @Nikolay (tnx again man).

Спасибо вам большое за вашу помощь. Скалы StackOverflow!

Ответ 2

Вам не хватает ключевого слова - общедоступные и закрытые ключи являются отдельными, и вы не можете рассчитать их на основе другого. Это своего рода точка шифрования с открытым ключом. Проблемы с использованием необработанного RSA в стороне, если у вас что-то зашифровано открытым ключом, для его расшифровки необходимо иметь соответствующий закрытый ключ. И наоборот. Поэтому, если у вас есть файл открытого ключа, вы можете получить только открытый ключ. Это было бы полезно, только если ваши данные были зашифрованы с помощью соответствующего закрытого ключа.

Что касается фактического исключения: удалите строки "---" в начале и конце, используйте Base64.decode(), чтобы получить массив байтов, и используйте это для создания X509EncodedKeySpec. Один из способов сделать это - используйте что-то вроде BufferedReader для чтения по строкам, игнорируйте строки "---" и разделите остальные на один большой String.

Ответ 3

Открытые ключи могут только шифровать данные. Открытые ключи не могут расшифровывать данные. Вы можете расшифровывать данные только с помощью закрытого ключа. Все дело в том, что вы можете раздавать открытый ключ всем и каждому, и они могут отправлять вам зашифрованные сообщения, которые могут видеть только владелец частного ключа.

Вам действительно нужно быть очень осторожным с использованием технологии шифрования. Я боюсь, вы просто собираетесь распространять секретный ключ на все ваши устройства, что ослабит вашу безопасность, поскольку каждый будет иметь тот же секретный ключ. Поэтому, если я хочу взломать вашу безопасность, я просто перехожу к Google Play и загружаю приложение и вытаскиваю секретный ключ из вашего приложения. Виола Я вижу все.

Итак, у вас есть ответ, почему это не сработает, но вам теперь нужно дать совет о дизайне, который я не могу дать вам, зная, почему вы используете шифрование. Что ты скрываешь?

Update:

Похоже, вы пытаетесь выполнить проверку шифрования и подписи, например, как работает RSA, но вы смущены тем, как это работает. Для этого вам нужны два набора частных/открытых ключей. Один набор ключей для клиента и один набор ключей для сервера.

Веб-сервер отправит свой открытый ключ клиенту. Клиент мог отправить аутентифицированное и зашифрованное сообщение на сервер, используя открытый ключ сервера, а затем подписав это сообщение с использованием закрытого ключа клиента. И наоборот для сервера. Сервер будет использовать открытый ключ клиента для шифрования сообщения и подписывать его своим личным ключом для отправки сообщения клиенту. Затем клиент может расшифровать сообщение с помощью закрытого ключа клиента и проверить подпись с использованием открытого ключа сервера.

Теперь вы повторно используете SSL? Прекрати это. Использовать SSL.

Вот как SSL достигает безопасного канала. Клиент получает ключ PUBLIC с веб-сервера и 1 или более имен для симметричных алгоритмов шифрования. Он выбирает общий алгоритм, а затем генерирует секретный ключ для использования для всех сообщений в будущем. Он ОБЕСПЕЧИВАЕТ этот секретный ключ с открытым ключом веб-сервера и отправляет его вместе с выбранным алгоритмом. Веб-сервер DECRYPTS использует ключ PRIVATE для получения общего секретного ключа. После этого все шифрование представляет собой симметричное шифрование с использованием общего секрета, который намного быстрее, чем асимметричное шифрование.

Ответ 4

Чтобы создать открытый ключ RSA из формата PEM, как вы указали (ключ openssl gen. rsa)

-----BEGIN PUBLIC KEY-----
SOMEDES3UNREADABLETEXT+PADDING==
-----END PUBLIC KEY

и использовать его для чтения содержимого, подписанного с ним?

-посмотрите мой ответ в подобном вопросе здесь: fooobar.com/info/325678/...