package com.introspy.hooks;
import com.introspy.core.IntroHook;
import java.security.Key;
import java.util.Stack;
import javax.crypto.Cipher;
import android.util.Log;
import com.introspy.core.ApplicationConfig;
class Intro_CRYPTO extends IntroHook {
protected static Cipher _lastCipher;
protected static Integer _lastMode;
}
class Intro_CRYPTO_FINAL_UTIL extends Intro_CRYPTO {
protected static Stack<byte[]> IVList = new Stack<byte[]>();
protected String _out = "";
protected boolean _warning = false;
protected void _getIV(Cipher cipher) {
if (cipher.getIV() != null) {
String iv = _getReadableByteArr(cipher.getIV());
_out += "; IV: " + iv;
_logParameter("IV", iv);
if (cipher.getIV()[0] == 0) {
Log.w("Introspy", "!!! IV of 0");
_warning = true;
}
else {
// check if this IV has already been used
if (IVList.contains(cipher.getIV())) {
_out += " - !!! Static IV";
_warning = true;
}
IVList.push(cipher.getIV());
// keep a list of a max of 10 IVs
if (IVList.size() > 10)
IVList.pop();
}
}
}
protected void _getAlgo(Cipher cipher) {
String algo = cipher.getAlgorithm();
if (algo != null) {
_out = "-> Algo: " + algo;
_logParameter("Algo", algo);
if (cipher.getAlgorithm().contains("ECB")) {
_warning = true;
_out += " - !!! ECB used. ECB mode is broken and should not be used.";
}
}
}
}
class Intro_CRYPTO_FINAL extends Intro_CRYPTO_FINAL_UTIL {
private void _getInput(byte[] data) {
if (data != null && data.length != 0) { // when no args to doFinal (used only update())
String i_sdata = null;
i_sdata = new String(data);
if (i_sdata != null && !i_sdata.isEmpty()) {
if (_isItReadable(i_sdata)) {
i_sdata = _byteArrayToReadableStr(data);
_logParameter("input (Encrypt)", i_sdata);
_logLine("-> ENCRYPT: [" + i_sdata + "]");
}
else {
String sdata = _byteArrayToB64(data);
_logLine("-> Input data is not in a readable format, " +
"base64: ["+ sdata +"]");
_logParameter("Output (converted to b64)", sdata);
}
}
}
}
private void _getOutput(Object... args) {
byte[] data = null;
String o_sdata = null;
// if (cipher == _lastCipher && _lastMode == Cipher.DECRYPT_MODE)
try {
data = (byte[]) _hookInvoke(args);
}
catch (Throwable e) {
Log.i(_TAG_ERROR, "doFinal function failed: "+e);
}
if (data != null) {
o_sdata = new String(data);
if (_isItReadable(o_sdata)) {
o_sdata = _byteArrayToReadableStr(data);
_logParameter("Ouput (Decrypt)", o_sdata);
_logLine("-> DECRYPT: [" + o_sdata + "]");
}
else {
String sdata = _byteArrayToB64(data);
_logLine("-> Output data is not in a readable format," +
" base64: ["+ sdata +"]");
_logReturnValue("Output (converted to b64)", sdata);
}
}
// } else {
// }
}
public void execute(Object... args) {
if (_resources != null) {
_warning = false;
_out = "";
Cipher cipher = (Cipher) _resources;
_logBasicInfo();
// input
if (args.length != 0 && args[0] != null) {
try {
_getInput((byte[]) args[0]);
}
catch (Exception e) {
Log.w(_TAG_ERROR, "Error in _getInput " +
"(CRYPTO_IMPL->dofinal): " + e);
}
}
//output
try {
_getOutput(args);
}
catch (Exception e) {
Log.w(_TAG_ERROR, "Error in _getOutput " +
"(CRYPTO_IMPL->dofinal): " + e);
}
// algo/IV
try {
_getAlgo(cipher);
_getIV(cipher);
}
catch (Exception e) {
Log.w(_TAG_ERROR, "Error in _getAlgo/_getCipher " +
"(CRYPTO_IMPL->dofinal): " + e);
}
// dump some params
if (cipher.getParameters() != null && ApplicationConfig.g_debug)
_logLine("Parameters: " + cipher.getParameters());
if (_warning)
_logFlush_W(_out);
else if (!_out.isEmpty())
_logFlush_I(_out);
}
else {
Log.w(_TAG_ERROR,
"Error in Intro_CRYPTO: resource is null");
}
}
}
class Intro_CRYPTO_INIT extends Intro_CRYPTO {
public void execute(Object... args) {
// let's not care about init since we are hooking
// the key class already
// BUT it can be useful to get a state of the mode
// if needed later
if (_resources != null) {
try {
_lastCipher = (Cipher) _resources;
// get the mode
Integer mode = _lastMode = (Integer) args[0];
String smode;
switch (mode) {
case Cipher.DECRYPT_MODE:
smode = "DECRYPT_MODE";
break;
case Cipher.ENCRYPT_MODE:
smode = "ENCRYPT_MODE";
break;
default:
smode = "???";
}
_logBasicInfo();
String out = "-> Mode: " + smode;
// get the key
Key key = (Key) args[1];
String skey = "";
if (key != null) {
skey = _getReadableByteArr(key.getEncoded());
out += ", Key format: " + key.getFormat() +
", Key: [" + skey + "]";
}
_logParameter("Mode", smode);
_logParameter("Key", skey);
_logParameter("Key Format", key.getFormat());
_logFlush_I(out);
} catch (Exception e) {
Log.w(_TAG_ERROR, "Error in Intro_CRYPTO: " + e);
}
}
}
}