Partagez le password
(a char[]
) et salt
(a - byte[]
8 octets sélectionnés par un SecureRandom
fait un bon sel - qui n'a pas besoin d'être gardé secret) avec le destinataire hors bande. Ensuite, pour dériver une bonne clé de ces informations:
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Les nombres magiques (qui pourraient être définis comme des constantes quelque part) 65536 et 256 sont le nombre d'itérations de dérivation de clé et la taille de clé, respectivement.
La fonction de dérivation de clé est itérée pour exiger un effort de calcul important, et cela empêche les attaquants d'essayer rapidement de nombreux mots de passe différents. Le nombre d'itérations peut être modifié en fonction des ressources informatiques disponibles.
La taille de la clé peut être réduite à 128 bits, ce qui est toujours considéré comme un cryptage "fort", mais cela ne donne pas beaucoup de marge de sécurité si l'on découvre des attaques qui affaiblissent AES.
Utilisée avec un mode de chaînage de blocs approprié, la même clé dérivée peut être utilisée pour crypter de nombreux messages. Dans Cipher Block Chaining (CBC) , un vecteur d'initialisation aléatoire (IV) est généré pour chaque message, produisant un texte chiffré différent même si le texte brut est identique. CBC n'est peut-être pas le mode le plus sûr à votre disposition (voir AEAD ci-dessous); il existe de nombreux autres modes avec des propriétés de sécurité différentes, mais ils utilisent tous une entrée aléatoire similaire. Dans tous les cas, les sorties de chaque opération de chiffrement sont le texte chiffré et le vecteur d'initialisation:
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
Stockez le ciphertext
et le iv
. Lors du déchiffrement, le SecretKey
est régénéré exactement de la même manière, en utilisant le mot de passe avec les mêmes paramètres de sel et d'itération. Initialisez le chiffrement avec cette clé et le vecteur d'initialisation stocké avec le message:
/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), "UTF-8");
System.out.println(plaintext);
Java 7 incluait la prise en charge de l' API pour les modes de chiffrement AEAD , et le fournisseur "SunJCE" inclus avec les distributions OpenJDK et Oracle les implémente à partir de Java 8. L'un de ces modes est fortement recommandé à la place de CBC; il protégera l'intégrité des données ainsi que leur confidentialité.
Un java.security.InvalidKeyException
avec le message "Taille de clé illégale ou paramètres par défaut" signifie que la puissance de cryptographie est limitée; les fichiers de politique de compétence de force illimitée ne sont pas au bon endroit. Dans un JDK, ils doivent être placés sous${jdk}/jre/lib/security
D'après la description du problème, il semble que les fichiers de stratégie ne soient pas correctement installés. Les systèmes peuvent facilement avoir plusieurs runtimes Java; revérifiez pour vous assurer que l'emplacement correct est utilisé.