/**
* {iDart - Pharmacy dispensing tool for cronic diseases}
* Copyright (C) 2006 Cell-Life
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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 version
* 2 for more details.
*
* You should have received a copy of the GNU General Public License version 2
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
**/
package org.celllife.idart.misc;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import java.util.Map.Entry;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* Created on 31/07/2006
*
* Class to encrypt and decrypt system properties from a file file format:
*
* property_name_no_spaces property_no_spaces or
* property_name_no_spaces=property_no_spaces
*
* property_name should start with encrypted if the property is meant to be
* encrypted / decrypted
*
* Has a main method that encrypts the given file, used during installation by
* izPack
*
*/
public class PropertiesEncrypter {
private static String fubu = "[B@4aeb52";
private static SecretKey blowfishKey;
private static Cipher ecipher;
private static Cipher dcipher;
private static boolean debug;
private SortedProperties props;
public PropertiesEncrypter() {
init();
}
public Properties getProperties() {
return props;
}
/**
* Method main.
*
* @param args
* expecting the names of the input file and output file.
* @throws IOException
*/
public static void main(String[] args) throws IOException {
if (args.length != 2)
throw new IllegalArgumentException(
"Expecting exactly two argument.");
debug = true;
PropertiesEncrypter pe = new PropertiesEncrypter();
File input = pe.loadPropertiesFromFile(args[0]);
pe.encryptProperties();
pe.savePropertiesToFile(args[1]);
input.delete();
}
/**
* Creates a new SystemPropertiesEncrypter, which can be used to encrypt or
* decrypt the given file
*/
private void init() {
byte[] raw = fubu.getBytes();
blowfishKey = new SecretKeySpec(raw, "Blowfish");
try {
ecipher = Cipher.getInstance("Blowfish");
dcipher = Cipher.getInstance("Blowfish");
ecipher.init(Cipher.ENCRYPT_MODE, blowfishKey);
dcipher.init(Cipher.DECRYPT_MODE, blowfishKey);
} catch (NoSuchPaddingException e) {
System.out.println("EXCEPTION: NoSuchPaddingException");
} catch (NoSuchAlgorithmException e) {
System.out.println("EXCEPTION: NoSuchAlgorithmException");
} catch (InvalidKeyException e) {
System.out.println("EXCEPTION: InvalidKeyException");
}
}
public void decryptProperties() {
processProperties(EncryptionMode.DECRYPT);
}
public void encryptProperties() {
processProperties(EncryptionMode.ENCRYPT);
}
public File loadPropertiesFromFile(String fileName) throws IOException {
File inFile = new File(fileName);
InputStream in;
try {
in = new FileInputStream(inFile);
} catch (FileNotFoundException e) {
throw new IllegalArgumentException(
"Input file does not exist or is a directory: "
+ inFile.getAbsolutePath(), e);
}
props = loadProperties(in);
return inFile;
}
public void loadPropertiesFromString(String properties) throws IOException {
InputStream in = new ByteArrayInputStream(properties.getBytes());
props = loadProperties(in);
}
/**
* Loads the properties from and InputStream
*
* @param in
* InputStream from which to load the properties
* @return the loaded properties
* @throws IOException
*/
private SortedProperties loadProperties(InputStream in) throws IOException {
SortedProperties properties = new SortedProperties();
properties.load(in);
props = properties;
return props;
}
private void processProperties(EncryptionMode mode) {
for (Entry<Object, Object> e : props.entrySet()) {
String key = (String) e.getKey();
String value = (String) e.getValue();
if (key.startsWith("encrypted")) {
String processedValue = "";
switch (mode) {
case ENCRYPT:
try {
processedValue = encrypt(value);
} catch (EncryptionException e1) {
System.err.println("Failed to encrypt proptery: "
+ value);
e1.printStackTrace();
}
break;
case DECRYPT:
try {
processedValue = decrypt(value);
} catch (EncryptionException e1) {
System.err.println("Failed to decrypt proptery: "
+ value);
e1.printStackTrace();
}
break;
}
if (debug) {
System.out.println(key + "=" + processedValue);
}
props.setProperty(key, processedValue);
} else {
if (debug) {
System.out.println(key + "=" + value);
}
}
}
}
public void savePropertiesToFile(String fileName) throws IOException {
File outFile = new File(fileName);
OutputStream out;
try {
out = new FileOutputStream(outFile);
} catch (FileNotFoundException e) {
throw new IllegalArgumentException(
"Output file does not exist or is a directory: "
+ outFile.getAbsolutePath(), e);
}
props.store(out, "Encrypted properties generated by iDART.");
}
/**
* Takes a single String as an argument and returns an Encrypted version of
* that String.
*
* @param str
* String to be encrypted
* @return <code>String</code> Encrypted version of the provided String
* @throws EncryptionException
*/
private String encrypt(String str) throws EncryptionException {
assert ecipher != null : "SystemPropertiesEncyrpter not initialised.";
try {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
String tmp = Base64.encodeBytes(enc);
// Strip out all newline and linefeed characters
return tmp.replaceAll("[\r,\n]", "");
} catch (BadPaddingException e) {
throw new EncryptionException("Error encrypting properties.", e);
} catch (IllegalBlockSizeException e) {
throw new EncryptionException("Error encrypting properties.", e);
} catch (UnsupportedEncodingException e) {
throw new EncryptionException("Error encrypting properties.", e);
}
}
/**
* Takes a encrypted String as an argument, decrypts and returns the
* decrypted String.
*
* @param str
* Encrypted String to be decrypted
* @return <code>String</code> Decrypted version of the provided String
* @throws EncryptionException
*/
private String decrypt(String str) throws EncryptionException {
assert dcipher != null : "SystemPropertiesEncyrpter not initialised.";
try {
// Decode base64 to get bytes
byte[] dec = Base64.decode(str);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (BadPaddingException e) {
throw new EncryptionException("Error decrypting properties.", e);
} catch (IllegalBlockSizeException e) {
throw new EncryptionException("Error decrypting properties.", e);
} catch (UnsupportedEncodingException e) {
throw new EncryptionException("Error decrypting properties.", e);
}
}
}