Слишком много данных для сбоя блока RSA. Что такое PKCS#7?

Разговор о javax.crypto.Cipher

Я пытался зашифровать использование данных Cipher.getInstance("RSA/None/NoPadding", "BC") но я получил исключение:

ArrayIndexOutOfBoundsException: too much data for RSA block

Похож что-то связанное с "NoPadding", таким образом, читая о дополнении, похож на CBC, лучший подход для использования здесь.

Я нашел в Google что-то о "RSA/CBC/PKCS#7", каков этот "PKCS#7"? И почему не перечисленный на стандартных названиях алгоритма солнца?

Обновление:

Я задаюсь вопросом, если дополнительная проблема, почему этот пример, выполненный очень хорошо?

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;

import javax.crypto.Cipher;

/**
 * Basic RSA example.
 */
public class BaseRSAExample
{
    public static void main(
        String[]    args)
        throws Exception
    {
        byte[]           input = new byte[] { (byte)0xbe, (byte)0xef };
        Cipher          cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
        KeyFactory       keyFactory = KeyFactory.getInstance("RSA", "BC");

        // create the keys

        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
                new BigInteger("d46f473a2d746537de2056ae3092c451", 16),
                new BigInteger("11", 16));
        RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(
                new BigInteger("d46f473a2d746537de2056ae3092c451", 16),  
                new BigInteger("57791d5430d593164082036ad8b29fb1", 16));

        RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(pubKeySpec);
        RSAPrivateKey privKey = (RSAPrivateKey)keyFactory.generatePrivate(privKeySpec);

        // encryption step

        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        byte[] cipherText = cipher.doFinal(input);

        // decryption step

        cipher.init(Cipher.DECRYPT_MODE, privKey);

        byte[] plainText = cipher.doFinal(cipherText);

    }
}

Обновление 2:

Я понял это, даже если я использую просто Cipher.getInstance("RSA", "BC") это выдает то же исключение.

11
задан Tom Brito 6 April 2010 в 13:27
поделиться

6 ответов

Если вы используете блочный шифр, вы ввод должен быть точным кратным длине блока в битах.

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

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

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

Следовательно, блочный шифр не может быть применен к вашим данным, и вы получили сообщение об исключении.

ОБНОВЛЕНИЕ:

В ответ на ваше обновление и замечание GregS я хотел бы подтвердить, что GregS был прав (я не знал этого о RSA), и немного поясню:

RSA не работает с биты, он работает с целыми числами. Следовательно, чтобы использовать RSA, вам необходимо преобразовать ваше строковое сообщение в целое число m: 0 , где n - это модуль двух различных простых чисел, выбранных при генерации процесс. Размер ключа в алгоритме RSA обычно составляет n . Более подробную информацию об этом можно найти в статье википедии по RSA .

Процесс преобразования строкового сообщения в целое число без потерь (например, усечение начальных нулей) обычно выполняется в соответствии со стандартом PKCS # 1 . Этот процесс также добавляет некоторую другую информацию для целостности сообщения (хэш-дайджест), семантической безопасности (IV) и так далее. С этими дополнительными данными максимальное количество байтов, которое может быть передано в RSA / None / PKCS1Padding, составляет (длина ключа - 11). Я не знаю, как PKCS # 1 сопоставляет входные данные с выходным целочисленным диапазоном, но мое впечатление таково, что он может принимать любую длину ввода, меньшую или равную длине ключа - 11, и выдавать действительное целое число для RSA шифрование.

Если вы не используете заполнение, ваш ввод будет просто интерпретирован как число. Ваш пример ввода, {0xbe, 0xef}, скорее всего, будет интерпретирован как {10111110 + o 11101111} = 1011111011101111_2 = 48879_10 = beef_16 (sic!). Поскольку 0

Это упоминается в FAQ по bouncycastle . Они также заявляют следующее:

Реализация RSA, поставляемая с Bouncy Castle, позволяет шифрование только одного блока данных. Алгоритм RSA не подходит для потоковые данные и не должны использоваться таким образом. В такой ситуации вы должны зашифровать данные с помощью случайно сгенерированного ключа и симметричного шифра, после чего вы должны зашифровать случайно сгенерированный ключ, используя RSA, , а затем отправить зашифрованные данные и зашифрованный случайный ключ на другой конец, где они могут отменить процесс (т. Е. Расшифровать случайный ключ используя свой закрытый ключ RSA, а затем расшифровать данные).

