Подтвердить что ты не робот

Получение исключения IllegalBlockSizeException: данные не должны превышать 256 байтов при использовании rsa

Я использую ключ rsa для шифрования длинной строки, которую я пошлю на свой сервер (зашифрует его с помощью открытого ключа сервера и моего закрытого ключа). Но он генерирует исключение, например javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes Я чувствую, что до сих пор я не понимал работу rsa (использование встроенных библиотек является причиной этого). Может кто-нибудь объяснить, почему это исключение выбрасывается. Невозможно ли отправить длинную строку зашифрованной?

4b9b3361

Ответ 1

Алгоритм RSA может только шифровать данные с максимальной длиной байта     длины ключа RSA в битах, разделенных на восемь минус одиннадцать отступов     байты, то есть количество максимальных байтов = длина ключа в битах /8-11.

Итак, вы разделите длину ключа на 8 -11 (если у вас есть отступы). Например, если у вас есть 2048-битный ключ, вы можете зашифровать 2048/8 = 256 байт (- 11 байтов, если у вас есть отступы). Таким образом, используйте либо более крупный ключ, либо шифруйте данные симметричным ключом, и зашифруйте этот ключ с помощью rsa (это рекомендуемый подход).

Это потребует от вас:

  • создать симметричный ключ
  • Шифровать данные с помощью симметричного ключа
  • Зашифровать симметричный ключ с помощью rsa
  • отправить зашифрованный ключ и данные
  • Расшифровать зашифрованный симметричный ключ с помощью rsa
  • расшифровать данные с помощью симметричного ключа
  • done:)

Ответ 2

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

У вас проблема с 256 байтами - это потому, что вы, вероятно, работаете с 2048-битными ключами. Клавиши могут шифровать любое целое число в диапазоне от 0 до 2^2048 - 1 в том же диапазоне, а это значит, что ваши данные должны быть 256 байт или меньше.

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

Ответ 3

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

Вы можете найти библиотеку в GitHub - произвольно-симметричное криптование

 final RandomSymmetricCipher cipher = new RandomSymmetricCipher();

 // Encrypt the data and the random symmetric key.
 final CryptoPacket cryptoPacket = cipher.encrypt(inputData, PRIVATE_KEY_BASE64);

 // Convert the CryptoPacket into a Base64 String that can be readily reconstituted at the other end.
 final CryptoPacketConverter cryptoPacketConverter = new CryptoPacketConverter();
 final String base64EncryptedData = cryptoPacketConverter.convert(cryptoPacket);
 System.out.println("Base64EncryptedData=" + base64EncryptedData);

 // Decrypt the Base64 encoded (and encrypted) String.
 final byte[] outputData = cipher.decrypt(base64EncryptedData, PUBLIC_KEY_BASE64);

Ответ 4

Основываясь на ответе @John Snow, я сделал пример

  • Создать симметричный ключ (AES с 128 бит)

    KeyGenerator generator = KeyGenerator.getInstance("AES");
    generator.init(128); // The AES key size in number of bits
    SecretKey secKey = generator.generateKey();
    
  • Зашифровать простой текст с помощью AES

    String plainText = "Please encrypt me urgently..."
    Cipher aesCipher = Cipher.getInstance("AES");
    aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
    byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());
    
  • Зашифровать ключ с помощью открытого ключа RSA

    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(2048);
    KeyPair keyPair = kpg.generateKeyPair();
    
    PublicKey puKey = keyPair.getPublic();
    PrivateKey prKey = keyPair.getPrivate();
    
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.PUBLIC_KEY, puKey);
    byte[] encryptedKey = cipher.doFinal(byteCipherText);
    
  • Отправить зашифрованные данные (byteCipherText) + зашифрованный ключ AES (encryptedKey)

  • На стороне клиента расшифруйте симметричный ключ с помощью закрытого ключа RSA

    cipher.init(Cipher.PRIVATE_KEY, prKey);
    byte[] decryptedKey = cipher.doFinal(encryptedKey);
    
  • Расшифруйте шифр, используя дешифрованный симметричный ключ

    //Convert bytes to AES SecertKey
    SecretKey originalKey = new SecretKeySpec(decryptedKey , 0, decryptedKey .length, "AES");
    Cipher aesCipher = Cipher.getInstance("AES");
    aesCipher.init(Cipher.DECRYPT_MODE, originalKey);
    byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
    String plainText = new String(bytePlainText);`
    

Ответ 5

вам нужно разделить свои данные с помощью publicKey

int keyLength = publicKey.getModulus().bitLength() / 16;
String[] datas = splitString(data, keyLength - 11);
String mi = ""//the data after encrypted;
for (String s : datas) {
    mi += bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;


public static String bcd2Str(byte[] bytes) {
    char temp[] = new char[bytes.length * 2], val;

    for (int i = 0; i < bytes.length; i++) {
        val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
        temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');

        val = (char) (bytes[i] & 0x0f);
        temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
    }
   return new String(temp);
}