package org.kisst.util;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CryptoUtil {
final static Logger logger=LoggerFactory.getLogger(CryptoUtil.class);
public static interface KeySetter {
public void setCryptoKey();
}
private static final String ALGORITHM = "AES";
private static Key key= calcKey("jF0OQtZ4PYlEzEyZCchJdIq22GUuV6U9LoLZYqRt".getBytes());
public static void checkKeySetter(Object obj) {
if (obj instanceof KeySetter)
((KeySetter) obj).setCryptoKey();
else {
// Old method for module that does not know yet of new CryptoUtil.KeySetter interface
// to be removed in future
Method method = ReflectionUtil.getMethod(obj.getClass(),"setKey", new Class<?>[]{});
if (method!=null) {
if (Modifier.isStatic(method.getModifiers())) {
logger.warn("Using old deprecated way (calling setKey through reflection) for setting cryptoKey in object "+obj);
ReflectionUtil.invoke(null, method, null);
}
}
}
}
// The following method is public, so that any program using this library can set it's
// own key (preferably one that isn't publicly available worldwide through github :-)
public static void setKey(String keystring) {
key=calcKey(keystring.getBytes());
}
public static void setHexKey(String keystring) {
key=calcKey(fromHex(keystring));
}
private static Key calcKey(byte[] keyValue) {
// Make sure the key is 128-bits, if it is too long an Exception will be thrown
byte[] bytes= new byte[16];
for (int i=0; i<keyValue.length; i++)
bytes[i%16] += keyValue[i];
return new SecretKeySpec(bytes, ALGORITHM);
}
public static String encrypt(String valueToEnc) {
try {
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encValue = c.doFinal(valueToEnc.getBytes());
return toHex(encValue);
}
catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); }
catch (NoSuchPaddingException e) { throw new RuntimeException(e); }
catch (InvalidKeyException e) { throw new RuntimeException(e); }
catch (IllegalBlockSizeException e) { throw new RuntimeException(e); }
catch (BadPaddingException e) { throw new RuntimeException(e); }
}
public static String decrypt(String encryptedValue) {
try {
Cipher c;
c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decodedValue = fromHex(encryptedValue);
byte[] decValue = c.doFinal(decodedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); }
catch (NoSuchPaddingException e) { throw new RuntimeException(e); }
catch (InvalidKeyException e) { throw new RuntimeException(e); }
catch (IllegalBlockSizeException e) { throw new RuntimeException(e); }
catch (BadPaddingException e) { throw new RuntimeException(e); }
}
static final String HEXES = "0123456789ABCDEF";
public static byte[] fromHex( String hex) {
byte[] result=new byte[hex.length()/2];
for ( int i=0; i<hex.length(); i+=2) {
byte b=(byte) (HEXES.indexOf(""+hex.charAt(i))*16);
b +=(byte) HEXES.indexOf(""+hex.charAt(i+1));
result[i/2]=b;
}
return result;
}
public static String toHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
public static String parse(String str) {
if (str==null)
return null;
if (str.startsWith("encrypted:"))
return CryptoUtil.decrypt(str.substring(10));
else if (str.startsWith("cleartext:"))
return str.substring(10);
else
throw new RuntimeException("Password property should start with encrypted: or cleartext:");
}
}