11
ответ дан 3 December 2019 в 07:36
поделиться

RSA - это однократное асимметричное шифрование с ограничениями. Он шифрует одно «сообщение» за один раз, но сообщение должно соответствовать довольно жестким ограничениям, основанным на размере открытого ключа. Для типичного 1024-битного ключа RSA максимальная длина входящего сообщения (с RSA, как описано в стандарте PKCS # 1 ) составляет 117 байтов, не более. Кроме того, с таким ключом зашифрованное сообщение имеет длину 128 байтов, независимо от длины входящего сообщения. Как общий механизм шифрования RSA очень неэффективен и расходует пропускную способность сети.

Симметричные системы шифрования (например, AES или 3DES) намного более эффективны и имеют «режимы цепочки», которые позволяют им обрабатывать входящие сообщения произвольной длины. Но у них нет «асимметричного» свойства RSA: с RSA вы можете сделать ключ шифрования открытым, не раскрывая ключ дешифрования. В этом весь смысл RSA. При симметричном шифровании тот, у кого есть возможность зашифровать сообщение, также имеет всю необходимую информацию для расшифровки сообщений, поэтому вы не можете сделать ключ шифрования открытым, потому что он также сделает открытый ключ дешифрования.

Таким образом, обычно используется гибридная система, в которой (большое) сообщение симметрично зашифровано (например,, AES), используя симметричный ключ (который представляет собой произвольную короткую последовательность случайных байтов), и зашифровать этот ключ с помощью RSA. Затем принимающая сторона использует расшифровку RSA для восстановления этого симметричного ключа, а затем использует его для дешифрования самого сообщения.

Помимо довольно упрощенного описания, приведенного выше, криптографические системы, в частности гибридные системы, представляют собой часы, полные мелких деталей, которые, если о них не позаботиться, могут сделать ваше приложение чрезвычайно уязвимым для атак злоумышленников. Поэтому лучше всего использовать протокол с реализацией, которая уже выполняет всю эту тяжелую работу. PKCS # 7 - такой протокол. В настоящее время он стандартизирован под названием CMS . Он используется в нескольких местах, например в основе S / MIME (стандарт шифрования и подписи электронной почты). Другой хорошо известный протокол, предназначенный для шифрования сетевого трафика, - это SSL (теперь стандартизированный под названием TLS и часто используемый в сочетании с HTTP в качестве известного протокола «HTTPS»).

Java содержит реализацию SSL (см. javax.net.ssl ​​). Java не содержит реализации CMS (по крайней мере, в ее API), но Bouncy Castle имеет некоторый код для CMS.

4
ответ дан 3 December 2019 в 07:36
поделиться

RSA можно использовать только для encrypt, когда количество бит, используемых для шифрования, больше, чем размер объекта, который вы привязываете для шифрования + 11 байтов

Стандарты криптографии с открытым ключом - PKCS

0
ответ дан 3 December 2019 в 07:36
поделиться

Прокрутите немного вниз, и вы увидите это. Это не алгоритм шифрования (например, RSA) или режим шифрования, такой как CBC, а описание способа кодирования сертификата в байтах (т. Е. Синтаксиса структуры данных). Вы можете найти его спецификацию здесь .

0
ответ дан 3 December 2019 в 07:36
поделиться

Не следует шифровать данные напрямую с помощью RSA. Зашифруйте свои данные случайным симметричным ключом (например, AES / CBC / PKCS5Padding) и зашифруйте симметричный ключ с помощью RSA / None / PKCS1Padding.

0
ответ дан 3 December 2019 в 07:36
поделиться

PKCS#7 указан (ссылаясь на вашу ссылку). Его кодировка - PKCS7

Описание

Объект PKCS#7 SignedData, с единственным значимым полем является сертификаты.

Используйте java.security.cert.CertificateFactory или CertPath при использовании PKCS7.


RSA - это блочный шифр. Он шифрует блок одинакового размера ключа. Поэтому BouncyCastle RSA выдает исключение, если вы пытаетесь зашифровать блок который длиннее, чем размер ключа.

Это все, что я могу сказать вам на данный момент.

0
ответ дан 3 December 2019 в 07:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: