package ch.bfh.sokoban.db;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import ch.bfh.sokoban.common.exceptions.CryptingException;
import ch.bfh.sokoban.lib.jsonJava.JSONArray;
import ch.bfh.sokoban.lib.jsonJava.JSONException;
import ch.bfh.sokoban.lib.jsonJava.JSONObject;
/**
* Is used for encrypting and decrypting Strings and JSONObjects. <br>
* The JSON Objects can then be sent to a PHP script where they can be encrypted and decrypted with the same algorithm.
* @throws CryptingException
*/
public class Cryptor {
private Cipher cipher;
private String secretKey = "1234567890qwertz";
private String iv = "1234567890qwertz";
private final String CIPHER_MODE = "AES/CFB8/NoPadding";
private SecretKey keySpec;
private IvParameterSpec ivSpec;
private static Charset CHARSET = Charset.forName("UTF8");
public Cryptor() {
keySpec = new SecretKeySpec(secretKey.getBytes(CHARSET), "AES");
ivSpec = new IvParameterSpec(iv.getBytes(CHARSET));
try {
cipher = Cipher.getInstance(CIPHER_MODE);
} catch (NoSuchAlgorithmException e) {
throw new SecurityException(e);
} catch (NoSuchPaddingException e) {
throw new SecurityException(e);
}
}
/**
* @param input A "AES/CFB8/NoPadding" encrypted String
* @return The decrypted String
* @throws CryptingException
*/
public String decrypt(String input) {
try {
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
//parseBase64Binary is necessary to convert the String to byte[]
// return new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(input)));
// return new String(cipher.doFinal(Base64.decodeBase64(input)));
return new String(cipher.doFinal(Base64.decode(input, Base64.DEFAULT)));
} catch (IllegalBlockSizeException e) {
throw new SecurityException(e);
} catch (BadPaddingException e) {
throw new SecurityException(e);
} catch (InvalidKeyException e) {
throw new SecurityException(e);
} catch (InvalidAlgorithmParameterException e) {
throw new SecurityException(e);
} /*catch (Base64DecodingException e) {
throw new SecurityException(e);
}*/
}
/**
* @param input Any String to be encrypted
* @return An "AES/CFB8/NoPadding" encrypted String
* @throws CryptingException
*/
public String encrypt(String input) {
try {
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
//printBase64Binary is necessary to convert the byte[] to a String
// return DatatypeConverter.printBase64Binary(cipher.doFinal(input.getBytes(CHARSET))).trim();
// return Base64.encodeBase64String(cipher.doFinal(input.getBytes(CHARSET))).trim();
return Base64.encodeToString(cipher.doFinal(input.getBytes(CHARSET)), Base64.DEFAULT).trim();
} catch (InvalidKeyException e) {
throw new SecurityException(e);
} catch (InvalidAlgorithmParameterException e) {
throw new SecurityException(e);
} catch (IllegalBlockSizeException e) {
throw new SecurityException(e);
} catch (BadPaddingException e) {
throw new SecurityException(e);
}/* catch (NoClassDefFoundError e) {
e.printStackTrace();
return "";
}*/
}
/**
* Encrypts the keys and values of a JSONObject with Cryptor.encrypt(String input)
* @param o The JSONObject to be encrypted
* @return A JSONObject with encrypted keys and values
*/
public JSONObject jsonObjectEncrypt(JSONObject o) {
Iterator<?> keys = o.keys();
JSONObject returnObject = new JSONObject();
while( keys.hasNext() ){
String key = (String)keys.next();
returnObject.put(this.encrypt(key), this.encrypt(o.getString(key)));
}
return returnObject;
}
/**
* Decrypts the keys and values of a JSONObject with Cryptor.decrypt(String input)
* @param o The JSONObject to be decrypted
* @return A JSONObject with decrypted keys and values
*/
public JSONObject jsonObjectDecrypt(JSONObject o) {
Iterator<?> keys = o.keys();
JSONObject returnObject = new JSONObject();
while( keys.hasNext() ){
String key = (String)keys.next();
if(key != null && !key.equals("")) {
returnObject.put(this.decrypt(key), this.decrypt(o.getString(key)));
}
}
return returnObject;
}
/**
* Encrypts keys and values of every JSONObject in a JSONArray
* @param a The JSONArray to be encrypted
* @return A JSONArray with encrypted keys and values
*/
public JSONArray jsonArrayEncrypt(JSONArray a) {
JSONArray returnArray = new JSONArray();
for(int i = 0; i < a.length(); i++) {
returnArray.put(this.jsonObjectEncrypt((JSONObject)a.get(i)));
}
return returnArray;
}
/**
* Decrypts keys and values of every JSONObject in a JSONArray
* @param a The JSONArray to be decrypted
* @return A JSONArray with decrypted keys and values
*/
public JSONArray jsonArrayDecrypt(JSONArray a) {
JSONArray returnArray = new JSONArray();
for(int i = 0; i < a.length(); i++) {
returnArray.put(this.jsonObjectDecrypt((JSONObject)a.get(i)));
}
return returnArray;
}
/**
* Converts a String to a md5 Hash, compatible to the PHP md5 function
* @throws NoSuchAlgorithmException
*/
public static String md5(String input) {
MessageDigest mdEnc;
try {
mdEnc = MessageDigest.getInstance("MD5");
mdEnc.update(input.getBytes(CHARSET), 0, input.length());
return new BigInteger(1, mdEnc.digest()).toString(16); // Encrypted
} catch (NoSuchAlgorithmException e) {
throw new SecurityException(e);
}
}
public static void main(String Args[]) {
try {
Cryptor c = new Cryptor();
String original = "MiiiMüäöMeeʞ";
System.out.println("Original: " + original);
String encrypted = c.encrypt(original);
System.out.println("Encoded: " + encrypted);
System.out.println("Decoded: " + c.decrypt(encrypted));
JSONArray arr = new JSONArray("[{\"id\"=\" 1 ʞ3 \"},{\"id\"=\"key\"}]");
System.out.println(c.encrypt(arr.getJSONObject(1).getString("id")));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}