Obteniendo una IllegalBlockSizeException: los datos no deben ser más largos que 256 bytes cuando se usa rsa

Estoy usando la clave rsa para encriptar una cadena larga que enviaré a mi servidor (la encriptaré con la clave pública del servidor y mi clave privada) Pero arroja una excepción como javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes Siento que no he entendido el funcionamiento de rsa correctamente hasta ahora (el uso de las bibliotecas integradas es la causa de esto).
¿Puede alguien explicar por qué se lanza esta excepción? ¿No es posible enviar cadenas largas encriptadas?

El algoritmo RSA solo puede encriptar datos que tienen una longitud máxima de bytes de la longitud de clave RSA en bits divididos con ocho bytes menos de relleno, es decir, número de bytes máximos = longitud de clave en bits / 8 – 11.

Así que, básicamente, se divide la longitud de la clave con 8 -11 (si tiene relleno). Por ejemplo, si tiene una clave de 2048bit, puede encriptar 2048/8 = 256 bytes (- 11 bytes si tiene relleno). Entonces, use una clave más grande o encripte los datos con una clave simétrica y encripte esa clave con rsa (que es el enfoque recomendado).

Eso requerirá que:

  1. generar una clave simétrica
  2. Cifre los datos con la clave simétrica
  3. Encriptar la clave simétrica con rsa
  4. enviar la clave encriptada y los datos
  5. Descifrar la clave simétrica cifrada con rsa
  6. descifrar los datos con la clave simétrica
  7. hecho 🙂

Basado en la respuesta de @John Snow, hice un ejemplo

  1. Generar clave simétrica (AES con 128 bits)

     KeyGenerator generator = KeyGenerator.getInstance("AES"); generator.init(128); // The AES key size in number of bits SecretKey secKey = generator.generateKey(); 
  2. Encriptar texto sin formato con AES

     String plainText = "Please encrypt me urgently..." Cipher aesCipher = Cipher.getInstance("AES"); aesCipher.init(Cipher.ENCRYPT_MODE, secKey); byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes()); 
  3. Encriptar la clave usando la clave pública 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(secKey.getEncoded()/*Seceret Key From Step 1*/); 
  4. Enviar datos cifrados (byteCipherText) + clave AES cifrada (encryptedKey)

  5. En el lado del cliente, descifrar la clave simétrica usando la clave privada RSA

     cipher.init(Cipher.PRIVATE_KEY, prKey); byte[] decryptedKey = cipher.doFinal(encryptedKey); 
  6. Descifrar el cifrado utilizando clave simétrica descifrada

     //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);` 

No debe usar RSA en sus datos secretos directamente. Solo debe utilizar RSA en datos pseudoaleatorios o completamente aleatorios , como claves de sesión o códigos de autenticación de mensajes.

Has obtenido el problema a 256 bytes, eso es porque probablemente estés trabajando con claves de 2048 bits. Las claves pueden encriptar cualquier entero en el rango 0 a 2^2048 - 1 en el mismo rango, y eso significa que sus datos deben ser de 256 bytes o menores.

Si tiene la intención de encriptar más que esto, use un cifrado RSA para encriptar una clave de sesión para un algoritmo simétrico y úsela para encriptar sus datos.

Para seguir con la respuesta anterior de John Snow, creé una biblioteca de criptas simétricas aleatorias que puedes usar simplemente para cifrar cualquier dato de longitud con una clave privada.

Puede encontrar la biblioteca en GitHub – random-symmetric-crypto

  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); 

necesita dividir sus datos por 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); }