Расшифровка «длинного» сообщения, зашифрованного с помощью RSA java

Привет, это тот же вопрос, который задавали два года назад: Java / JCE: расшифровка «длинного» сообщения, зашифрованного с помощью RSA

У меня был большой массив байтов и пара ключей rsa, инициированная значением 1024. Использование шифрования rsa и указанный размер ключа является строгим требованием, я не могу его изменить. Поэтому я не могу использовать симметричное шифрование с симметричным ключом асимметричного шифрования. Я не могу использовать другие ключи. У меня был байтовый массив, и мне нужно было вернуть зашифрованный байтовый массив. Интересно, есть ли готовый инструмент, который справится с этой проблемой?

Извините за такой дилетантский вопрос, но мне очень нужна помощь.


person Denis    schedule 16.04.2010    source источник


Ответы (2)


Как уже говорилось, на ваш вопрос есть один ответ, и это «нет». Шифрование RSA - это алгоритм, который шифрует сообщения до заданного размера, который зависит от размера ключа; с 1024-битным ключом RSA, а RSA как стандарт описывает его , максимальный размер 117 байт, не более. Невозможно зашифровать более крупное сообщение только с помощью RSA, и это определенная математическая уверенность.

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

Итак, проторенный путь асимметричного шифрования:

  1. Вы выбираете случайную последовательность байтов некоторой подходящей длины, например 128 бит (это 16 байт). Назовем его K.
  2. Вы шифруете K открытым ключом RSA; это дает E.
  3. Вы шифруете сообщение с помощью K, используя алгоритм симметричного шифрования ("AES/CBC/PKCS5Padding"). Поскольку это одноразовый ключ, вы можете использовать все нули IV. В результате получается группа байтов, назовем ее F.
  4. Зашифрованное сообщение представляет собой соединение E и F.

Расшифровка выполняется в обратном порядке: закрытый ключ RSA используется для восстановления K из E, затем K используется для расшифровки F в исходное сообщение. Ключ K никогда нигде не сохраняется, и каждый раз создается новый ключ K (даже если вы дважды зашифруете одно и то же сообщение). Это важно, не меняйте это, если вы не понимаете, что делаете (а если да, то вы уже это знаете).

Учитывая то, что вы заявляете о своей проблеме, вы должны сделать что-то еще, кроме «только RSA». Процедура, которую я описываю выше, касается лучшего "чего-то еще", что вы могли придумать с точки зрения безопасности.

Сборка некоторых криптографических элементов в такой протокол - это процесс, чреватый подводными камнями, поэтому вам, возможно, повезет больше, если вы используете уже определенный формат и библиотеку поддержки. Двумя распространенными форматами асимметричного шифрования являются CMS и OpenPGP. Библиотека, которая поддерживает и то, и другое и имеет хорошую репутацию, называется Bouncy Castle.

person Thomas Pornin    schedule 16.04.2010
comment
Хороший ответ. Больше нечего добавить. - person St.Shadow; 16.04.2010
comment
Жалко, что не могу поменять спецификацию. - person Denis; 16.04.2010
comment
Это может быть просто вопрос того, как вы интерпретируете спецификацию. Если он просто говорит, что данные должны быть зашифрованы с использованием 1024-битного ключа RSA, то ответ Томаса - это стандартный способ сделать это, поэтому я бы сказал, что он полностью соответствует спецификации. - person caf; 17.04.2010
comment
-1. Хорошо известно, что этот режим шифрования небезопасен. Он подвержен атаке по выбранному зашифрованному тексту. Либо используйте заполнение OAEP вместо старого заполнения PKCS # 1, либо лучше используйте некоторую аутентификацию. - person Accipitridae; 18.04.2010
comment
Кроме того, Bouncy Castle не так уж и хорош. В его реализации RSA все еще есть существенные не исправленные недостатки. - person Accipitridae; 18.04.2010
comment
Если хорошо известно, что заполнение PKCS # 1 v1.5 небезопасно и восприимчиво к выбранной атаке зашифрованного текста, то, возможно, вы могли бы предоставить ссылку, подтверждающую это утверждение? - person Thomas Pornin; 19.04.2010
comment
В том же абзаце, в котором PKCS # 1 (2.0) говорится об атаке Блейхенбахера на заполнение v1.5, также говорится, что есть несколько контрмер, которые очень эффективны в предотвращении атаки, без изменения ни одного бита в заполнении или шифровании. процесс (и это, кстати, то, что делает любая приличная реализация SSL). Заполнение v1.5 небезопасно; то, что небезопасно, - это сообщение о небинарных ошибках при неудачной операции. Такой же тип атаки на самом деле применяется к OAEP, см .: citeseerx.ist.psu.edu/viewdoc/ - person Thomas Pornin; 01.08.2010

Если вам действительно нужно зашифровать / расшифровать длинные строки с помощью RSA, вы можете разбить байты на более мелкие «фрагменты» и обрабатывать каждый фрагмент байтов через шифр по одному, сохраняя результаты в ByteBuffer.

Шифрование:

byte[] encData = null;
try {

    // create public key
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(key);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PublicKey pk = kf.generatePublic(publicKeySpec);

    Cipher pkCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    pkCipher.init(Cipher.ENCRYPT_MODE, pk);

    int chunkSize = 117; // 1024 / 8 - 11(padding) = 117
    int encSize = (int) (Math.ceil(data.length/117.0)*128);
    int idx = 0;
    ByteBuffer buf = ByteBuffer.allocate(encSize);
    while (idx < data.length) {
        int len = Math.min(data.length-idx, chunkSize);
        byte[] encChunk = pkCipher.doFinal(data, idx, len);
        buf.put(encChunk);
        idx += len;
    }

    // fully encrypted data     
    encData = buf.array();
} catch (Exception e) {
    e.printStackTrace();

Расшифровка

Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsaCipher.init(Cipher.DECRYPT_MODE, rsaPk);

int chunkSize = 128;
int idx = 0;
ByteBuffer buf = ByteBuffer.allocate(data.length);
while(idx < data.length) {
    int len = Math.min(data.length-idx, chunkSize);
    byte[] chunk = rsaCipher.doFinal(data, idx, len);
    buf.put(chunk);
    idx += len;
}

// fully decrypted data
byte[] decryptedData = buf.array();
person Aaron Wilson    schedule 18.05.2014
comment
Никогда не следует делать такое шифрование / дешифрование RSA по частям. Он подвержен ошибкам, небезопасен и ужасно медленен для длинных сообщений. - person Artjom B.; 16.03.2016
comment
Здесь много сообщений, в которых говорится, чего не следует делать. Было бы неплохо хотя бы упомянуть, что искать. Прямо сейчас я ищу информацию о том, как что-то делать. Теперь я знаю, что RSA предназначен для шифрования ключа симметричного алгоритма, например AES. - person Pochmurnik; 08.10.2020