package info.guardianproject.pixelknot;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import info.guardianproject.f5android.plugins.PluginNotificationListener;
import info.guardianproject.f5android.plugins.f5.Extract;
import info.guardianproject.f5android.plugins.f5.james.Jpeg;
import info.guardianproject.pixelknot.crypto.Aes;
class StegoDecryptionJob extends StegoJob {
private static final boolean LOGGING = false;
private static final String LOGTAG = "StegoDecryptionJob";
public interface OnProgressListener {
void onProgressUpdate(StegoDecryptionJob job, int percent);
}
private final DummyListenerActivity mActivity;
private String mMessage;
private final String mPassword;
private final File mOutputFile;
private OnProgressListener mOnProgressListener;
public StegoDecryptionJob(IStegoThreadHandler threadHandler, File outputFile, String password) {
super(threadHandler);
mOutputFile = outputFile;
mMessage = null;
mPassword = password;
mActivity = new DummyListenerActivity();
addProcess(new Runnable() {
@SuppressLint("LongLogTag")
@Override
public void run() {
try {
Extract extract = new Extract(mActivity, mOutputFile, getF5Seed());
extract.run();
} catch (Exception e) {
Log.e(Jpeg.LOG, e.toString());
e.printStackTrace();
abortJob();
}
}
}, Constants.Steps.EXTRACT);
if (hasPassword()) {
addProcess(new Runnable() {
@Override
public void run() {
if (mMessage != null && mMessage.indexOf(Constants.PASSWORD_SENTINEL) == 0) {
String secret_message = mMessage.substring(Constants.PASSWORD_SENTINEL.length());
int idx = secret_message.indexOf("\n");
byte[] message = Base64.decode(secret_message.substring(idx + 1), Base64.DEFAULT);
byte[] iv = Base64.decode(secret_message.substring(0, idx), Base64.DEFAULT);
String sm = Aes.DecryptWithPassword(extractPassword(mPassword), iv, message, extractPasswordSalt(mPassword).getBytes());
if (sm != null) {
mMessage = sm;
} else {
// Wrong password
abortJob();
}
}
onProgressTick();
}
}, 1);
}
addProcess(new Runnable() {
@Override
public void run() {
setProcessingStatus(mMessage != null ? ProcessingStatus.EXTRACTED_SUCCESSFULLY : ProcessingStatus.ERROR);
onProgressTick();
}
}, 1);
Run();
}
public String getMessage() {
return mMessage;
}
public void setOnProgressListener(OnProgressListener listener) {
mOnProgressListener = listener;
}
private boolean hasPassword() {
return !TextUtils.isEmpty(mPassword);
}
private String extractPasswordSalt(String from_password) {
return from_password.substring(from_password.length()/3, (from_password.length()/3)*2);
}
private String extractF5Seed(String from_password) {
return from_password.substring((from_password.length()/3)*2);
}
private String extractPassword(String from_password) {
return from_password.substring(0, from_password.length()/3);
}
private String getPassword() {
if(!hasPassword()) {
return null;
}
return extractPassword(mPassword);
}
private byte[] getPasswordSalt() {
if(!hasPassword()) {
return Constants.DEFAULT_PASSWORD_SALT;
}
return extractPasswordSalt(mPassword).getBytes();
}
private byte[] getF5Seed() {
if(!hasPassword()) {
return Constants.DEFAULT_F5_SEED;
}
return extractF5Seed(mPassword).getBytes();
}
@Override
void setProcessingStatus(ProcessingStatus processingStatus) {
super.setProcessingStatus(processingStatus);
if (mOnProgressListener != null) {
mOnProgressListener.onProgressUpdate(StegoDecryptionJob.this, getProgressPercent());
}
}
@Override
void onProgressTick() {
super.onProgressTick();
if (mOnProgressListener != null) {
mOnProgressListener.onProgressUpdate(StegoDecryptionJob.this, getProgressPercent());
}
}
private class DummyListenerActivity extends Activity implements PluginNotificationListener, Extract.ExtractionListener {
@Override
public Resources getResources() {
return mThreadHandler.getContext().getResources();
}
@Override
public void onUpdate(String with_message) {
onProgressTick();
}
@Override
public void onFailure() {
mMessage = null;
abortJob();
}
@Override
public void onExtractionResult(ByteArrayOutputStream baos) {
mMessage = new String(baos.toByteArray());
}
}
}