package model.persistance;
import java.io.*;
import java.nio.file.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import org.apache.log4j.*;
public class Storer {
private String storePath;
private Key key;
private static final Logger LOGGER = Logger.getLogger(Storer.class);
public Storer(String storePath) {
this.storePath = storePath;
}
protected void store(Storable storableObject) {
createStorageFolder();
String thisStorePath = createStorePath(storableObject);
// TODO check if file already exists and throw exception!
serializeAndEncrypt(storableObject, thisStorePath);
}
private void createStorageFolder() {
File file = new File(storePath);
if (!file.exists()) {
file.mkdir();
}
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
try {
Files.setAttribute(file.toPath(), "dos:hidden", true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
protected Storable load(Storable storableObject) {
return (Storable) deserializeAndDecrypt(createStorePath(storableObject));
}
private String createStorePath(Storable storableObject) {
String thisStorePath = storePath + "/" + storableObject.getStorageFileName();
return thisStorePath;
}
private void serializeAndEncrypt(Serializable object, String path) {
SealedObject sealedObject = encryptStorableObject(object);
Object storableObject;
if (sealedObject == null) {
storableObject = object;
} else {
storableObject = sealedObject;
}
serialize(storableObject, path);
}
private void serialize(Object object, String path) {
ObjectOutputStream out = null;
try {
FileOutputStream output = new FileOutputStream(path);
out = new ObjectOutputStream(output);
out.writeObject(object);
out.close();
} catch (FileNotFoundException e) {
LOGGER.error(e);
} catch (IOException e) {
LOGGER.error(e);
}
}
private Object deserializeAndDecrypt(String path) {
Object object = deserialize(path);
Storable storable = decryptSealedObject(object);
return storable;
}
private Object deserialize(String path) {
Object object = null;
try {
final FileInputStream fileInputStream = new FileInputStream(new File(path));
ObjectInputStream o = new ObjectInputStream(fileInputStream);
object = o.readObject();
o.close();
} catch (FileNotFoundException e) {
LOGGER.error(e);
} catch (IOException e) {
LOGGER.error(e);
} catch (ClassNotFoundException e) {
LOGGER.error(e);
}
return object;
}
private SealedObject encryptStorableObject(Serializable object) {
Cipher cipher = null;
KeyGenerator keyGen = null;
SealedObject sealedObject = null;
try {
keyGen = KeyGenerator.getInstance("AES");
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
keyGen.init(128);
if (key == null) {
key = keyGen.generateKey();
serialize(key, storePath + "/" + "key.ser");
}
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivspec);
sealedObject = new SealedObject(object, cipher);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| IllegalBlockSizeException | IOException | InvalidAlgorithmParameterException e1) {
LOGGER.warn("No Cipher.", e1);
e1.printStackTrace();
}
return sealedObject;
}
private Storable decryptSealedObject(Object object) {
if (!(object instanceof SealedObject)) {
return null;
}
SealedObject sealedObject = (SealedObject) object;
Cipher cipher = null;
Storable storable;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey key = (SecretKey) deserialize(storePath + "/" + "key.ser");
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, ivspec);
storable = (Storable) sealedObject.getObject(cipher);
} catch (ClassCastException | NoSuchAlgorithmException | NoSuchPaddingException
| InvalidKeyException | IllegalBlockSizeException | IOException
| ClassNotFoundException | BadPaddingException | InvalidAlgorithmParameterException e1) {
LOGGER.warn("No Cipher.", e1);
e1.printStackTrace();
return null;
}
return storable;
}
}