Exemple simple de cryptage / décryptage Java AES

Quel est le problème avec l’exemple suivant?

Le problème est que la première partie de la chaîne déchiffrée est un non-sens. Cependant, le rest va bien, je reçois …

Result: `£eB6O geS  i are you? Have a nice day. 
 @Test public void testEncrypt() { try { Ssortingng s = "Hello there. How are you? Have a nice day."; // Generate key KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128); SecretKey aesKey = kgen.generateKey(); // Encrypt cipher Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey); // Encrypt ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, encryptCipher); cipherOutputStream.write(s.getBytes()); cipherOutputStream.flush(); cipherOutputStream.close(); byte[] encryptedBytes = outputStream.toByteArray(); // Decrypt cipher Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded()); decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec); // Decrypt outputStream = new ByteArrayOutputStream(); ByteArrayInputStream inStream = new ByteArrayInputStream(encryptedBytes); CipherInputStream cipherInputStream = new CipherInputStream(inStream, decryptCipher); byte[] buf = new byte[1024]; int bytesRead; while ((bytesRead = cipherInputStream.read(buf)) >= 0) { outputStream.write(buf, 0, bytesRead); } System.out.println("Result: " + new Ssortingng(outputStream.toByteArray())); } catch (Exception ex) { ex.printStackTrace(); } } 

Beaucoup de gens, y compris moi-même, font face à beaucoup de problèmes pour faire ce travail en raison de l’absence d’informations comme oublier de convertir en Base64, des vecteurs d’initialisation, des jeux de caractères, etc.

J’espère que cela vous sera utile à tous: Pour comstackr, vous avez besoin de jar Apache Commons Codec supplémentaire, qui est disponible ici: http://commons.apache.org/proper/commons-codec/download_codec.cgi

 import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; public class Encryptor { public static Ssortingng encrypt(Ssortingng key, Ssortingng initVector, Ssortingng value) { try { IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8")); SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); byte[] encrypted = cipher.doFinal(value.getBytes()); System.out.println("encrypted ssortingng: " + Base64.encodeBase64Ssortingng(encrypted)); return Base64.encodeBase64Ssortingng(encrypted); } catch (Exception ex) { ex.printStackTrace(); } return null; } public static Ssortingng decrypt(Ssortingng key, Ssortingng initVector, Ssortingng encrypted) { try { IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8")); SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted)); return new Ssortingng(original); } catch (Exception ex) { ex.printStackTrace(); } return null; } public static void main(Ssortingng[] args) { Ssortingng key = "Bar12345Bar12345"; // 128 bit key Ssortingng initVector = "RandomInitVector"; // 16 bytes IV System.out.println(decrypt(key, initVector, encrypt(key, initVector, "Hello World"))); } } 

Voici une solution sans Apache Commons Codec ‘s Base64 :

 import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class AdvancedEncryptionStandard { private byte[] key; private static final Ssortingng ALGORITHM = "AES"; public AdvancedEncryptionStandard(byte[] key) { this.key = key; } /** * Encrypts the given plain text * * @param plainText The plain text to encrypt */ public byte[] encrypt(byte[] plainText) throws Exception { SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return cipher.doFinal(plainText); } /** * Decrypts the given byte array * * @param cipherText The data to decrypt */ public byte[] decrypt(byte[] cipherText) throws Exception { SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKey); return cipher.doFinal(cipherText); } } 

Exemple d’utilisation:

 byte[] encryptionKey = "MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8); byte[] plainText = "Hello world!".getBytes(StandardCharsets.UTF_8); AdvancedEncryptionStandard advancedEncryptionStandard = new AdvancedEncryptionStandard( encryptionKey); byte[] cipherText = advancedEncryptionStandard.encrypt(plainText); byte[] decryptedCipherText = advancedEncryptionStandard.decrypt(cipherText); System.out.println(new Ssortingng(plainText)); System.out.println(new Ssortingng(cipherText)); System.out.println(new Ssortingng(decryptedCipherText)); 

Impressions:

 Hello world! դ;  LA+ ߙb* Hello world! 

Il me semble que vous ne traitez pas correctement votre vecteur d’initialisation (IV). Il y a longtemps que je n’ai plus lu sur AES, IVs et block chaining, mais votre ligne

 IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded()); 

ne semble pas être OK. Dans le cas d’AES, vous pouvez considérer le vecteur d’initialisation comme “l’état initial” d’une instance de chiffrement et cet état est un bit d’informations que vous ne pouvez pas obtenir de votre clé mais du calcul réel du chiffrement de chiffrement. (On pourrait argumenter que si le fichier IV pouvait être extrait de la clé, il ne serait d’aucune utilité, car la clé est déjà donnée à l’instance de chiffrement lors de sa phase d’initialisation).

Par conséquent, vous devriez obtenir l’IV en tant qu’octet [] à partir de l’instance de chiffrement à la fin de votre chiffrement.

  cipherOutputStream.close(); byte[] iv = encryptCipher.getIV(); 

et vous devriez initialiser votre Cipher dans DECRYPT_MODE avec cet octet []:

  IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 

Ensuite, votre déchiffrement devrait être OK. J’espère que cela t’aides.

Le IV que vous utilisez pour le déchiffrement est incorrect. Remplacez ce code

 //Decrypt cipher Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded()); decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec); 

Avec ce code

 //Decrypt cipher Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivParameterSpec = new IvParameterSpec(encryptCipher.getIV()); decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec); 

Et cela devrait résoudre votre problème.


Vous trouverez ci-dessous un exemple de classe AES simple en Java. Je ne recommande pas l’utilisation de cette classe dans les environnements de production, car cela pourrait ne pas prendre en compte tous les besoins spécifiques de votre application.

 import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class AES { public static byte[] encrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException { return AES.transform(Cipher.ENCRYPT_MODE, keyBytes, ivBytes, messageBytes); } public static byte[] decrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException { return AES.transform(Cipher.DECRYPT_MODE, keyBytes, ivBytes, messageBytes); } private static byte[] transform(final int mode, final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException { final SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); final IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); byte[] transformedBytes = null; try { final Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); cipher.init(mode, keySpec, ivSpec); transformedBytes = cipher.doFinal(messageBytes); } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) { e.printStackTrace(); } return transformedBytes; } public static void main(final Ssortingng[] args) throws InvalidKeyException, InvalidAlgorithmParameterException { //Resortingeved from a protected local file. //Do not hard-code and do not version control. final Ssortingng base64Key = "ABEiM0RVZneImaq7zN3u/w=="; //Resortingeved from a protected database. //Do not hard-code and do not version control. final Ssortingng shadowEntry = "AAECAwQFBgcICQoLDA0ODw==:ZtrkahwcMzTu7e/WuJ3AZmF09DE="; //Extract the iv and the ciphertext from the shadow entry. final Ssortingng[] shadowData = shadowEntry.split(":"); final Ssortingng base64Iv = shadowData[0]; final Ssortingng base64Ciphertext = shadowData[1]; //Convert to raw bytes. final byte[] keyBytes = Base64.getDecoder().decode(base64Key); final byte[] ivBytes = Base64.getDecoder().decode(base64Iv); final byte[] encryptedBytes = Base64.getDecoder().decode(base64Ciphertext); //Decrypt data and do something with it. final byte[] decryptedBytes = AES.decrypt(keyBytes, ivBytes, encryptedBytes); //Use non-blocking SecureRandom implementation for the new IV. final SecureRandom secureRandom = new SecureRandom(); //Generate a new IV. secureRandom.nextBytes(ivBytes); //At this point instead of printing to the screen, //one should replace the old shadow entry with the new one. System.out.println("Old Shadow Entry = " + shadowEntry); System.out.println("Decrytped Shadow Data = " + new Ssortingng(decryptedBytes, StandardCharsets.UTF_8)); System.out.println("New Shadow Entry = " + Base64.getEncoder().encodeToSsortingng(ivBytes) + ":" + Base64.getEncoder().encodeToSsortingng(AES.encrypt(keyBytes, ivBytes, decryptedBytes))); } } 

Notez que AES n’a rien à voir avec l’encodage, c’est pourquoi j’ai choisi de le gérer séparément et sans avoir recours à des bibliothèques tierces.

C’est souvent la bonne idée de compter sur la solution standard fournie par la bibliothèque:

 private static void stackOverflow15554296() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { // prepare key KeyGenerator keygen = KeyGenerator.getInstance("AES"); SecretKey aesKey = keygen.generateKey(); Ssortingng aesKeyForFutureUse = Base64.getEncoder().encodeToSsortingng( aesKey.getEncoded() ); // cipher engine Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // cipher input aesCipher.init(Cipher.ENCRYPT_MODE, aesKey); byte[] clearTextBuff = "Text to encode".getBytes(); byte[] cipherTextBuff = aesCipher.doFinal(clearTextBuff); // recreate key byte[] aesKeyBuff = Base64.getDecoder().decode(aesKeyForFutureUse); SecretKey aesDecryptKey = new SecretKeySpec(aesKeyBuff, "AES"); // decipher input aesCipher.init(Cipher.DECRYPT_MODE, aesDecryptKey); byte[] decipheredBuff = aesCipher.doFinal(cipherTextBuff); System.out.println(new Ssortingng(decipheredBuff)); } 

Ceci imprime “Texte à encoder”.

La solution est basée sur le Guide de référence de l’architecture de cryptographie Java et sur https://stackoverflow.com/a/20591539/146745 answer.

Editeur en ligne Version exécutable: –

 import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; //import org.apache.commons.codec.binary.Base64; import java.util.Base64; public class Encryptor { public static Ssortingng encrypt(Ssortingng key, Ssortingng initVector, Ssortingng value) { try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8")); SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); byte[] encrypted = cipher.doFinal(value.getBytes()); //System.out.println("encrypted ssortingng: " // + Base64.encodeBase64Ssortingng(encrypted)); //return Base64.encodeBase64Ssortingng(encrypted); Ssortingng s = new Ssortingng(Base64.getEncoder().encode(encrypted)); return s; } catch (Exception ex) { ex.printStackTrace(); } return null; } public static Ssortingng decrypt(Ssortingng key, Ssortingng initVector, Ssortingng encrypted) { try { IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8")); SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); byte[] original = cipher.doFinal(Base64.getDecoder().decode(encrypted)); return new Ssortingng(original); } catch (Exception ex) { ex.printStackTrace(); } return null; } public static void main(Ssortingng[] args) { Ssortingng key = "Bar12345Bar12345"; // 128 bit key Ssortingng initVector = "RandomInitVector"; // 16 bytes IV System.out.println(encrypt(key, initVector, "Hello World")); System.out.println(decrypt(key, initVector, encrypt(key, initVector, "Hello World"))); } }