Слишком много данных для блока 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"? И почему его нет в списке название стандартного алгоритма солнца?

Update:

Мне интересно, если это проблема с заполнением, почему этот пример работает нормально?

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"), он выдает одно и то же исключение.

Ответ 1

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

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

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

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

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

UPDATE:

Как ответ на ваше обновление и замечание GregS, я хотел бы отметить, что GregS был прав (я не знал об RSA) и немного уточнил:

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

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

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

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

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

Ответ 2

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.

Ответ 3

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

Ответ 4

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

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

Ответ 5

Указан PKCS # 7 (ссылка на вашу ссылку). Это кодирование PKCS7

Описание

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

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


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

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

Ответ 6

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

Ответ 7

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