chiffrer et déchiffrer la valeur du fichier de propriétés en java

Je cherche un moyen de chiffrer un mot de passe dans un fichier de configuration en cours de lecture par un programme Java. Actuellement, j’ai lu le mot de passe à partir du fichier texte, mais cela laisse le mot de passe à l’air libre si quelqu’un devait consulter le fichier de configuration.

Je pensais à la construction d’une classe simple où l’utilisateur pourrait saisir le mot de passe souhaité, obtenir une version chiffrée du mot de passe, puis coller la version chiffrée dans le fichier texte de configuration. Ensuite, l’application lirait le mot de passe crypté, décrypterait le mot de passe dans une chaîne et passerait à autre chose.

J’ai des problèmes avec la chaîne -> octets cryptés -> conversions de chaînes.

J’utilise les classes de sécurité Java intégrées pour implémenter ce code. Voici un exemple de code de test:

// Reads password from config file Ssortingng password = ScriptConfig.getSsortingng( "password" ); // Generate Key KeyGenerator kg = KeyGenerator.getInstance("DES"); Key key = kg.generateKey(); // Create Encryption cipher Cipher cipher = Cipher.getInstance( "DES" ); cipher.init( Cipher.ENCRYPT_MODE, key ); // Encrypt password byte[] encrypted = cipher.doFinal( password.getBytes() ); // Create decryption cipher cipher.init( Cipher.DECRYPT_MODE, key ); byte[] decrypted = cipher.doFinal( encrypted ); // Convert byte[] to Ssortingng Ssortingng decryptedSsortingng = new Ssortingng(decrypted); System.out.println("password: " + password); System.out.println("encrypted: " + encrypted); System.out.println("decrypted: " + decryptedSsortingng); // Read encrypted ssortingng from config file Ssortingng encryptedPassword = ScriptConfig.getSsortingng( "encryptedPassword" ); // Convert encryptedPassword ssortingng into byte[] byte[] encryptedPasswordBytes = new byte[1024]; encryptedPasswordBytes = encryptedPassword.getBytes(); // Decrypt encrypted password from config file byte[] decryptedPassword = cipher.doFinal( encryptedPasswordBytes );//error here System.out.println("encryptedPassword: " + encryptedPassword); System.out.println("decryptedPassword: " + decryptedPassword); The config file has the following variables: password=password encryptedPassword=[B@2a4983 When I run the code, I get the following output: password: passwd encrypted: [B@2a4983 decrypted: passwd javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher at com.sun.crypto.provider.SunJCE_h.b(DashoA12275) at com.sun.crypto.provider.SunJCE_h.b(DashoA12275) at com.sun.crypto.provider.DESCipher.engineDoFinal(Da shoA12275) at javax.crypto.Cipher.doFinal(DashoA12275) at com.sapient.fbi.uid.TestEncryption.main(TestEncryp tion.java:4 

Toute aide sur l’erreur, la structure ou le processus que j’utilise pour faire cela serait formidable. Merci.

Une solution très simple serait d’utiliser l’encodage Base64, voir l’extrait de code ci-dessous: –

 import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; ... private Ssortingng encode(Ssortingng str) { BASE64Encoder encoder = new BASE64Encoder(); str = new Ssortingng(encoder.encodeBuffer(str.getBytes())); return str; } private Ssortingng decode(Ssortingng str) { BASE64Decoder decoder = new BASE64Decoder(); try { str = new Ssortingng(decoder.decodeBuffer(str)); } catch (IOException e) { e.printStackTrace(); } return str; } ... 

Jetez un coup d’œil à Jasypt . Il a déjà fait le gros du travail pour vous. Plus précisément, les classes org.jasypt.encryption.pbe.StandardPBESsortingngEncryptor et org.jasypt.properties.PropertyValueEncryptionUtils .

Créer un crypteur:

 SimplePBEConfig config = new SimplePBEConfig(); config.setAlgorithm("PBEWithMD5AndTripleDES"); config.setKeyObtentionIterations(1000); config.setPassword("propertiesFilePassword"); StandardPBESsortingngEncryptor encryptor = new org.jasypt.encryption.pbe.StandardPBESsortingngEncryptor(); encryptor.setConfig(config); encryptor.initialize(); 

Ensuite, utilisez PropertyValueEncryptionUtils pour chiffrer / déchiffrer des valeurs:

 PropertyValueEncryptionUtils.encrypt(value, encryptor); PropertyValueEncryptionUtils.decrypt(encodedValue, encryptor) 

