/*
SubspaceMobile - A subspace/continuum client for mobile phones
Copyright (C) 2010 Kingsley Masters
Email: kshade2001 at users.sourceforge.net
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
REVISIONS:
*/
package com.subspace.network;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import android.util.Log;
import com.subspace.random.*;
/**
*
* @author Kingsley
*/
public final class NetworkEncryptionVIE implements INetworkEncryption {
static final String TAG = "Subspace";
static final int BAD_KEY = -1;
static final int MAX_PACKET_SIZE = 520;
int key;
ByteBuffer keyStream;
boolean encrypt = false;
SubspaceHeavyLCG prng = new SubspaceHeavyLCG();
public boolean isConnected() {
return encrypt;
}
public NetworkEncryptionVIE() {
keyStream = ByteBuffer.allocate(MAX_PACKET_SIZE);
keyStream.order(ByteOrder.LITTLE_ENDIAN);
key = BAD_KEY;
}
public ByteBuffer CreateLogin() {
encrypt = false;
key = Util.GetRandomInt();
if (key > 0) {
key = -key;
}
Log.d(TAG, "Create Key: " + key);
return NetworkPacket.CreateConnection(key, (short) 1);
}
public boolean HandleLoginAck(ByteBuffer bb) {
if (bb.limit() >= 6) {
int gotkey = bb.getInt(2);
if (gotkey == key) /* signal for no encryption */ {
key = BAD_KEY;
return true;
//encryption is not turned on
} else {
if (key == -gotkey) {
Log.d(TAG, "Init VIE Encryption\n");
key = gotkey;
DoInit();
return true;
} else {
Log.d(TAG, "Invalid Key: " + gotkey);
}
}
}
return false;
}
void DoInit() {
int k = key;
if (k == 0) {
return;
}
prng.seed(k);
for (int i = 0; i < MAX_PACKET_SIZE; i += 2) {
keyStream.putShort(i, prng.getNextE());
}
//turn encryption on now
encrypt = true;
}
public void Encrypt(ByteBuffer message) {
message.rewind();
int length = message.limit();
if (length > MAX_PACKET_SIZE) {
throw new IndexOutOfBoundsException("Max Packet Length for VIE Encrption is 520");
}
if (!encrypt) {
return; //if encryption isnt on, dont do it!
}
message.order(ByteOrder.LITTLE_ENDIAN);
//if encryption isnt need
if (this.key == 0 || keyStream.getInt(0) == 0) {
return;
}
int work = key;
int mytable = 0;
int mydata = 0;
int loop, until, lengthWithoutHeader;
if (work == 0 || keyStream.getInt(0) == 0) {
return;
}
if (message.get(0) == 0) {
mydata = 2;
lengthWithoutHeader = (length - 2);
until = lengthWithoutHeader / 4;
} else {
mydata = 1;
lengthWithoutHeader = (length - 1);
until = lengthWithoutHeader / 4;
}
if(lengthWithoutHeader % 4 !=0) until++;
for (loop = 0; loop < until; loop++) {
work = Util.safeGetInt(message,mydata + loop * 4)
^ keyStream.getInt(mytable + loop * 4) ^ work;
Util.safePutInt(message,mydata + loop * 4, work);
}
message.rewind();
}
public void Decrypt(ByteBuffer message) {
message.rewind();
int length = message.limit();
if (length > MAX_PACKET_SIZE) {
throw new IndexOutOfBoundsException("Max Packet Length for VIE Encrption is 520");
}
if (!encrypt) {
return; //if encryption isnt on, dont do it!
}
//if encryption isnt need
if (this.key == 0 || keyStream.getInt(0) == 0) {
return;
}
int work = key;
int mytable = 0; //keyStreamMessage(int);
int mydata = 0;//msg(int)
int loop, until;
int lengthWithoutHeader = 0;
if (message.get(0) == 0) {
mydata = 2;
lengthWithoutHeader = (length - 2);
until = lengthWithoutHeader / 4;
} else {
mydata = 1;
lengthWithoutHeader = (length - 1);
until = lengthWithoutHeader / 4;
}
if(lengthWithoutHeader % 4 !=0) until++;
for (loop = 0; loop < until; loop++) {
int tmp = Util.safeGetInt(message, mydata + loop * 4);
Util.safePutInt(message,
mydata + loop * 4,
keyStream.getInt(mytable + loop * 4)
^ work ^ tmp);
work = tmp;
}
message.rewind();
}
}