Dans cette réponse, j'ai choisi d'aborder le thème principal «Exemple simple de chiffrement / déchiffrement de Java AES» et non la question de débogage spécifique car je pense que cela profitera à la plupart des lecteurs.
Ceci est un simple résumé de mon article de blog sur le cryptage AES en Java , je vous recommande donc de le lire avant de mettre en œuvre quoi que ce soit. Je vais cependant toujours fournir un exemple simple à utiliser et donner quelques conseils à surveiller.
Dans cet exemple, je choisirai d'utiliser le cryptage authentifié avec le mode Galois / compteur ou le mode GCM . La raison en est que dans la plupart des cas, vous voulez l' intégrité et l'authenticité en combinaison avec la confidentialité (en savoir plus dans le blog ).
Tutoriel de chiffrement / déchiffrement AES-GCM
Voici les étapes nécessaires pour crypter / décrypter avec AES-GCM avec Java Cryptography Architecture (JCA) . Ne mélangez pas avec d'autres exemples , car des différences subtiles peuvent rendre votre code totalement non sécurisé.
1. Créer une clé
Comme cela dépend de votre cas d'utilisation, je suppose le cas le plus simple: une clé secrète aléatoire.
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");
Important:
2. Créez le vecteur d'initialisation
Un vecteur d'initialisation (IV) est utilisé pour que la même clé secrète crée différents textes de chiffrement .
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);
Important:
3. Crypter avec IV et Key
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] cipherText = cipher.doFinal(plainText);
Important:
- utiliser une balise d'authentification de 16 octets / 128 bits (utilisée pour vérifier l'intégrité / l'authenticité)
- la balise d'authentification sera automatiquement ajoutée au texte chiffré (dans l'implémentation JCA)
- puisque GCM se comporte comme un chiffrement de flux, aucun remplissage n'est requis
- à utiliser
CipherInputStream
lors du chiffrement de gros morceaux de données
- voulez-vous que des données supplémentaires (non secrètes) soient vérifiées si elles ont été modifiées? Vous pouvez utiliser les données associées avec
cipher.updateAAD(associatedData);
Plus ici.
3. Sérialisation en message unique
Ajoutez simplement IV et le texte chiffré. Comme indiqué ci-dessus, l'IV n'a pas besoin d'être secrète.
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();
Encodez éventuellement avec Base64 si vous avez besoin d'une représentation sous forme de chaîne. Utilisez l' implémentation intégrée d' Android ou de Java 8 (n'utilisez pas Apache Commons Codec - c'est une implémentation horrible). Le codage est utilisé pour "convertir" des tableaux d'octets en représentation sous forme de chaîne pour le rendre sûr ASCII, par exemple:
String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);
4. Préparez le décryptage: désérialiser
Si vous avez encodé le message, décodez-le d'abord en tableau d'octets:
byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)
Important:
5. Décrypter
Initialisez le chiffrement et définissez les mêmes paramètres qu'avec le chiffrement:
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
//use first 12 bytes for iv
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmIv);
//use everything from 12 bytes on as ciphertext
byte[] plainText = cipher.doFinal(cipherMessage, 12, cipherMessage.length - 12);
Important:
- n'oubliez pas d'ajouter les données associées à
cipher.updateAAD(associatedData);
si vous les avez ajoutées lors du chiffrement.
Un extrait de code fonctionnel peut être trouvé dans cet essentiel.
Notez que les implémentations Android (SDK 21+) et Java (7+) les plus récentes devraient avoir AES-GCM. Les anciennes versions peuvent en manquer. Je choisis toujours ce mode, car il est plus facile à mettre en œuvre en plus d'être plus efficace par rapport au mode similaire d' Encrypt-then-Mac (avec par exemple AES-CBC + HMAC ). Consultez cet article pour savoir comment implémenter AES-CBC avec HMAC .