/* * Copyright (C) 2014 Serverfrog.de * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.serverfrog.pw; import de.serverfrog.pw.crypt.SerpentUtil; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.Security; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.SecretKey; import org.apache.commons.io.IOUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * * @author Bastian Venz */ public class ConfigurationUtil { static { Security.addProvider(new BouncyCastleProvider()); } private static final String configPath = System.getProperty("user.home") + "/.FrogPw"; private static final String configFilePath = System.getProperty("user.home") + "/.FrogPw/config.crypted"; private static final String saltFilePath = System.getProperty("user.home") + "/.FrogPw/salt.crypted"; /** * This Method write a List of Configurations into the default File. The * File is with Seprent encrypted and has a 256 Bit Salt. * * @param c is the list of configurations which should be saved. * @param password is the password with which the file is encrypted. * @throws IOException is thrown if something went wrong while the IO * Process. */ public static void writeConfig(ArrayList<Configuration> c, byte[] password) throws IOException { try { File configFolder = new File(configPath); if (!configFolder.exists()) { configFolder.mkdirs(); } if (!configFolder.canRead() || !configFolder.canWrite()) { throw new IOException("Can't Read or Write into Configuration Folder \"" + configFolder.getAbsolutePath() + "\""); } File configFile = new File(configFilePath); if (!configFile.exists()) { configFile.createNewFile(); } File saltFile = new File(saltFilePath); byte[] salt = new byte[256]; if (!saltFile.exists()) { saltFile.createNewFile(); salt = SecureRandom.getInstanceStrong().generateSeed(256); try (FileOutputStream fos = new FileOutputStream(saltFile);) { fos.write(salt); } } FileReader fr = new FileReader(saltFile); int i = 0; while (fr.ready()) { salt[i] = (byte) fr.read(); } SecretKey generateKey = SerpentUtil.generateKey(password, salt); try (FileOutputStream fos = new FileOutputStream(configFilePath); CipherOutputStream outputStream = SerpentUtil.getOutputStream(fos, generateKey); ObjectOutputStream oss = new ObjectOutputStream(outputStream)) { oss.writeObject(c); } catch (Exception ex) { configFile.delete(); } } catch (NoSuchAlgorithmException ex) { Logger.getLogger(ConfigurationUtil.class.getName()).log(Level.SEVERE, null, ex); } } /** * This Method reads from the default Location the "config.crypted" and the * "salt.crypted" File an return that Encrypted Configuration File which is * encrypted with the given password. * * @param password is the password of the encrypted configuration file. * @return a List of Configurations whiche were saved in the encrypted * files. * @throws IOException if something was wrong while reading the files and/or * converting them into objects. */ public static ArrayList<Configuration> readConfig(byte[] password) throws IOException { try { ObjectInputStream ois = null; File saltFile = new File(saltFilePath); byte[] salt = new byte[256]; FileReader fr = new FileReader(saltFile); int i = 0; while (fr.ready()) { salt[i] = (byte) fr.read(); } SecretKey generateKey = SerpentUtil.generateKey(password, salt); try (FileInputStream fis = new FileInputStream(configFilePath); CipherInputStream inputStream = SerpentUtil.getInputStream(fis, generateKey);) { byte[] toByteArray = IOUtils.toByteArray(inputStream); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(toByteArray); try { ois = new ObjectInputStream(byteArrayInputStream); } catch (java.lang.NullPointerException ex) { throw new IOException(ex); } ArrayList readObject = (ArrayList) ois.readObject(); ArrayList<Configuration> configs = new ArrayList<>(); for (Object object : readObject) { if (!(object instanceof Configuration)) { throw new RuntimeException("Loaded Class was not from type Configuration. Class=" + object.getClass()); } configs.add((Configuration) object); } return configs; } finally { if (ois != null) { ois.close(); } } } catch (ClassNotFoundException ex) { throw new RuntimeException("Could not Find class.", ex); } } /** * Add a Configuration to the encrypted Savefile. * * @param c is the Configration which should be added. * @param password is the password of the encrypted file. * @throws IOException is thrown if something went wrong in the IO Process. */ public static void addConfiguration(Configuration c, byte[] password) throws IOException { ArrayList<Configuration> readConfig = new ArrayList<>(); if (exist()) { readConfig = readConfig(password); } if (readConfig.contains(c)) { readConfig.add(readConfig.indexOf(c), c); } else { readConfig.add(c); } writeConfig(readConfig, password); } /** * This method checks if every file which is needed to read or write a * configuration is existing. * * @return True if the encrypted configuration File and the Salt file exist. */ public static boolean exist() { return new File(configFilePath).exists() && new File(saltFilePath).exists(); } }