Notez que la valeur encodée commence par ENC( et se termine par ) , il est donc facile de déterminer si une propriété d’un fichier est cryptée.

Notez également que le mot de passe utilisé pour config.setPassword() n’est pas le mot de passe que vous codez pour être stocké dans le fichier de propriétés. Au lieu de cela, c’est le mot de passe pour chiffrer / déchiffrer la valeur que vous stockez. Ce que ce mot de passe est et comment le configurer est à vous. J’utilise par défaut le nom de classe complet de ce qui lit le fichier de propriétés.

Enfin, si vous utilisez Spring, Jasypt dispose d’une classe EncryptablePropertyPlaceholderConfigurer que vous pouvez utiliser pour charger le fichier de propriétés et utiliser la syntaxe ${foo} dans vos fichiers XML Spring pour effectuer une substitution de variable, par exemple des mots de passe de firebase database.

Voici quelques aides à chiffrer ou à déchiffrer à l’aide d’AES en Java:

 public static final Ssortingng AES = "AES"; /** * Encrypt a value and generate a keyfile. * If the keyfile is not found, then a new one will be created. * * @throws GeneralSecurityException * @throws IOException if an I/O error occurs */ public static Ssortingng encrypt(Ssortingng value, File keyFile) throws GeneralSecurityException, IOException { if (!keyFile.exists()) { KeyGenerator keyGen = KeyGenerator.getInstance(CryptoUtils.AES); keyGen.init(128); SecretKey sk = keyGen.generateKey(); FileWriter fw = new FileWriter(keyFile); fw.write(byteArrayToHexSsortingng(sk.getEncoded())); fw.flush(); fw.close(); } SecretKeySpec sks = getSecretKeySpec(keyFile); Cipher cipher = Cipher.getInstance(CryptoUtils.AES); cipher.init(Cipher.ENCRYPT_MODE, sks, cipher.getParameters()); byte[] encrypted = cipher.doFinal(value.getBytes()); return byteArrayToHexSsortingng(encrypted); } /** * Decrypt a value. * * @throws GeneralSecurityException * @throws IOException if an I/O error occurs */ public static Ssortingng decrypt(Ssortingng message, File keyFile) throws GeneralSecurityException, IOException { SecretKeySpec sks = getSecretKeySpec(keyFile); Cipher cipher = Cipher.getInstance(CryptoUtils.AES); cipher.init(Cipher.DECRYPT_MODE, sks); byte[] decrypted = cipher.doFinal(hexSsortingngToByteArray(message)); return new Ssortingng(decrypted); } private static SecretKeySpec getSecretKeySpec(File keyFile) throws NoSuchAlgorithmException, IOException { byte[] key = readKeyFile(keyFile); SecretKeySpec sks = new SecretKeySpec(key, CryptoUtils.AES); return sks; } private static byte[] readKeyFile(File keyFile) throws FileNotFoundException { Scanner scanner = new Scanner(keyFile).useDelimiter("\\Z"); Ssortingng keyValue = scanner.next(); scanner.close(); return hexSsortingngToByteArray(keyValue); } private static Ssortingng byteArrayToHexSsortingng(byte[] b) { SsortingngBuffer sb = new SsortingngBuffer(b.length * 2); for (int i = 0; i < b.length; i++) { int v = b[i] & 0xff; if (v < 16) { sb.append('0'); } sb.append(Integer.toHexString(v)); } return sb.toString().toUpperCase(); } private static byte[] hexStringToByteArray(String s) { byte[] b = new byte[s.length() / 2]; for (int i = 0; i < b.length; i++) { int index = i * 2; int v = Integer.parseInt(s.substring(index, index + 2), 16); b[i] = (byte) v; } return b; } 

Appelez simplement la méthode appropriée.

J’ai des problèmes avec la chaîne -> octets cryptés -> conversions de chaînes.

Je farcirais le tableau d’octets via un en / décodeur base64. Ainsi, vous devrez conserver des chaînes ne contenant que des caractères dans (un sous-ensemble d’ASCII), ce qui devrait limiter vos problèmes. Regardez par exemple les codecs communs et remplacez votre new Ssortingng(decrypted) par un appel à l’une des méthodes statiques de la classe org.apache.commons.codec.binary.Base64 .

En plus de cela, je pense que ce que vous voulez faire en fin de compte n’est pas ssortingctement de “chiffrer” le mot de passe, mais plutôt de stocker uniquement un hachage du mot de passe, ce qui a déjà été discuté sur SO .