L'algorithme RSA est un pilier de la cryptographie asymétrique, utilisé pour sécuriser les échanges de données. En Java, l'implémentation repose sur l'architecture JCE (Java Cryptography Extension). Voici un guide technique détaillant comment traiter des données par blocs avec RSA, ainsi que la gestion des clés.
import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.io.ByteArrayOutputStream;
public class RsaProcessor {
// Pour une clé de 1024 bits, la charge utile maximale est de 117 octets (avec PKCS1Padding)
private static final int ENCRYPTION_LIMIT = 117;
// Le bloc chiffré résultant est toujours de 128 octets pour une clé de 1024 bits
private static final int DECRYPTION_LIMIT = 128;
public static void main(String[] args) throws Exception {
// Initialisation de la paire de clés
KeyPair pair = createKeyPair();
PublicKey pubKey = pair.getPublic();
PrivateKey privKey = pair.getPrivate();
String message = "Exemple de message sécurisé avec RSA !";
// Exécution du chiffrement
String secret = cipherData(message, pubKey);
System.out.println("Résultat chiffré (Base64) : " + secret);
// Exécution du déchiffrement
String clearText = decipherData(secret, privKey);
System.out.println("Message décodé : " + clearText);
}
private static KeyPair createKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(1024);
return gen.generateKeyPair();
}
public static String cipherData(String input, PublicKey key) throws Exception {
Cipher engine = Cipher.getInstance("RSA/ECB/PKCS1Padding");
engine.init(Cipher.ENCRYPT_MODE, key);
byte[] raw = input.getBytes(StandardCharsets.UTF_8);
byte[] output = segmentOperation(raw, engine, ENCRYPTION_LIMIT);
return Base64.getEncoder().encodeToString(output);
}
public static String decipherData(String b64Data, PrivateKey key) throws Exception {
Cipher engine = Cipher.getInstance("RSA/ECB/PKCS1Padding");
engine.init(Cipher.DECRYPT_MODE, key);
byte[] raw = Base64.getDecoder().decode(b64Data);
byte[] output = segmentOperation(raw, engine, DECRYPTION_LIMIT);
return new String(output, StandardCharsets.UTF_8);
}
private static byte[] segmentOperation(byte[] input, Cipher cipher, int blockSize) throws Exception {
int length = input.length;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int cursor = 0;
while (length - cursor > 0) {
int currentChunkSize = Math.min(length - cursor, blockSize);
byte[] processed = cipher.doFinal(input, cursor, currentChunkSize);
buffer.write(processed, 0, processed.length);
cursor += currentChunkSize;
}
return buffer.toByteArray();
}
}
Logique de segmentation des blocs
La nécessité de segmenter les données provient des contraintes mathématiques de RSA. La taille des blocs varie entre l'encodage et le décodage :
- Bloc de chiffrement (117 octets) : Avec une clé de 1024 bits (128 octets) et l'utilisation du padding
PKCS#1 v1.5, 11 octets sont réservés pour les métadonnées de remplissage. Ainsi, la taille maximale du texte clair par segment est de 128 - 11 = 117 octets. - Bloc de déchiffrement (128 octets) : Lors de la lecture du texte chiffré, chaque segment correspond exactement à la taille de la clé (128 octets). Le moteur de chiffrement retire automatiquement le padding après le traitement pour restituer les données originales.
Reconstruction des clés depuis des chaînes Base64
Dans un environnement de production, les clés sont souvent stockées sous forme de chaînes de caractères. Voici comment les transformer en objets Key exploitables :
// Conversion d'une chaîne Base64 en clé publique (format X.509)
public static PublicKey loadPublicKey(String base64Key) throws Exception {
byte[] decoded = Base64.getDecoder().decode(base64Key);
X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
// Conversion d'une chaîne Base64 en clé privée (format PKCS#8)
public static PrivateKey loadPrivateKey(String base64Key) throws Exception {
byte[] decoded = Base64.getDecoder().decode(base64Key);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(spec);
}