web-dev-qa-db-fra.com

obtenir une exception IllegalBlockSizeException: les données ne doivent pas dépasser 256 octets lors de l'utilisation de rsa

J'utilise la clé rsa pour crypter une longue chaîne que j'enverrai à mon serveur (la crypterai avec la clé publique du serveur et ma clé privée) Mais cela lève une exception comme javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes Je sens que je n'ai pas bien compris le fonctionnement de rsa jusqu'à présent (l'utilisation des bibliothèques intégrées en est la cause).
Quelqu'un peut-il expliquer pourquoi cette exception est levée. N'est-il pas possible d'envoyer des chaînes longues chiffrées?

40
Ashwin

L'algorithme RSA ne peut chiffrer que les données dont la longueur maximale en octets est la longueur de la clé RSA en bits, divisée par huit moins onze octets de remplissage, c'est-à-dire le nombre maximal d'octets = longueur de la clé en bits/8-11.

Donc, fondamentalement, vous divisez la longueur de la clé par 8 -11 (si vous avez un rembourrage). Par exemple, si vous avez une clé à 2048 bits, vous pouvez chiffrer 2048/8 = 256 octets (- 11 octets si vous avez un remplissage). Donc, soit utilisez une clé plus grande, soit chiffrez les données avec une clé symétrique, puis chiffrez cette clé avec rsa (qui est l'approche recommandée).

Cela vous obligera à:

  1. générer une clé symétrique
  2. Chiffrez les données avec la clé symétrique
  3. Crypter la clé symétrique avec rsa
  4. envoyer la clé cryptée et les données
  5. Déchiffrez la clé symétrique chiffrée avec rsa
  6. décrypter les données avec la clé symétrique
  7. terminé :)
66
John Snow

Sur la base de la réponse de @John Snow, j'ai fait un exemple

  1. Générer une clé symétrique (AES avec 128 bits)

    KeyGenerator generator = KeyGenerator.getInstance("AES");
    generator.init(128); // The AES key size in number of bits
    SecretKey secKey = generator.generateKey();
    
  2. Crypter du texte brut à l'aide d'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. Chiffrer la clé à l'aide de la clé publique 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. Envoyer des données cryptées (byteCipherText) + clé AES cryptée (encryptedKey)

  5. Côté client, déchiffrez la clé symétrique à l'aide de la clé privée RSA

    cipher.init(Cipher.PRIVATE_KEY, prKey);
    byte[] decryptedKey = cipher.doFinal(encryptedKey);
    
  6. Déchiffrer le chiffrement à l'aide d'une clé symétrique déchiffrée

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

Vous ne devez pas utiliser RSA sur vos données secrètes directement. Vous ne devez utiliser RSA que sur des données pseudo-aléatoires ou complètement aléatoires, telles que des clés de session ou des codes d'authentification de message.

Vous avez eu le problème à 256 octets - c'est parce que vous travaillez probablement avec des clés de 2048 bits. Les clés sont capables de crypter n'importe quel entier dans la plage 0 à 2^2048 - 1 dans la même plage, ce qui signifie que vos données doivent être de 256 octets ou moins.

Si vous avez l'intention de crypter plus que cela, veuillez utiliser un cryptage RSA pour crypter une clé de session pour un algorithme symétrique, et utilisez that pour crypter vos données.

11
sarnold

Pour faire suite à la réponse de John Snow ci-dessus, j'ai créé une bibliothèque de cryptage symétrique aléatoire simple que vous pouvez utiliser pour chiffrer simplement toutes les données de longueur à l'aide d'une clé privée.

Vous pouvez trouver la bibliothèque sur 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);
3
William