com.wassilak.configuration_service.service.ServiceImpl Maven / Gradle / Ivy
Show all versions of configuration-service Show documentation
package com.wassilak.configuration_service.service;
import com.wassilak.configuration_service.configuration.Configuration;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* The ServiceImpl class serves as the reference implementation of the
* Service interface, which provides users the ability to store and retrieve
* Configuration objects. This implementation uses AES-128 to encrypt/decrypt
* the file where the Configuration object is stored.
*
* Copyright (C) 2014 John Wassilak ([email protected])
*
* 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/.
*/
final class ServiceImpl implements Service {
/**
* The loadConfiguration method attempts to read a Configuration object
* from the given file location. The file is expected to be encrypted with
* the given encryption password.
*
* @param fileLocation The file location of the persisted
* Configuration object.
* @param encryptionPassword The password to use when decrypting the file.
* @return The Configuration object stored at the given file location.
* @throws ServiceException If exceptions occurred while trying to read
* a Configuration object from the given file
* location.
*/
public Configuration loadConfiguration(File fileLocation,
String encryptionPassword)
throws ServiceException {
FileInputStream fileInputStream = null;
CipherInputStream cipherInputStream = null;
GZIPInputStream gzipInputStream = null;
ObjectInputStream objectInputStream = null;
try {
fileInputStream = new FileInputStream(fileLocation);
cipherInputStream =
new CipherInputStream(
fileInputStream,
getAes128Cipher(
Cipher.DECRYPT_MODE,
encryptionPassword
)
);
gzipInputStream = new GZIPInputStream(cipherInputStream);
objectInputStream = new ObjectInputStream(gzipInputStream);
Object readObject = objectInputStream.readObject();
if (readObject instanceof Configuration) {
return (Configuration) readObject;
} else {
throw new Exception("No Configuration object found.");
}
} catch (Exception e) {
throw new ServiceException(
"Could not read Configuration - " + e.getMessage()
);
} finally {
closeStream(objectInputStream);
closeStream(cipherInputStream);
closeStream(gzipInputStream);
closeStream(fileInputStream);
}
}
/**
* The persistConfiguration method attempts to store the given
* Configuration object at the given file location. The method uses the
* given encryption password to encrypt the file.
*
* @param fileLocation The file location to persist the Configuration
* object to.
* @param configuration The Configuration object to persist.
* @param encryptionPassword The password to use when encrypting the file.
* @throws ServiceException If an exception occurs while trying to persist
* the given Configuration object to the given
* file location.
*/
public void persistConfiguration(File fileLocation,
Configuration configuration,
String encryptionPassword)
throws ServiceException {
FileOutputStream fileOutputStream = null;
CipherOutputStream cipherOutputStream = null;
GZIPOutputStream gzipOutputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
fileOutputStream = new FileOutputStream(fileLocation);
cipherOutputStream =
new CipherOutputStream(
fileOutputStream,
getAes128Cipher(
Cipher.ENCRYPT_MODE,
encryptionPassword
)
);
gzipOutputStream = new GZIPOutputStream(cipherOutputStream);
objectOutputStream = new ObjectOutputStream(gzipOutputStream);
objectOutputStream.writeObject(configuration);
objectOutputStream.flush();
} catch (Exception e) {
throw new ServiceException(
"Could not persist Configuration - " + e.getMessage()
);
} finally {
closeStream(objectOutputStream);
closeStream(cipherOutputStream);
closeStream(gzipOutputStream);
closeStream(fileOutputStream);
}
}
/**
* The getAes128Cipher method creates an AES cipher using a 128 bit key
* generated by the given password.
*
* @param mode The mode that the cipher should be initialized
* in. Use the constants provided by the Cipher
* class, i.e Cipher.ENCRYPT_MODE or
* Cipher.DECRYPT_MODE.
* @param encryptionPassword The password to use when generating the
* cipher's key.
* @return The initialized Cipher.
* @throws Exception If an exception occurs while trying to create the
* Cipher.
*/
Cipher getAes128Cipher(Integer mode, String encryptionPassword)
throws Exception {
MessageDigest sha = MessageDigest.getInstance("SHA-1");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(
mode,
new SecretKeySpec(
Arrays.copyOf(
sha.digest(encryptionPassword.getBytes()),
16
),
"AES"
),
new IvParameterSpec(
new byte[]{
0, 5, 5, 3, 2, 1, 0, 1,
2, 3, 4, 5, 6, 7, 6, 5
})
);
return cipher;
}
/**
* The closeStream method closes streams, ignoring any exceptions that
* occur while trying to close.
*
* @param stream The stream to close.
*/
void closeStream(Closeable stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException ignored) {
}
}
}
}