This commit is contained in:
emigrantMuse 2017-04-16 01:49:52 +08:00
commit 340fecc407
28 changed files with 3950 additions and 0 deletions

6
.classpath Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="output" path="bin"/>
</classpath>

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bin/

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ThinORAM</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -0,0 +1,29 @@
package nankai.oram.client;
public interface MCloudCommInfo {
// public static int severBeginLevel = 3;//the default level of each partition in the server
// public static int clientEndLevel = 2;//the default level of each partition in the client cache
// public static int evictConditionSize = 8;//1+2+4+8+16=31
// public static int cloudNumber = 2; //the cloud number
// public static int severBeginLevel = 4;//the default level of each partition in the server
// public static int clientEndLevel =3;//the default level of each partition in the client cache
// public static int evictConditionSize = 16;//1+2+4=6
// public static int cloudNumber = 2; //the cloud number
public static int severBeginLevel = 2;//the default level of each partition in the server
public static int clientEndLevel =1;//the default level of each partition in the client cache
public static int evictConditionSize = 4;//1+2+4=6
public static int cloudNumber = 2; //the cloud number
// public static int severBeginLevel = 5;//the default level of each partition in the server
// public static int clientEndLevel = 4;//the default level of each partition in the client cache
// public static int evictConditionSize = 32;//1+2+4+8=15
// public static int cloudNumber = 2; //the cloud number
//public static String[] ip={ "114.215.26.85", "114.215.26.85"};
public static String[] ip={ "localhost", "localhost"};
public static int[] port={ 2121, 2122};
}

View File

@ -0,0 +1,280 @@
package nankai.oram.client;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import nankai.oram.client.common.Position;
import nankai.oram.client.common.SlotObject;
import nankai.oram.client.partition.Partition;
import nankai.oram.common.CommInfo;
import nankai.oram.common.SocketClientUtil;
import nankai.oram.common.CommandType;
import nankai.oram.common.ResponseType;
import nankai.oram.common.Util;
import nankai.oram.interfaces.ORAM;
public class PartitionClient implements ORAM{
boolean initFlag;
int N;
int n_partitions;
int n_capacity;//the max capacity of a partition -- need the top level
int n_levels;
int n_blocks;
int n_realBlocks_p;//the real number of blocks in a partition
int counter=0;//for sequneceEvict
byte s_buffer[][];//shuffule buffer - a large memory
Position pos_map[];//position map
/*************************************************/
Queue<SlotObject> slots[];
Partition partions[];
SocketClientUtil cli;
public PartitionClient()
{
initFlag=false;
cli=new SocketClientUtil("localhost",2121);
}
/**
* initialize the parameters, storage space and so on
* @param nN
*/
public boolean init(int nN)
{
if (initFlag==true)
{
System.out.println("have inited!");
return false;
}
N=nN;
n_partitions = (int) Math.ceil(Math.sqrt(nN));
n_realBlocks_p = (int) Math.ceil(((double) nN) / n_partitions);
n_blocks = n_realBlocks_p * n_partitions;
n_levels = (int) (Math.log((double) n_realBlocks_p) / Math.log(2.0)) + 1;
n_capacity = (int) Math.ceil(CommInfo.capacity_parameter * n_realBlocks_p);
partions=new Partition[n_partitions];
s_buffer=new byte[n_capacity][CommInfo.blockSize];
pos_map=new Position[n_blocks];
for (int i=0;i<n_blocks; i++)
{
pos_map[i]=new Position();
}
slots=new Queue[n_partitions];
//randomly generate the keys for each level of each partition
for (int i = 0; i < n_partitions; i++)
{
slots[i]=new LinkedList<SlotObject>();
partions[i]=new Partition(N, n_partitions, pos_map, s_buffer, cli);
}
counter = 0;
initFlag=true;
return true;
}
public void openConnection()
{
cli.connect();
}
public void closeConnection()
{
cli.disConnect();
}
public boolean initORAM()
{
byte cmd[]=new byte[5];
cmd[0]=CommandType.initORAM;
Util.intToByte(cmd, 1, N);
cli.send( cmd, 5, null , 0, null);
return cli.responseType!=ResponseType.wrong;
}
/**
* Notice the ORAM server to open the database, will use the created database
* @return
*/
public boolean openORAM()
{
byte cmd[]=new byte[5];
cmd[0]=CommandType.openDB;
cli.send( cmd, 1, null , 0, null);
return cli.responseType!=ResponseType.wrong;
}
byte[] access(char op, int block_id, byte[] value)
{
byte data[] = new byte[CommInfo.blockSize];
int r = 1;
if (Util.debug==false){
r = Util.rand_int(n_partitions);
//not write to the partition with more than the pre-defined real blocks
while ( partions[r].realDataNumber >= this.n_realBlocks_p )
r = Util.rand_int(n_partitions);
}
int p = pos_map[block_id].partition;
/****************
* Read data from slots or the server
* If it is in the slot
* readAndDel from the slot
* read a dummy block from server
* Else
* read the real block from the server
* ******************/
if (p >= 0) {
boolean isInSlot = false;
Iterator itr = slots[p].iterator();
SlotObject targetObj = null;
while (itr.hasNext())
{
targetObj = (SlotObject)itr.next();
if (targetObj.id==block_id)
{
isInSlot=true;
break;
}
}
if ( isInSlot ) {
// in the slot
System.arraycopy(targetObj.value, 0, data, 0, CommInfo.blockSize);
slots[p].remove(targetObj);
partions[p].readPartition(CommInfo.dummyID);
} else {
/**************************
* Here, should send a request to the cloud server to get the
* data
* **************************/
byte[] bReadData=partions[p].readPartition(block_id);
System.arraycopy(bReadData, 0, data, 0, CommInfo.blockSize);
}
}
pos_map[block_id].partition = r;
pos_map[block_id].level = -1;
pos_map[block_id].offset = -1;
if (op == 'w')
{
data=value;
}
SlotObject newObject = new SlotObject(block_id, data);
slots[r].add(newObject);
// if (p>=0)
// evict(p);
randomEvict(CommInfo.v);
return data;
}
void sequentialEvict(int vNumber)
{
for (int i = 0; i < vNumber; i++) {
counter = (counter + 1) % n_partitions;
evict(counter);
}
}
void randomEvict(int vNumber)
{
Random rnd=new Random();
for (int i = 0; i < vNumber; i++) {
int r = rnd.nextInt(n_partitions);
evict(r);
}
}
void evict(int p) {
if (slots[p].isEmpty()) {
partions[p].writePartition(CommInfo.dummyID, null);
} else {
//pop a data in slots
SlotObject obj=slots[p].poll();
partions[p].writePartition( obj.id, obj.value);
}
}
public int getCacheSlotSize()
{
int ret = 0;
for (int i=0; i<slots.length; i++)
{
ret += slots[i].size();
}
return ret;
}
/**
* Suggest the client to call this, when it will be closed
*/
public void clearSlot()
{
for (int i=0; i<slots.length; i++)
{
/**************
* Here, do not clear directly
* Just remove from the slot, but the data should always stored in the database
* So, we should update the position map
*
*/
while (slots[i].size()>0){
SlotObject obj=slots[i].poll();
partions[i].writePartition(obj.id, obj.value);
}
slots[i].clear();
}
}
@Override
public void write(String idStr, byte[] value) {
access('w', Integer.parseInt(idStr), value);
}
@Override
public byte[] read(String idStr) {
return access('r', Integer.parseInt(idStr), null);
}
@Override
public void write(int id, byte[] value) {
access('w', id, value);
}
@Override
public byte[] read(int id) {
return access('r', id, null);
}
}

View File

@ -0,0 +1,178 @@
package nankai.oram.client;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import nankai.oram.client.ThinORAMClient;
import nankai.oram.client.common.Position;
import nankai.oram.client.common.SlotObject;
import nankai.oram.client.partition.Partition;
import nankai.oram.common.CommInfo;
import nankai.oram.common.SocketClientUtil;
import nankai.oram.common.CommandType;
import nankai.oram.common.ResponseType;
import nankai.oram.common.SymmetricCypto;
import nankai.oram.common.Util;
import nankai.oram.interfaces.MultiCloudORAM;
import nankai.oram.interfaces.ORAM;
public class SubCloudThinORAM implements MultiCloudORAM {
int cloud;
int n_partitions;
int n_capacity;//the max capacity of a partition -- need the top level
int n_levels;
int n_realBlocks_p;//the real number of blocks in a partition
int counter=0;//for sequneceEvict
ThinORAMPartition[] partitions;
Position pos_map[];//position map
SocketClientUtil[] cli;
private SecretKey userKey; //First onion encryption Layer
byte s_buffer[][];
public SubCloudThinORAM(int npartitions, int realBlocks_p, int levels, int capacity, int c, Position posMap[], SocketClientUtil[] cLi,byte sBuffer[][])
{
n_partitions=npartitions;
n_realBlocks_p=realBlocks_p;
n_levels=levels;
n_capacity=capacity;
cloud=c;
pos_map=posMap;
cli=cLi;
partitions=new ThinORAMPartition[n_partitions];
s_buffer=sBuffer;
for (int i=0;i<n_partitions;i++)
{
partitions[i]=new ThinORAMPartition(realBlocks_p, levels, posMap, cLi[cloud], this,s_buffer);
partitions[i].partition=i;
}
KeyGenerator kg;
try {
kg = KeyGenerator.getInstance("AES");
kg.init(128);
userKey = kg.generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public void encryptData(byte[] data) {
// SymmetricCypto scp=new SymmetricCypto(CommInfo.keySize);
// scp.initEnc(this.userKey, null);
// scp.enc_decData(data, CommInfo.blockSize);
}
public void decryptData(byte[] data) {
// SymmetricCypto scp=new SymmetricCypto(CommInfo.keySize);
// scp.initDec(this.userKey, null);
// scp.enc_decData(data, CommInfo.blockSize);
}
public boolean initORAM()
{
byte cmd[]=new byte[14];
cmd[0]=CommandType.initORAM;
Util.intToByte(cmd, 1, n_partitions);
Util.intToByte(cmd, 5, n_capacity);
Util.intToByte(cmd, 9, n_levels);
cmd[13] = (byte) this.cloud;
cli[cloud].send( cmd, 14, null , 0, null);
return cli[cloud].responseType!=ResponseType.wrong;
}
public boolean openORAM()
{
byte cmd[]=new byte[2];
cmd[0]=CommandType.openDB;
cmd[1]=(byte) this.cloud;
cli[cloud].send( cmd, 2, null , 0, null);
return cli[cloud].responseType!=ResponseType.wrong;
}
@Override
public void writeCloud(Queue slot) {
/*****************
* Random select a partition
*
* Select another cloud to do the shuffle operation
* *********************/
//System.out.println("writeCloud begin");
Random rnd=new Random();
int p = 1;//rnd.nextInt(n_partitions);
if (Util.debug == false){
p = rnd.nextInt(n_partitions);
//not write to the partition with more than the pre-defined real blocks
while ( partitions[p].realDataNumber >= (partitions[p].top_level_len - 2*MCloudCommInfo.evictConditionSize) )
p = rnd.nextInt(n_partitions);
}
//generate a random cloud to do the shuffle operation
int otherCloud = rnd.nextInt(MCloudCommInfo.cloudNumber);
if (MCloudCommInfo.cloudNumber > 1){
while (otherCloud == this.cloud)
otherCloud = rnd.nextInt(MCloudCommInfo.cloudNumber);
}
partitions[p].writePartition(slot, cli[cloud], otherCloud, cli[otherCloud], userKey, cloud);
}
public boolean canWrite()
{
int realnumber = 0;
for (int i=0;i<this.n_partitions; i++)
{
realnumber += this.partitions[i].realDataNumber;
}
if (realnumber> ( (this.n_realBlocks_p * this.n_partitions * 11)/10 ) )
return false;
return true;
}
@Override
public byte[] readCloud(String key) {
return readCloud(Integer.parseInt(key));
}
@Override
public byte[] readCloud(int id) {
/*****************
* If it is a dummy Block, random select a partition to read
* **********************/
byte[] data = null;
int p = 0;
if (id<=CommInfo.dummyID)
{
Random rnd=new Random();
p = rnd.nextInt(n_partitions);
}else{
p = pos_map[id].partition;
}
if (p>=0){
data = partitions[p].readPartition(id, userKey);
return data;
}else{
return new byte[CommInfo.blockSize];
}
}
}

View File

@ -0,0 +1,37 @@
package nankai.oram.client.Test.TestReadWrite;
import nankai.oram.client.ThinORAMClient;
import nankai.oram.client.PartitionClient;
/**
* This is the init oram program
* Each test should after the initilization of ORAM
* @author Dell
*
*/
public class ThinInitOram {
public static void main(String[] args) {
ThinORAMClient oram=new ThinORAMClient();
//initialize the client
oram.init(40000);
oram.openConnection();
long testTime = -1;
long testDoneTime = -1;
testTime = System.currentTimeMillis(); //ms
//initalize the server
oram.initORAM();
testDoneTime = System.currentTimeMillis();
double totalElapsedTime = (testDoneTime - testTime);// / 1000.0;
System.out.println("totalElapsedTime:"+totalElapsedTime);
oram.closeConnection();
}
}

View File

@ -0,0 +1,391 @@
package nankai.oram.client.Test.TestReadWrite;
import java.util.Random;
import nankai.oram.client.ThinORAMClient;
import nankai.oram.client.PartitionClient;
import nankai.oram.client.MCloudCommInfo;
import nankai.oram.common.CommInfo;
import nankai.oram.common.Util;
public class ThinReadAndWrite {
public static int N = 40000;
public static void main(String[] args) {
//testRead();
//testMultiWrite();
//testSameAccess();
testRandomAccess();
}
private static void testMultiWrite() {
//testWrite(5);
testWrite(10);
testWrite(50);
testWrite(100);
testWrite(1000);
}
private static void testRead() {
ThinORAMClient oram=new ThinORAMClient();
//initialize the client
oram.init(N);
oram.openConnection();
//initalize the server
oram.openORAM();
writeTheBlocksToApartition(oram, 1000);
readABlock(oram, 10);
readABlock(oram, 50);
readABlock(oram, 100);
readABlock(oram, 150);
// readABlock(oram, 40);
// readABlock(oram, 50);
// readABlock(oram, 60);
// readABlock(oram, 70);
// readABlock(oram, 80);
// readABlock(oram, 90);
//readABlock(oram, 70);
//readABlock(oram, 100);
//readABlock(oram, 150);
readABlock(oram, 250);
readABlock(oram, 500);
oram.closeConnection();
}
/************************
* After the initOram
* This test can be performed
*
* This test is used to test the execution time of random access, the number of shuffle between clouds and the write operation
**********************/
private static void testRandomAccess() {
ThinORAMClient oram=new ThinORAMClient();
//initialize the client
oram.init(N);
oram.openConnection();
//initalize the server
oram.openORAM();
Util.debug = false;
writeTheBlocks(oram, N);
accessWithRandomStatus(oram, 50);
accessWithRandomStatus(oram, 100);
accessWithRandomStatus(oram, 500); accessWithRandomStatus(oram, 1000);
//
oram.closeConnection();
}
private static void testSameAccess() {
ThinORAMClient oram=new ThinORAMClient();
//initialize the client
oram.init(N);
oram.openConnection();
//initalize the server
oram.openORAM();
Util.debug = false;
writeTheBlocks(oram, 10000);
// //accessWithSameStatus(oram, 5);
// accessWithSameStatus(oram, 10);
// //accessWithSameStatus(oram, 25);
// accessWithSameStatus(oram, 50);
// //accessWithSameStatus(oram, 75);
accessWithSameStatus(oram, 100);
// //accessWithSameStatus(oram, 150);
// accessWithSameStatus(oram, 200);
accessWithSameStatus(oram, 500);
//accessWithSameStatus(oram, 500);
accessWithSameStatus(oram, 1000);
//accessWithSameStatus(oram, 2500);
accessWithSameStatus(oram, 5000);
// accessWithSameStatus(oram, 7500); accessWithSameStatus(oram, 10000);
// writeTheBlocks(oram, 10000);
//
// accessWithSameStatus(oram, 5000);
//
oram.closeConnection();
}
private static void writeTheBlocks(ThinORAMClient oram, int number) {
//write some data
byte[] bData = new byte[CommInfo.blockSize];
for (int id = 0; id < number; id++) {
for (int i = 0; i < CommInfo.blockSize; i++)
bData[i] = (byte) (i % 100);
//Util.intToByte(bData, 0, id);
oram.write(id, bData);
}
bData = oram.read( 2 );
System.out.println(" read 2:"+bData[2]);
}
private static void accessWithRandomStatus(ThinORAMClient oram, int number)
{
oram.clearSlot();
Util.writeNumber = 0;
Util.readbandwidth =0;
Util.cloudcloudbandwidth =0;
Util.readNumber =0;
Util.bandwidth =0;
Util.cloudtocloud=0;
long testTime = -1;
long testDoneTime = -1;
testTime = System.currentTimeMillis(); //ms
byte[] bData = new byte[CommInfo.blockSize];
Random rnd=new Random();
for (int id = 0; id < number ; id++) {
//System.out.println("read "+id);
int _id= rnd.nextInt(N);
oram.read(_id);
_id= rnd.nextInt(N);
oram.read(_id);
_id= rnd.nextInt(N);
//write to the cloud
for (int i = 0; i < CommInfo.blockSize; i++)
bData[i] = (byte) ((_id) % 100);
//System.out.println("write "+ (id+1) );
oram.write(_id, bData);
}
testDoneTime = System.currentTimeMillis();
double totalElapsedTime = (testDoneTime - testTime);// / 1000.0;
System.out.println("number is:"+number);
System.out.println("totalElapsedTime:"+totalElapsedTime);
// System.out.println("-----Shuffle numeber-----!"+Util.writeNumber+" Util.cloudtocloud:"+ Util.cloudtocloud);
// System.out.println("-----ORAM CACHE-----!"+ oram.getCacheSlotSize());
System.out.println("-----writeNumb r ---- "+Util.writeNumber );
System.out.println("-----cloudtocloud ---- "+Util.cloudtocloud );
System.out.println("-----readNumber ---- "+Util.readNumber );
System.out.println("-----bandwidth ---- "+ Util.bandwidth );
System.out.println("-----cloudcloudbandwidth ---- "+Util.cloudcloudbandwidth );
System.out.println("-----readbandwidth ---- "+Util.readbandwidth );
bData = oram.read( 2 );
System.out.println(" read 2:"+bData[2]);
bData = oram.read( 8 );
System.out.println(" read 8:"+bData[2]);
}
private static void accessWithSameStatus(ThinORAMClient oram, int number)
{
oram.clearSlot();
Util.writeNumber = 0;
Util.readbandwidth =0;
Util.cloudcloudbandwidth =0;
Util.readNumber =0;
Util.bandwidth =0;
Util.cloudtocloud=0;
long testTime = -1;
long testDoneTime = -1;
testTime = System.currentTimeMillis(); //ms
byte[] bData = new byte[CommInfo.blockSize];
for (int id = 0; id < number -10 ; id++) {
//System.out.println("read "+id);
oram.read(id);
//write to the cloud
for (int i = 0; i < CommInfo.blockSize; i++)
bData[i] = (byte) ((id+1) % 100);
//System.out.println("write "+ (id+1) );
oram.write(id+1, bData);
}
testDoneTime = System.currentTimeMillis();
double totalElapsedTime = (testDoneTime - testTime);// / 1000.0;
System.out.println("number is:"+number);
System.out.println("totalElapsedTime:"+totalElapsedTime);
// System.out.println("-----Shuffle numeber-----!"+Util.writeNumber+" Util.cloudtocloud:"+ Util.cloudtocloud);
// System.out.println("-----ORAM CACHE-----!"+ oram.getCacheSlotSize());
System.out.println("-----writeNumber ---- "+Util.writeNumber );
System.out.println("-----cloudtocloud ---- "+Util.cloudtocloud );
System.out.println("-----readNumber ---- "+Util.readNumber );
System.out.println("-----bandwidth ---- "+ Util.bandwidth );
System.out.println("-----cloudcloudbandwidth ---- "+Util.cloudcloudbandwidth );
System.out.println("-----readbandwidth ---- "+Util.readbandwidth );
bData = oram.read( 2 );
System.out.println(" read 2:"+bData[2]);
bData = oram.read( 8 );
System.out.println(" read 8:"+bData[2]);
}
private static void writeTheBlocksToApartition(ThinORAMClient oram, int number) {
Util.debug = true; //debug is ture, to write into a fix partiton
Util.writeNumber = 0;
long testTime = -1;
long testDoneTime = -1;
testTime = System.currentTimeMillis(); //ms
byte[] bData = new byte[CommInfo.blockSize];
for (int id = 0; id < number; id++) {
for (int i = 0; i < CommInfo.blockSize; i++)
bData[i] = (byte) (i % 128);
Util.intToByte(bData, 0, id);
oram.write(id, bData);
}
testDoneTime = System.currentTimeMillis();
double totalElapsedTime = (testDoneTime - testTime);// / 1000.0;
System.out.println("totalElapsedTime:"+totalElapsedTime);
System.out.println("-----Shuffle numeber---- -"+Util.writeNumber+" cache size:"+oram.getCacheSlotSize());
byte[] bdata = oram.read(2);
System.out.println(" data :"+bdata[8]);
}
private static void readABlock(ThinORAMClient oram, int number) {
Util.debug = true;
Util.writeNumber = 0;
long testTime = -1;
long testDoneTime = -1;
testTime = System.currentTimeMillis(); //ms
for (int i=0; i<number;i++)
{
oram.read(oram.getIDinDB() );
}
testDoneTime = System.currentTimeMillis();
double totalElapsedTime = (testDoneTime - testTime);// / 1000.0;
System.out.println("number is:"+number);
System.out.println("totalElapsedTime:"+totalElapsedTime);
System.out.println("-----Shuffle numeber---- -"+Util.writeNumber+" cache size:"+oram.getCacheSlotSize());
byte[] bdata = oram.read(2);
System.out.println(" data :"+bdata[8]);
}
private static void access(int number)
{
ThinORAMClient oram=new ThinORAMClient();
//initialize the client
oram.init(N);
oram.openConnection();
//initalize the server
oram.openORAM();
long testTime = -1;
long testDoneTime = -1;
testTime = System.currentTimeMillis(); //ms
byte[] bData = new byte[CommInfo.blockSize];
for (int id = 0; id < number; id++) {
for (int i = 0; i < CommInfo.blockSize; i++)
bData[i] = (byte) (i % 128);
oram.read(id);
oram.write(id+1, bData);
}
testDoneTime = System.currentTimeMillis();
double totalElapsedTime = (testDoneTime - testTime);// / 1000.0;
System.out.println("totalElapsedTime:"+totalElapsedTime);
System.out.println("-----Shuffle numeber---- -"+Util.writeNumber+" cache size:"+oram.getCacheSlotSize());
oram.closeConnection();
}
/**
* Test the special write to a fix partition
*
* if Util.debug set true, fix partition
* For a fix partition, test the number less than 1100
* but if false, random partition
*/
private static void testWrite(int number) {
ThinORAMClient oram=new ThinORAMClient();
//initialize the client
oram.init(N);
oram.openConnection();
//initalize the server
oram.openORAM();
//write some data
Util.debug = true;
Util.writeNumber = 0;
Util.readbandwidth =0;
Util.cloudcloudbandwidth =0;
Util.readNumber =0;
Util.bandwidth =0;
Util.cloudtocloud=0;
byte[] bData = new byte[CommInfo.blockSize];
System.out.println("number is:"+number);
long testTime = -1;
long testTime1 = -1;
long testDoneTime = -1;
long testDoneTime1 = -1;
testTime = System.currentTimeMillis(); //ms
testTime1 = System.nanoTime();//ns
for (int id = 0; id < number; id++) {
for (int i = 0; i < CommInfo.blockSize; i++)
bData[i] = (byte) (id % 100);
oram.write(id, bData);
}
testDoneTime = System.currentTimeMillis();
testDoneTime1 = System.nanoTime();
double totalElapsedTime = (testDoneTime - testTime);// / 1000.0;
double totalElapsedTime1 = (testDoneTime1 - testTime1);// / 1000.0;
System.out.println("totalElapsedTime:"+totalElapsedTime);
// System.out.println("totalElapsedTime222:"+totalElapsedTime1);
System.out.println("-----cloudtocloud ---- "+Util.cloudtocloud );
System.out.println("-----writeNumber ---- "+Util.writeNumber );
System.out.println("-----bandwidth ---- "+Util.bandwidth );
System.out.println("-----cloudcloudbandwidth ---- "+Util.cloudcloudbandwidth );
System.out.println("-----readNumber ---- "+Util.readNumber );
System.out.println("-----readbandwidth ---- "+Util.readbandwidth );
byte[] data = oram.read(8);
System.out.println("-----read 8--------- : " + data[8]);
data = oram.read(9);
System.out.println("-----read 9--------- : " + data[8]);
oram.closeConnection();
}
}

View File

@ -0,0 +1,324 @@
package nankai.oram.client;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import nankai.oram.client.common.Position;
import nankai.oram.client.common.SlotObject;
import nankai.oram.common.CommInfo;
import nankai.oram.common.SocketClientUtil;
import nankai.oram.common.CommandType;
import nankai.oram.common.ResponseType;
import nankai.oram.common.SymmetricCypto;
import nankai.oram.common.Util;
import nankai.oram.interfaces.MultiCloudORAM;
import nankai.oram.interfaces.ORAM;
public class ThinORAMClient implements ORAM{
boolean initFlag;
SubCloudThinORAM[] subORAMs;
int N;
int n_partitions; //All the partitions, for each cloud, it would be divided
int n_partitions_cloud;//the number of partitions for a cloud
int n_capacity;//the max capacity of a partition -- need the top level
int n_levels;
int n_blocks;
int n_realBlocks_p;//the real number of blocks in a partition
int top_level_len;//the number of blocks in the top level
int counter=0;//for sequneceEvict
Position pos_map[];//position map
/*************************************************/
Queue<SlotObject> slots[];
SocketClientUtil[] cli;
byte s_buffer[][];
public ThinORAMClient()
{
initFlag=false;
cli=new SocketClientUtil[MCloudCommInfo.cloudNumber];
}
/**
* initialize the parameters, storage space and so on
* @param nN
*/
public boolean init(int nN)
{
if (initFlag==true)
{
System.out.println("have inited!");
return false;
}
N=nN;
n_partitions = (int) Math.ceil(Math.sqrt(nN));
n_partitions_cloud = (int) Math.ceil(n_partitions/MCloudCommInfo.cloudNumber) ;
n_realBlocks_p = (int) Math.ceil(((double) nN) / n_partitions);
n_blocks = n_realBlocks_p * n_partitions;
n_levels = (int) (Math.log((double) n_realBlocks_p) / Math.log(2.0)) + 1;
n_capacity = (int) Math.ceil(CommInfo.capacity_parameter * n_realBlocks_p);
pos_map=new Position[n_blocks];
for (int i=0;i<n_blocks; i++)
{
pos_map[i]=new Position();
}
slots=new Queue[MCloudCommInfo.cloudNumber];
subORAMs=new SubCloudThinORAM[MCloudCommInfo.cloudNumber];
s_buffer=new byte[MCloudCommInfo.evictConditionSize*3][CommInfo.blockSize];//the real value is evicCondition*2
//randomly generate the keys for each level of each partition
for (int i = 0; i < MCloudCommInfo.cloudNumber; i++)
{
slots[i]=new LinkedList<SlotObject>();
cli[i]=new SocketClientUtil(MCloudCommInfo.ip[i], MCloudCommInfo.port[i]);
subORAMs[i]=new SubCloudThinORAM(n_partitions_cloud, n_realBlocks_p, n_levels, n_capacity, i, pos_map, cli, s_buffer);
}
counter = 0;
initFlag=true;
return true;
}
public void openConnection()
{
for (int i = 0; i < MCloudCommInfo.cloudNumber; i++)
{
cli[i].connect();
}
}
public void closeConnection()
{
for (int i = 0; i < MCloudCommInfo.cloudNumber; i++)
{
cli[i].disConnect();
}
}
public boolean initORAM()
{
boolean bRet = true;
for (int i = 0; i < MCloudCommInfo.cloudNumber; i++)
{
if (subORAMs[i].initORAM()==false)
bRet = false;
}
return bRet;
}
/**
* Notice the ORAM server to open the database
* @return
*/
public boolean openORAM()
{
boolean bRet = true;
for (int i = 0; i < MCloudCommInfo.cloudNumber; i++)
{
if (subORAMs[i].openORAM()==false)
bRet = false;
}
return bRet;
}
byte[] access(char op, int block_id, byte[] value)
{
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// // TODO ×Ô¯Éú³ÉµÄ catch ¿é
// e.printStackTrace();
// }
try{
// System.out.println("access begin");
byte data[] = new byte[CommInfo.blockSize];
int r = Util.rand_int(MCloudCommInfo.cloudNumber);
int c = pos_map[block_id].cloud;
int p = pos_map[block_id].partition;
/****************
* Read data from slots or the server If it is in the slot
* readAndDel from the slot read a dummy block from server Else read
* the real block from the server
* ******************/
if (c >= 0) {
boolean isInSlot = false;
Iterator itr = slots[c].iterator();
SlotObject targetObj = null;
while (itr.hasNext()) {
targetObj = (SlotObject) itr.next();
if (targetObj.id == block_id) {
isInSlot = true;
break;
}
}
if (isInSlot) {
// in the slot
System.arraycopy(targetObj.value, 0, data, 0,
CommInfo.blockSize);
slots[c].remove(targetObj);
// System.out.println("readdummy block_id " + block_id + " c:"
// + c + " p:" + p);
subORAMs[c].readCloud(CommInfo.dummyID);
// System.out.println("readdummy end block_id " + block_id
// + " c:" + c + " p:" + p);
} else {
/**************************
* Here, should send a request to the cloud server to get
* the data
* **************************/
// System.out.println("readCloud block_id " + block_id + " c:"
// + c + " p:" + p);
System.arraycopy(subORAMs[c].readCloud(block_id), 0, data,
0, CommInfo.blockSize);
// System.out.println("read end");
}
}
pos_map[block_id].cloud = r;
pos_map[block_id].partition = -1;
pos_map[block_id].level = -1;
pos_map[block_id].offset = -1;
if (op == 'w') {
System.arraycopy(value, 0, data, 0, CommInfo.blockSize);
}
writeCache(block_id, data, r);
//System.out.println("sequentialEvict begin");
sequentialEvict(CommInfo.v);
//System.out.println("sequentialEvict end");
// System.out.println("access end");
return data;
}catch(Exception ex)
{
ex.printStackTrace();
}
return null;
}
/****
* Write to the cache. With the first layer onion-encryption
* @param block_id
* @param data
* @param r
*/
private void writeCache(int block_id, byte[] data, int c) {
//should be first onion - encryption
SlotObject newObject = new SlotObject(block_id, data);
slots[c].add(newObject);
}
void sequentialEvict(int vNumber)
{
for (int i = 0; i < vNumber; i++) {
counter = (counter + 1) % MCloudCommInfo.cloudNumber;
evict(counter);
}
}
void randomEvict(int vNumber)
{
Random rnd=new Random();
for (int i = 0; i < vNumber; i++) {
int r = rnd.nextInt(MCloudCommInfo.cloudNumber);
evict(r);
}
}
void evict(int c) {
if (slots[c].size() >= MCloudCommInfo.evictConditionSize)
{
if (subORAMs[c].canWrite())
subORAMs[c].writeCloud(slots[c]);
}
}
public int getCacheSlotSize()
{
int ret = 0;
for (int i=0; i<slots.length; i++)
{
ret += slots[i].size();
}
return ret;
}
public void clearSlot()
{
for (int i=0; i<slots.length; i++)
{
/**************
* Here, do not clear directly
* Just remove from the slot, but the data should always stored in the database
* So, we should update the position map
*
*/
if (slots[i].size()>0)
subORAMs[i].writeCloud(slots[i]);
slots[i].clear();
}
}
public int getIDinDB()
{
for (int i=0;i<n_blocks; i++)
{
if (pos_map[i].partition != -1 )
return i;
}
return -1;
}
@Override
public void write(String idStr, byte[] value) {
access('w', Integer.parseInt(idStr), value);
}
@Override
public byte[] read(String idStr) {
return access('r', Integer.parseInt(idStr), null);
}
@Override
public void write(int id, byte[] value) {
access('w', id, value);
}
@Override
public byte[] read(int id) {
return access('r', id, null);
}
}

View File

@ -0,0 +1,716 @@
package nankai.oram.client;
/*************
* The data in a level of a partition is encrypted by the key for level
*
* Each data is included by BID+DATA
* BID = REALBLOCK? BLOCKID : - OFFSET
*/
import java.security.NoSuchAlgorithmException;
import java.util.Queue;
import java.util.Random;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import nankai.oram.client.common.Position;
import nankai.oram.client.common.SlotObject;
import nankai.oram.common.CommInfo;
import nankai.oram.common.SocketClientUtil;
import nankai.oram.common.CommandType;
import nankai.oram.common.SymmetricCypto;
import nankai.oram.common.Util;
public class ThinORAMPartition{
public static int part=0;
int n_levels;
int n_realBlocks_p;//the real number of blocks in a partition
int n_capacity;//the max capacity of a partition -- need the top level
int top_level_len;//the number of blocks in the top level
int partition = 0;
int blockIDs[];//all the blockIDs. When re-shuffle, the dummyIDs will be re-filled
int dummyNumbers[];//the dummy block numbers; When re-shuffle, the dummyIDs will be filled
int nextDummy[];//the dummy block counter;
boolean filled[];//filled level flag
boolean readFlag[];//read flag
SecretKey keys[];//level key for each partition
byte s_buffer[][];
Position pos_map[];//position map
SocketClientUtil cli;
SubCloudThinORAM subOram;
KeyGenerator kg;
public int realDataNumber = 0;
public ThinORAMPartition(int realBlocks_p, int levels, Position posMap[], SocketClientUtil cLi, SubCloudThinORAM soram,byte sBuffer[][])
{
subOram=soram;
pos_map=posMap;
cli=cLi;
s_buffer = sBuffer;
n_realBlocks_p = realBlocks_p;
n_levels = levels;
n_capacity = (int) Math.ceil(CommInfo.capacity_parameter * n_realBlocks_p);
top_level_len = n_capacity - (1 << n_levels) + 2;
readFlag=new boolean[n_capacity];
keys=new SecretKey[n_levels];
blockIDs=new int[n_capacity];
nextDummy=new int[n_levels];
dummyNumbers=new int[n_levels];
filled=new boolean[n_levels];
for (int i=0;i<n_levels;i++)
{
dummyNumbers[i]=0;
nextDummy[i]=0;
filled[i]=false;
}
for (int i=0;i<n_capacity;i++)
{
readFlag[i]=true;
blockIDs[i]=CommInfo.dummyID;
}
initKeys();
}
private void initKeys()
{
try {
kg = KeyGenerator.getInstance("AES");
kg.init(128);
for (int j = 0; j < n_levels; j++)
keys[j] = kg.generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public byte[] getKey(int pos)
{
return keys[pos].getEncoded();
}
public byte[] readPartition(int block_id, SecretKey userKey) {
/*******************************
* Gnerate the OFFSETs
*
* Length + ID1 ...... + ID2......
* *****************************/
byte[] data = new byte[CommInfo.blockSize];
byte[] xorZero = new byte[CommInfo.blockSize];
byte[] ids = new byte[ n_levels * 4 ];
int[] levels = new int[n_levels];
int level = -1;
if (block_id!=CommInfo.dummyID)
level = pos_map[block_id].level;
int length = 0;
int realDataID = -1;
for (int i=MCloudCommInfo.severBeginLevel;i<n_levels;i++)
{
if (filled[i])
{
int _id = (1 << (i + 1)) - 2;
if (level==i && block_id!=CommInfo.dummyID)
{
_id += pos_map[block_id].offset;
realDataID = _id;
}else{
// not in this level, to read a dummy block, get the dummy offset
int dID=nextDummy(0, i);
if (dID == -1) // There is no dummy block can be read
continue;
_id += dID;//nextDummy(i);
}
readFlag[_id]=true;
Util.intToByte(ids, length*4, _id);
levels[length] = i;
length ++;
}
}
if (length==0)
return null;
/*************************
* Send to the cloud
*
* Command: readCloud
* content: partition + length
* offsets
* **************************/
//System.out.println("read partition length:"+length);
byte[] cmd=new byte[9];
cmd[0]=CommandType.readCloud;
Util.intToByte(cmd, 1, partition);
Util.intToByte(cmd, 5, length);
cli.send(cmd, 9, ids, length*4, data);
Util.readbandwidth += 9+length*4+CommInfo.blockSize; //
Util.readNumber ++ ; //
/*************************************
* Decrypt Data based on XOR technique
*
* Enc-level-key and Enc-enc-key
* **********************************/
if (block_id != CommInfo.dummyID) {
SymmetricCypto scp = new SymmetricCypto(CommInfo.keySize);
for (int i = 0; i < length; i++) {
// XOR the data 000000
int _id = Util.byteToInt(ids, i * 4, 4);
if (_id >= 0)
continue;
byte[] iv = Util.generateIV(_id);
for (int j = 0; j < CommInfo.blockSize; j++)
xorZero[j] = 0;
// // first onion encrypt userkey
// scp.initEnc(userKey, iv);
// scp.enc_decData(xorZero, CommInfo.blockSize);
// // second onion encrypt level key
// scp.initEnc(keys[levels[i]], null);
// scp.enc_decData(xorZero, CommInfo.blockSize);
// XOR
for (int j = 0; j < CommInfo.blockSize; j++)
data[j] ^= xorZero[j];
}
// // First onion decrypt by level key
// scp.initDec(keys[level], null);
// scp.enc_decData(data, CommInfo.blockSize);
// Second, onion decrypt by the user key
subOram.decryptData(data);
}
//update all the real numbers
realDataNumber=0;
int levelBegin = (1 << (MCloudCommInfo.severBeginLevel + 1)) - 2;
for (int i=levelBegin; i<this.n_capacity; i++)
{
if (blockIDs[i]>0 && readFlag[i]==false)
realDataNumber++;
}
return data ;
}
public byte[] generateXORBlock(int p, int _id, SecretKey userKey)
{
//Encrypt the 0x00 default value by the userkey
byte[] data=new byte[CommInfo.blockSize];
for (int i=0;i<CommInfo.blockSize;i++)
{
data[i] = 0;
}
/****************************
* The first 4 bytes is the dummmyID and the random value, to make sure it is less than 0
*
* But now, to simplify the implementation, we ignore the random value for the same 0000000
* ******************************/
int dummyID = CommInfo.dummyID - Util.rand_int(n_capacity);
blockIDs[_id]=dummyID;
// byte[] iv = Util.generateIV(dummyID);
//encrypt
// SymmetricCypto scp=new SymmetricCypto(CommInfo.keySize);
// scp.initEnc(userKey, iv);
// scp.enc_decData(data, CommInfo.blockSize);
return data;
}
public void writePartition(Queue slot, SocketClientUtil cli, int otherCloud, SocketClientUtil cliOtherCloud, SecretKey userKey, int cloud)
{
//System.out.println("write begin!!");
int evictSize = MCloudCommInfo.evictConditionSize;
if (slot.size()<evictSize) {
evictSize = slot.size();
}
int unfilledLevel = -1;
for (int i = MCloudCommInfo.severBeginLevel; i < this.n_levels; i++) {
if (!filled[i]) {
unfilledLevel = i ;
break;
}
}
if (unfilledLevel == MCloudCommInfo.severBeginLevel){
//CASE 2
writeCase1(slot, userKey, cloud, evictSize, unfilledLevel);
}else{
try {
writeCase2(slot, cli, otherCloud, cliOtherCloud, userKey,
cloud, evictSize, unfilledLevel);
} catch (Exception e) {
System.out.println("error!!");
}
}
//System.out.println("write ok!!");
}
private void writeCase2(Queue slot, SocketClientUtil cli, int otherCloud,
SocketClientUtil cliOtherCloud, SecretKey userKey, int cloud,
int evictSize, int unfilledLevel) {
// System.out.println(" writeCase2 ");
byte[] bSessionID = Util.generateSessionData(8);
int unreadRealDataNumber = 0;
/***************************************************
* COMPUTE the range of the levels
* ********************************************/
int begin = (1 << (MCloudCommInfo.severBeginLevel + 1)) - 2;
int end = (1 << (unfilledLevel + 1)) - 2;
boolean bSpecialCase = false;
if (unfilledLevel == -1){
bSpecialCase = true;
//All Filled levels, special treatment
unfilledLevel = n_levels - 1;
end = this.n_capacity;
}
for (int i=begin; i<end; i++)
if (readFlag[i] == false)
{
if (blockIDs[i]>=0)
unreadRealDataNumber++;
}
/**********************************************
* GEI the maxinum number of blocks in this level
* *****************************************/
int filledLevelLength = 0;
if (unfilledLevel != n_levels - 1) {
filledLevelLength = 2 *(1 << unfilledLevel);
} else filledLevelLength = top_level_len;
int dataNumber=unreadRealDataNumber;
byte[] ids=new byte[dataNumber*4];//id in partition , for reading
int[] intIDs=new int[dataNumber];//id
byte[] levels=new byte[dataNumber];//store each id's level, for onion decryption
int pos = 0;
for (int level = MCloudCommInfo.severBeginLevel; level < this.n_levels; level++) {
if (filled[level]) {
begin = (1 << (level + 1)) - 2;
int datalen = 0;
if (level != n_levels - 1) {
datalen = 2 * (1 << level);
} else
datalen = top_level_len;
for (int _id = begin; _id < begin + datalen; _id++) {
if (this.readFlag[_id] == false && blockIDs[_id]>=0 ) {
Util.intToByte(ids, pos * 4, _id);
levels[pos] = (byte) level;
intIDs[pos++] = blockIDs[_id];
}
}
} else {
break;
}
}
if (pos!=unreadRealDataNumber)
System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
/****************************************
* (1)Notice Shuffle , Send All the data, onionkeys in slots to the otherCloud
*
* CommandType: noticeShuffle
* Content: session ID | unfilled levels number |
* onion keys and slots data
*
* (2)Notice this cloud to send the data to the otherCloud for shuffling
* CommandType: writeCloud
* content: session ID | unfilled - partition | other cloud for shuffling | length of ids
*
*
* (3)Send back the shuffled Data -- cloud to cloud, but not the client
* CommandType: backData
* ************************************/
//System.out.println("write partition filledLevelLength:"+filledLevelLength+" dataNumber:"+dataNumber+" unreadRealDataNumber:"+unreadRealDataNumber+" bSessionID:"+bSessionID[0]);
int rndLength = filledLevelLength - dataNumber - 2*evictSize;
if (rndLength<0){
//System.out.println(" rndLength "+ rndLength +" filledLevelLength "+filledLevelLength+" dataNumber "+dataNumber+" evictSize "+evictSize );
return;
}
/*********************** First command: noticeShuffle ***************************/
byte[] cmd=new byte[29];
cmd[0]=CommandType.noticeShuffle;
System.arraycopy(bSessionID, 0, cmd, 1, 8);
Util.intToByte(cmd, 9, partition);
Util.intToByte(cmd, 13, unfilledLevel);
Util.intToByte(cmd, 17, filledLevelLength);
Util.intToByte(cmd, 21, dataNumber);
Util.intToByte(cmd, 25, evictSize);
cliOtherCloud.send(cmd, 29);
//send the ids to notice how to onion decryption and encryption
cliOtherCloud.send( levels, dataNumber );
// if (dataNumber*4>512)
// System.out.println("----512-----");
/****************************************************
* Send the data blocks to the shuffled cloud
* We sends them directly here, in fact, we can permute them before sending them
*********************************************/
//send the slots data, the number is filled
for (int _id=0;_id<evictSize;_id++)
{
SlotObject targetObj = (SlotObject)slot.poll();
blockIDs[_id]=targetObj.id;
subOram.encryptData(targetObj.value);
cliOtherCloud.send( targetObj.value, CommInfo.blockSize );
//System.out.println(" _id:"+_id+" value:"+targetObj.value[0]);
}
for (int _id = evictSize; _id < 2*evictSize; _id++) {
byte[] bDummyData = generateXORBlock(partition, _id, userKey);
cliOtherCloud.send( bDummyData, CommInfo.blockSize );
}
/****************************
* generate random value for dummy blocks
* **************************************/
//generate random value
Random rnd=new Random();
int[] rnds=new int[rndLength];
byte[] rndBytes=new byte[rndLength*4];
for (int i=0; i<rndLength; i++)
{
rnds[i]= - rnd.nextInt( this.n_capacity ); //
blockIDs[ i+2*evictSize ] = rnds[i];
Util.intToByte(rndBytes, i*4, rnds[i]);
}
for (int _id=0;_id<dataNumber;_id++)
{
blockIDs[_id+2*evictSize+rndLength]=intIDs[_id];
}
cliOtherCloud.send(rndBytes, rndLength*4);
//send the onion keys
/********************************************************************
* Notice that: must send the unfilledlevel key to the server,
* because the special case, the unfilled level is the top level, the onion decryption will be used
****************************************************************/
Util.bandwidth += rndLength*4 + MCloudCommInfo.evictConditionSize*CommInfo.blockSize + (unfilledLevel-MCloudCommInfo.severBeginLevel+1)*CommInfo.keySize;
Util.writeNumber ++;
Util.cloudtocloud++;
Util.cloudcloudbandwidth += (filledLevelLength) * CommInfo.blockSize + dataNumber*CommInfo.blockSize;
for (int i=MCloudCommInfo.severBeginLevel; i<=unfilledLevel; i++)
{
byte[] bkeyData = getKey(i);
cliOtherCloud.send( bkeyData, CommInfo.keySize );
}
//send the shuffle key and wait for the response
/******************************
* Here, the client can receive the shffule key
* But, in our implmenetation, we generate the key in the client
* it is also OK
* ************************************
*
* The client must wait for the response of the cloud
* and cloud should finish the shuffle operation
*
* Notice, we use the onion key as the shuffle key, it is also OK
* *********************************/
//reset some status in the unfilled level
keys[unfilledLevel]=kg.generateKey();
nextDummy[unfilledLevel]=0;
filled[unfilledLevel]=true;
byte[] shufflekey = getKey(unfilledLevel);//Util.generateDummyData(MCloudCommInfo.keySize);
cliOtherCloud.sendAndReceive(shufflekey, 16);
//System.out.println("noticeshufule ok cloud: "+cloud+" session "+ bSessionID[0]+" dataNumber "+dataNumber+" filledLevelLength:"+filledLevelLength);
/*********************** Second command: noticeWriteCloud ***************************/
/////////////////////////First, command and keys
byte[] cmd1=new byte[22];
cmd1[0]=CommandType.noticeWriteCloud;
System.arraycopy(bSessionID, 0, cmd1, 1, 8);
Util.intToByte(cmd1, 9, partition);
Util.intToByte(cmd1, 13, unfilledLevel);
cmd1[17] = (byte) otherCloud;
Util.intToByte(cmd1, 18, dataNumber);
cli.send(cmd1, 22, ids, dataNumber*4, null);
/***************************
* Final, reset the status in the client
* (1) shuffle the blockIDs
* (2) reset the filled and read flag
* *******************************/
psuedo_random_permute( shufflekey, filledLevelLength);
for (int i=MCloudCommInfo.severBeginLevel;i<unfilledLevel; i++)
{
nextDummy[i]=0;
filled[i]=false;
}
//update the status in the un-filled level
/******************
* Save to a temp int array
* For the worst case
* ******************/
int[] bIDS = new int[filledLevelLength];
for (int i=0; i<filledLevelLength; i++)
{
bIDS[i]=blockIDs[i];
}
int levelBegin = (1 << (unfilledLevel + 1)) - 2;
for (int i=0;i<filledLevelLength;i++)
{
int bID=bIDS[i];
int _id = i+levelBegin;
blockIDs[_id] = bID;
readFlag[_id]=false;
if (bID>=0)
{
//update the position map
pos_map[bID].cloud = cloud;
pos_map[bID].partition = this.partition;
pos_map[bID].level = unfilledLevel;
pos_map[bID].offset = i;
}
}
/*for (int i=filledLevelLength-1;i>=0;i--)
{
int bID=blockIDs[i];
int _id = i+levelBegin;
if (bID>=0)
{
//update the position map
pos_map[bID].cloud = cloud;
pos_map[bID].partition = this.partition;
pos_map[bID].level = unfilledLevel;
pos_map[bID].offset = i;
}
blockIDs[_id] = bID;
readFlag[_id]=false;
}*/
//update the status of consecutive levels
for (int i=0; i<levelBegin; i++)
{
blockIDs[i] = CommInfo.dummyID;
readFlag[i]=true;
}
//update all the real numbers
realDataNumber=0;
for (int i=levelBegin; i<this.n_capacity; i++)
{
if (blockIDs[i]>0 && readFlag[i]==false)
realDataNumber++;
}
if (realDataNumber > this.n_realBlocks_p)
realDataNumber=realDataNumber;
}
private void writeCase1(Queue slot, SecretKey userKey, int cloud,
int evictSize, int unfilledLevel) {
int filledLevelLength = 2 * (1 << unfilledLevel);
// System.out.println(" writeCase1 ");
if (evictSize > filledLevelLength )
System.out.println(" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ");
// shuffle in client and then write to cloud rightly
for (int _id = 0; _id < evictSize; _id++) {
SlotObject targetObj = (SlotObject) slot.poll();
blockIDs[_id] = targetObj.id;
subOram.encryptData(targetObj.value);
System.arraycopy(targetObj.value, 0, s_buffer[_id], 0,
CommInfo.blockSize);
// System.out.println(" _id:"+_id+" value:"+targetObj.value[0]);
}
for (int _id = evictSize; _id < filledLevelLength; _id++) {
byte[] bDummyData = generateXORBlock(partition, _id, userKey);
System.arraycopy(bDummyData, 0, s_buffer[_id], 0,
CommInfo.blockSize);
// System.out.println(" _id:"+_id+" value:"+bDummyData[0]);
}
// shuffle first and then send them to the clouds
psuedo_random_permute(s_buffer, filledLevelLength);
keys[unfilledLevel] = kg.generateKey();
nextDummy[unfilledLevel] = 0;
filled[unfilledLevel] = true;
// onion encrypt them using the level key
int[] bIDS = new int[filledLevelLength];
for (int i=0; i<filledLevelLength; i++)
{
bIDS[i]=blockIDs[i];
}
// reset the status
int levelBegin = (1 << (unfilledLevel + 1)) - 2;
for (int i = 0; i< filledLevelLength; i++ ) {
int bID = bIDS[i];
int _id = i + levelBegin;
if (bID >= 0) {
// update the position map
pos_map[bID].cloud = cloud;
pos_map[bID].partition = this.partition;
pos_map[bID].level = unfilledLevel;
pos_map[bID].offset = i;
}
blockIDs[_id] = bID;
readFlag[_id] = false;
}
// update the status of consecutive levels
for (int i = 0; i < levelBegin; i++) {
blockIDs[i] = CommInfo.dummyID;
readFlag[i] = true;
}
Util.writeNumber ++;
Util.bandwidth += filledLevelLength*CommInfo.blockSize ;
//write to cloud
byte[] cmd1=new byte[13];
cmd1[0]=CommandType.directWriteCloud;
Util.intToByte(cmd1, 1, partition);
Util.intToByte(cmd1, 5, unfilledLevel);
Util.intToByte(cmd1, 9, filledLevelLength);
cli.send(cmd1, 13);
for (int _id = 0; _id < filledLevelLength; _id++) {
cli.send( s_buffer[_id], CommInfo.blockSize );
}
//send over and receive
cmd1[0]=0;
cmd1[1]=0;
cli.sendAndReceive(cmd1, 2);
//update all the real numbers
realDataNumber=0;
for (int i=levelBegin; i<this.n_capacity; i++)
{
if (blockIDs[i]>0 && readFlag[i]==false)
realDataNumber++;
}
}
private void psuedo_random_permute(byte[][] sBuffer, int len) {
Random rnd=new Random();
int id =0;
byte[] bData=new byte[CommInfo.blockSize];
for (int i = len- 1; i > 0; --i) {
int j = rnd.nextInt(i);
System.arraycopy(sBuffer[i], 0, bData, 0, CommInfo.blockSize);
id=blockIDs[i];
System.arraycopy(sBuffer[j], 0, sBuffer[i], 0, CommInfo.blockSize);
blockIDs[i] =blockIDs[j];
System.arraycopy(bData, 0, sBuffer[j], 0, CommInfo.blockSize);
blockIDs[j]=id;
}
}
/***
* Permute the blockIDs in the client based on the key
* @param shufflekey
*/
private void psuedo_random_permute(byte[] shufflekey, int filledLevelLength) {
Util.writeNumber = Util.writeNumber+1;
// for (int i = 0; i < filledLevelLength; i++) {
// System.out.println("i: "+i+" "+blockIDs[i]);
// }
SecretKey sfk = new SecretKeySpec(shufflekey, "AES");
for (int i = 0; i < filledLevelLength; i++) {
int j = Util.fpeForPermution(i, sfk, filledLevelLength);
int t = blockIDs[i];
blockIDs[i] = blockIDs[j];
blockIDs[j] = t;
// System.out.println("permute: "+i+" "+j);
}
}
public int nextDummy(int type, int level)
{
int begin = (1 << (level + 1)) - 2;
int end=0;
if (level != n_levels - 1) {
end = 2 *(1 << level);
} else end = top_level_len;
//compute the position in the position map
for (int i=nextDummy[level];i<end;i++)
if (blockIDs[begin+i]<= CommInfo.dummyID)
{
nextDummy[level]=i+1;
return i;
}
//Notice that, there is no dummy blocks
// System.out.println("No dummy !!!!!! return 0!!!!!p:"+this.partition+" !!!type:"+type+" level:"+level+" nextDummy[level]"+nextDummy[level]);
return -1;
}
}

View File

@ -0,0 +1,24 @@
package nankai.oram.client.common;
public class Position{
/**********************
* BLockID is maintained by the client
* But id is stored in the server, the record ID of the data u with ID of BLockID
*
* The same sequence in the client is denoted as the BLockIDs
* but the real sequence in the server will be the different ids
* ********************/
public int partition;
public int level;
public int offset;
public int rndNumber;//random value
public int cloud;//random value
public Position()
{
partition=-1;
level=-1;
offset=-1;
rndNumber=0;
cloud=-1;
}
}

View File

@ -0,0 +1,19 @@
package nankai.oram.client.common;
import nankai.oram.common.CommInfo;
public class SlotObject{
public int id;
public byte[] value;
public SlotObject()
{
id=0;
value=new byte[CommInfo.blockSize];
}
public SlotObject(int _id, byte[] _value)
{
id=_id;
value=new byte[CommInfo.blockSize];
System.arraycopy(_value, 0, value, 0, CommInfo.blockSize);
}
}

View File

@ -0,0 +1,349 @@
package nankai.oram.client.partition;
/*************
* The data in a level of a partition is encrypted by the key for level
*
* Each data is included by BID+DATA
* BID = REALBLOCK? BLOCKID : - OFFSET
*/
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import nankai.oram.client.common.Position;
import nankai.oram.common.CommInfo;
import nankai.oram.common.SocketClientUtil;
import nankai.oram.common.CommandType;
import nankai.oram.common.SymmetricCypto;
import nankai.oram.common.Util;
public class Partition{
public static int part=0;
int n_levels;
int n_blocks;
int n_realBlocks_p;//the real number of blocks in a partition
int n_capacity;//the max capacity of a partition -- need the top level
int top_level_len;//the number of blocks in the top level
int p = 0;
int blockIDs[];//all the blockIDs. When re-shuffle, the dummyIDs will be re-filled
int dummyNumbers[];//the dummy block numbers; When re-shuffle, the dummyIDs will be filled
int nextDummy[];//the dummy block counter;
boolean filled[];//filled level flag
boolean flag[];//read flag
SecretKey keys[];//level key for each partition
byte s_buffer[][];//shuffule buffer - a large memory
Position pos_map[];//position map
SocketClientUtil cli;
byte cmdData[] = new byte[13];
public int realDataNumber = 0;
KeyGenerator kg;
public Partition(int nN, int n_partitions, Position posMap[], byte sBuffer[][], SocketClientUtil cLi)
{
s_buffer=sBuffer;
pos_map=posMap;
cli=cLi;
n_realBlocks_p = (int) Math.ceil(((double) nN) / n_partitions);
n_blocks = n_realBlocks_p * n_partitions;
n_levels = (int) (Math.log((double) n_realBlocks_p) / Math.log(2.0)) + 1;
n_capacity = (int) Math.ceil(CommInfo.capacity_parameter * n_realBlocks_p);
top_level_len = n_capacity - (1 << n_levels) + 2;
p = part++;
flag=new boolean[n_capacity];
keys=new SecretKey[n_levels];
blockIDs=new int[n_capacity];
nextDummy=new int[n_levels];
dummyNumbers=new int[n_levels];
filled=new boolean[n_levels];
for (int i=0;i<n_levels;i++)
{
dummyNumbers[i]=0;
nextDummy[i]=0;
filled[i]=false;
}
for (int i=0;i<n_capacity;i++)
{
flag[i]=true;
blockIDs[i]=CommInfo.dummyID;
}
initKeys();
}
private void initKeys()
{
try {
kg = KeyGenerator.getInstance("AES");
kg.init(128);
for (int j = 0; j < n_levels; j++)
keys[j] = kg.generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public byte[] readPartition(int block_id) {
/*******************************
* From Each filled level, to read a block
* if it is in this level, read the only one real block
* else, read a dummy block *
* *****************************/
int readNumber = 0;
byte[] data = new byte[CommInfo.blockSize];
int level=-1;
if (block_id!=CommInfo.dummyID)
level = pos_map[block_id].level;
for (int i=0;i<n_levels;i++)
{
if (filled[i])
{
if (level==i && block_id!=CommInfo.dummyID)
{
readNumber++;
// in this level, to read a real block. get the offset
readBlock(p, i, pos_map[block_id].offset, data);
/*****************************
* Decrypt the data
* *************************/
SymmetricCypto scp=new SymmetricCypto(CommInfo.keySize);
scp.initDec(keys[i], null);
scp.enc_decData(data, CommInfo.blockSize);
}else{
readNumber++;
// not in this level, to read a dummy block, get the dummy offset
int dID=nextDummy(i);
if (dID == -1) // There is no dummy block can be read
continue;
readBlock(p, i, dID, null);
}
}
}
Util.readNumber ++;
Util.readbandwidth += CommInfo.blockSize + readNumber*4;
Util.cloudcloudbandwidth += readNumber * CommInfo.blockSize *1.2 + readNumber*4;
Util.cloudtocloud ++;
return data ;
}
public void writePartition(int block_id, byte[] bData)
{
int level=-1;
for (int i=0;i<this.n_levels;i++)
{
if (!filled[i])
{
level=i-1;
break;
}
}
/***************************************
* fetch all the unread blocks from the server
* ***************************************/
int realNumber=0;
if (level != -1) {
for (int i = 0; i <= level; i++) {
realNumber = fetchLevel(i, realNumber);
filled[i]=false;
}
Util.cloudtocloud = Util.cloudtocloud+1;
}
/******************************************
* If block_id is dummy block
* It will not be add into the shffule buffer
* ***************************************/
if (block_id!=CommInfo.dummyID)
System.arraycopy(bData, 0, s_buffer[realNumber++], 0, CommInfo.blockSize);
/***********************
* Treate the special level, i.e., the top level
* ************************/
if (level != n_levels - 1) ++level;
else{
System.out.println(" Filled!!!¡¡¡¡¡¡¡¡");
}
/******************************************
* Generate the dummy blocks and add them into the buffer
* ***************************************/
int begin = (1 << (level + 1)) - 2;
int sbuffer_len=0;
if (level != n_levels - 1) {
sbuffer_len = 2 *(1 << level);
} else sbuffer_len = top_level_len;
for (int i=realNumber;i<sbuffer_len;i++)
{
//generate the data
Util.intToByte(s_buffer[i], 0, CommInfo.dummyID);
byte[] bDummy=Util.generateDummyData(CommInfo.blockSize-4);
System.arraycopy(bDummy, 0, s_buffer[i], 4, CommInfo.blockSize-4);
}
/******************************************
* Shuffle the plian data in the shufflebuffer
* Then encrypt Them using the level key
* ***************************************/
psuedo_random_permute(s_buffer, sbuffer_len);
//Reset the key and dummyID
keys[level]=kg.generateKey();
nextDummy[level]=0;
/******************************************
* re-encrypt all the data
* ***************************************/
int bID=0;
SymmetricCypto scp=new SymmetricCypto(CommInfo.keySize);
scp.initEnc(keys[level], null);
filled[level]=true;
for (int i=0;i<sbuffer_len;i++)
{
//set the flag and blockIDs
bID=Util.byteToInt(s_buffer[i], 0, 4);
int _id = begin+i;
if (bID==CommInfo.dummyID)
bID=CommInfo.dummyID-i;
else{
//update position map
pos_map[bID].partition=p;
pos_map[bID].level=level;
pos_map[bID].offset=i;
}
blockIDs[_id]=bID;
Util.intToByte(s_buffer[i], 0, bID);
flag[_id]=false;
//encrypt
scp.enc_decData(s_buffer[i], CommInfo.blockSize);
//partition + ID (_id)
cmdData[0]=CommandType.writeBlock;
Util.intToByte(cmdData, 1, p);
Util.intToByte(cmdData, 5, _id);
Util.intToByte(cmdData, 9, CommInfo.blockSize);
//store into the database
cli.send(cmdData, 13, s_buffer[i], CommInfo.blockSize, null);
}
for (int i=0;i<begin;i++)
{
blockIDs[i]=CommInfo.dummyID;
flag[i]=true;
}
realDataNumber=0;
for (int i=begin;i<this.n_capacity;i++)
{
if (blockIDs[i]>=0)
realDataNumber++;
}
Util.cloudcloudbandwidth += sbuffer_len*CommInfo.blockSize;
Util.writeNumber ++;
Util.bandwidth += CommInfo.blockSize + sbuffer_len*4;
Util.cloudtocloud ++;
}
private void psuedo_random_permute(byte[][] sBuffer, int len) {
Util.writeNumber = Util.writeNumber+1;
Random rnd=new Random();
byte[] bData=new byte[CommInfo.blockSize];
for (int i = len- 1; i > 0; --i) {
int j = rnd.nextInt(i);
/* bData=sBuffer[i].clone();
sBuffer[i] = sBuffer[j].clone();
sBuffer[j] = bData.clone();*/
System.arraycopy(sBuffer[i], 0, bData, 0, CommInfo.blockSize);
System.arraycopy(sBuffer[j], 0, sBuffer[i], 0, CommInfo.blockSize);
System.arraycopy(bData, 0, sBuffer[j], 0, CommInfo.blockSize);
}
}
private int fetchLevel(int level, int length) {
/******************************
* Compute the position of begin and end
* **********************************/
SymmetricCypto scp=new SymmetricCypto(CommInfo.keySize);
scp.initDec(keys[level], null);
int begin = (1 << (level + 1)) - 2;
int level_len=0;
if (level != n_levels - 1) {
level_len = 2 *(1 << level);
} else level_len = top_level_len;
int _id=0;
for (int j=0; j<level_len; j++)
{
_id=begin+j;
if (!flag[_id] && blockIDs[_id]>=0)
{
readBlock(p, level, j, s_buffer[length]);
/**************************
* Decrypt it and judge whether it is a dummy block
* *************************/
scp.enc_decData(s_buffer[length], CommInfo.blockSize);
length++;
}
//reset the flag
flag[_id]=true;
}
return length;
}
private void readBlock(int p, int level, int offset, byte[] recData) {
int begin = (1 << (level + 1)) - 2;
int _id = begin+offset;
cmdData[0]=CommandType.readBlock;
Util.intToByte(cmdData, 1, p);
//reset the read flag as true
flag[_id]=true;
Util.intToByte(cmdData, 5, _id);
cli.send(cmdData, 9, null, 0, recData);
}
public int nextDummy(int level)
{
int begin = (1 << (level + 1)) - 2;
int end=0;
if (level != n_levels - 1) {
end = 2 *(1 << level);
} else end = top_level_len;
//compute the position in the position map
for (int i=nextDummy[level];i<end;i++)
if (blockIDs[begin+i] <= CommInfo.dummyID)
{
nextDummy[level]=i+1;
return i;
}
//Notice that, there is no dummy blocks
//System.out.println("No dummy !!!!!! return 0!!!!!!!!");
return -1;
}
}

View File

@ -0,0 +1,10 @@
package nankai.oram.common;
public interface CommInfo {
public static int dummyID=-1;
public static int keySize=16;//the length of a key byte
public static int v=2;//the rate of evict operation
public static int blockSize=128;//the length of a block byte
public static double capacity_parameter=4.6;//4.6*N, the parameter of max capacity of partition
}

View File

@ -0,0 +1,23 @@
package nankai.oram.common;
public interface CommandType {
public static byte initORAM=1;
public static byte readBlock=2;
public static byte writeBlock=3;
public static byte readCloud=4;
public static byte noticeWriteCloud=5; //client notices the cloud to be ready for the write operation
public static byte noticeShuffle=6; //client notices the cloud to be read for the shuffle operation
public static byte shuffleData=7; //cloud sends the shuffle data to the other cloud
public static byte backData=8;//the other cloud sends back the shuffled data
public static byte directWriteCloud=9; //client write to cloud the unfilled level directly
public static byte testTime=112;//the other cloud sends back the shuffled data
public static byte closeThread=111;
public static byte openDB=113;//the other cloud sends back the shuffled data
}

View File

@ -0,0 +1,66 @@
package nankai.oram.common;
import com.mongodb.*;
import com.mongodb.client.*;
public class MongDBUtil {
MongoClient conn;
MongoDatabase db;
public void connect(String ip, int port, String dbName)
{
conn = new MongoClient(ip, port);
db = conn.getDatabase(dbName);
}
public void connect(String ip, int port )
{
conn = new MongoClient(ip, port);
}
public boolean createDB(String dbName)
{
if (conn==null)
{
System.out.println("no connection");
return false;
}
System.out.println("createDB "+dbName);
//first, drop it if exists
conn.dropDatabase(dbName);
//then, create
db = conn.getDatabase(dbName);
return true;
}
public boolean openDB(String dbName)
{
if (conn==null)
{
System.out.println("no connection");
return false;
}
System.out.println("openDB "+dbName);
db = conn.getDatabase(dbName);
return true;
}
/**
* create table / collection
* use the default index '__id' as the unique index
* @param collectioName
* @return
*/
public boolean createCollection(String collectioName)
{
if (db==null)
{
System.out.println("no db");
return false;
}
db.createCollection(collectioName);
return true;
}
public MongoCollection getCollection(String collectioName)
{
return db.getCollection(collectioName);
}
}

View File

@ -0,0 +1,8 @@
package nankai.oram.common;
public interface ResponseType {
public static int wrong=0;
public static int normal=1; //without value
public static int normalWithValue=2; //right run and some returned value + LEN +DATA
}

View File

@ -0,0 +1,224 @@
package nankai.oram.common;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class SocketClientUtil {
String ip;
int port;
Socket socket;
DataInputStream in;
DataOutputStream out;
byte recvMsg[];
byte sendMsg[];
public static int responseType;//the returned value from the cloud server
public SocketClientUtil(String ip, int port) {
this.ip = ip;
this.port = port;
recvMsg=new byte[1024];//1k
sendMsg=new byte[4];//100k
responseType=0;
}
public boolean connect() {
try {
// 向本机的2121端口发出客户请求
socket = new Socket(ip, port);
// System.out.println("Established a connection...");
socket.setKeepAlive(true);
out = new DataOutputStream(socket.getOutputStream());
in = new DataInputStream(socket.getInputStream());
// 由Socket对象得到输出流,并构造PrintWriter对象
} catch (Exception e) {
System.out.println("Error connect. " + e);
return false;
}
// System.out.println("success for connection. " );
return true;
}
public void disConnect() {
try {
out.write(CommandType.closeThread);
out.flush();
out.close(); // 关闭Socket输出流
in.close(); // 关闭Socket输入流
socket.close(); // 关闭Socket
} catch (Exception e) {
System.out.println("Error. " + e);
}
}
/**
*
* @param type request command type
* @param cmdInfo some information for specific command
* @param cmdLen the length of the cmdInfo
* @param sendData the data which contains the concrete command information
* @param dataLen the data length
* @param receiveData TODO
* @param retValue the returned data
* @return
*/
public void send(byte[] cmdInfo, int cmdLen, byte[] sendData, int dataLen, byte[] receiveData) {
try {
/************************
* Send
* (1) the request - command
* CommandType | len | data
* And (2) the message content
* *************************/
out.write(cmdInfo, 0, cmdLen);
out.flush();
if (dataLen > 0) {
// out.write(sendData, 0, dataLen);
// out.flush();
if (dataLen<512)
{
out.write(sendData, 0, dataLen);
out.flush();
}else{
int num = dataLen / 512 ;
int leftLen = dataLen % 512;
int hasSend = 0;
for (int i=0;i<num;i++)
{
out.write(sendData, hasSend, 512);
out.flush();
hasSend += 512;
}
if (leftLen>0){
out.write(sendData, hasSend, leftLen);
out.flush();
}
}
/*********************
* Send them with different block
* *********************/
}
/*************************
* Receive the response
* ResponseType | len | data
* *********************/
while (in.read(recvMsg, 0, 1024) > 0) {
break;
}
responseType=recvMsg[0];
//System.out.println("server return" + responseType);
if (responseType==ResponseType.wrong){
System.out.println(cmdInfo[0]+" "+cmdLen+" "+dataLen+"........");
for (int i=0;i<cmdLen;i++)
System.out.print(cmdInfo[i]+" ");
System.out.println();
for (int i=0;i<3;i++)
System.out.print(sendData[i]+" ");
System.out.println();
System.out.println("Return error value!");
}else{
//System.out.println("server return success" + responseType);
if (responseType == ResponseType.normalWithValue)
{
int retLen=0;
while ( (retLen = in.read(recvMsg, 0, 1024)) > 0) {
break;
}
if (retLen != CommInfo.blockSize)
System.out.println("Wrong length" );
if (receiveData!=null && retLen == CommInfo.blockSize)
System.arraycopy(recvMsg, 0, receiveData, 0, retLen);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(byte[] sendData, int dataLen) {
try {
// out.write(sendData, 0, dataLen);
// out.flush();
if (dataLen<512)
{
out.write(sendData, 0, dataLen);
out.flush();
}else{
int length = dataLen / 512;
int leftLen = dataLen % 512;
int pos = 0;
for (int i = 0; i < length; i++) {
out.write(sendData, pos, 512);
out.flush();
pos += 512;
}
if (leftLen > 0) {
out.write(sendData, pos, leftLen);
out.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public int receiving(byte[] recvData, int len) {
int retLen = -1;
try {
retLen = in.read(recvData, 0, len) ;
} catch (IOException e) {
e.printStackTrace();
}
return retLen;
}
public void sendAndReceive(byte[] cmdInfo, int cmdLen) {
try {
out.write(cmdInfo, 0, cmdLen);
out.flush();
/*************************
* Receive the response
* ResponseType | len | data
* *********************/
while (in.read(recvMsg, 0, 1024) > 0) {
break;
}
responseType=recvMsg[0];
//System.out.println("server return" + responseType);
if (responseType==ResponseType.wrong){
System.out.println(cmdInfo[0]+" "+cmdLen+"........");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,65 @@
package nankai.oram.common;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class SymmetricCypto {
Cipher cp;
int keySize;
static final String CIPHER_ALGORITHM_CBC_NoPadding = "AES/CBC/NoPadding";
byte[] iv;
public SymmetricCypto(int keysize)
{
try {
cp=Cipher.getInstance(CIPHER_ALGORITHM_CBC_NoPadding);
keySize=keysize;
iv=new byte[16];
for (int i=0;i<16;i++)
iv[i]=0;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
}
public void initEnc(SecretKey sk, byte[] IV) {
try {
cp.init(Cipher.ENCRYPT_MODE, sk, new IvParameterSpec( (IV==null)?iv:IV ));
} catch (Exception e) {
e.printStackTrace();
}
}
public void initDec(SecretKey sk, byte[] IV)
{
try {
cp.init(Cipher.DECRYPT_MODE, sk, new IvParameterSpec( (IV==null)?iv:IV ));
} catch (Exception e) {
e.printStackTrace();
}
}
public void enc_decData(byte[] bData, int len)
{
int blockNumber = len/keySize;
for (int i=0;i<blockNumber;i++)
{
try {
cp.doFinal(bData, i*keySize, keySize, bData, i*keySize);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,120 @@
package nankai.oram.common;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Random;
import javax.crypto.SecretKey;
import nankai.oram.client.MCloudCommInfo;
public class Util {
public static boolean debug = false;
public static int writeNumber = 0; //
public static int cloudtocloud = 0; //
public static long bandwidth = 0; //
public static long cloudcloudbandwidth = 0; //
public static long readbandwidth = 0; //
public static int readNumber = 0; //
public static int byteToInt(byte[] src, int pos, int len)
{
int ret = 0;
for(int i =0; i< len; i++){
ret += (src[pos+i]&0xff) << (24-8*i);
}
return ret;
}
public static void intToByte(byte[] dest, int pos, int value) {
dest[pos+3] = (byte) (value & 0xff);
dest[pos+2] = (byte) (value >> 8 & 0xff);
dest[pos+1] = (byte) (value >> 16 & 0xff);
dest[pos+0] = (byte) (value >> 24 & 0xff);
}
public static int rand_int(int maxNum)
{
Random rnd=new Random();
if (maxNum<=0) maxNum=1;
return Math.abs(rnd.nextInt(maxNum));
}
public static byte[] generateDummyData( int len)
{
byte[] bData=new byte[len];
// Random rnd=new Random();
// rnd.nextBytes(bData);
for (int i=0;i<len;i++)
bData[i]=-1;
return bData;
}
public static byte[] generateSessionData( int len)
{
byte[] bData=new byte[len];
Random rnd=new Random();
rnd.nextBytes(bData);
return bData;
}
public static byte[] generateIV(int dummyID) {
byte[] iv=new byte[16];
Util.intToByte(iv, 0, dummyID);
for (int i=4;i<16;i++)
{
iv[i] = 0;
}
return iv;
}
public static int fpeForPermution(int inData, SecretKey sfk, int modular)
{
SymmetricCypto scp =new SymmetricCypto(CommInfo.keySize);
scp.initEnc(sfk, null);
byte[] bData = new byte[CommInfo.keySize];
for (int j=0; j<CommInfo.keySize; j++)
bData[j]=(byte) inData;
scp.enc_decData(bData, CommInfo.keySize);
int ret = Math.abs( Util.byteToInt(bData, 0, 4) );
return ret % modular;
}
// public static byte[] hexStringToByte(String hex) {
// int len = (hex.length() / 2);
// byte[] result = new byte[len];
// char[] achar = hex.toCharArray();
// for (int i = 0; i < len; i++) {
// int pos = i * 2;
// result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
// }
// return result;
// }
//
// private static byte toByte(char c) {
// byte b = (byte) "0123456789ABCDEF".indexOf(c);
// return b;
// }
//
// /** *//**
// * 把字节数组转换成16进制字符串
// * @param bArray
// * @return
// */
// public static final String bytesToHexString(byte[] bArray) {
// StringBuffer sb = new StringBuffer(bArray.length);
// String sTemp;
// for (int i = 0; i < bArray.length; i++) {
// sTemp = Integer.toHexString(0xFF & bArray[i]);
// if (sTemp.length() < 2)
// sb.append(0);
// sb.append(sTemp.toUpperCase());
// }
// return sb.toString();
// }
}

View File

@ -0,0 +1,14 @@
package nankai.oram.interfaces;
import java.util.Queue;
import nankai.oram.client.common.SlotObject;
public interface MultiCloudORAM {
public byte[] readCloud(String key);
public void writeCloud(Queue slot);
public byte[] readCloud(int key);
}

View File

@ -0,0 +1,10 @@
package nankai.oram.interfaces;
public interface ORAM {
public void write(String idStr, byte[] value);
public byte[] read(String idStr);
public void write(int id, byte[] value);
public byte[] read(int id);
}

View File

@ -0,0 +1,45 @@
package nankai.oram.server;
import java.util.Vector;
public class SessionManager {
public static SessionManager instance;
public Vector objects ;
public synchronized static SessionManager getInstance()
{
if (instance==null)
instance=new SessionManager();
return instance;
}
private SessionManager()
{
objects = new Vector();
}
public synchronized SessionObject getObject(byte[] sessionID)
{
SessionObject obj = null;
int size = objects.size();
for (int i=0; i<size; i++)
{
obj = (SessionObject) objects.get(i);
if (obj.isEqual(sessionID) )
return obj;
}
return null;
}
public synchronized void addObject(SessionObject obj)
{
objects.add(obj);
//System.out.println("2. add --------------------size: "+objects.size());
}
public synchronized void removeObject(SessionObject obj)
{
objects.remove(obj);
//System.out.println("4. remove -----------------size: "+objects.size());
}
}

View File

@ -0,0 +1,132 @@
package nankai.oram.server;
import java.util.Random;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import nankai.oram.client.MCloudCommInfo;
import nankai.oram.common.CommInfo;
import nankai.oram.common.SymmetricCypto;
import nankai.oram.common.Util;
public class SessionObject {
public byte[] sessionID;
public byte[] levels;
public int idsLen = 0;
byte[][] shffule;
public int filledLevelLength;
public SecretKey key[];
public int unfilledLevel;
SecretKey sfk; //onion level key and shuffle key
SymmetricCypto scp;
int bPos =0;
public SessionObject(byte[] sid)
{
scp =new SymmetricCypto(CommInfo.keySize);
//System.out.print("2. add session ");
sessionID = new byte[8];
for(int i=0;i<8;i++){
//System.out.print(sid[i]+" ");
sessionID[i]=sid[i];
}
//System.out.println();
}
public void setLevels(byte[] ls, int len)
{
if (ls!=null)
;//System.out.println("has received IDs and levels Data!!");
idsLen=len;
levels=new byte[idsLen];
System.arraycopy(ls, 0, levels, 0, len);
}
public boolean isEqual(byte[] sid)
{
for(int i=0;i<8;i++)
{
if (sessionID[i]!=sid[i])
return false;
}
return true;
}
public void createShuffle(int filledLevelLength)
{
this.filledLevelLength = filledLevelLength;
shffule=new byte[filledLevelLength][CommInfo.blockSize];
bPos = 0;
}
public void createkey(int unfilledLevel)
{
this.unfilledLevel = unfilledLevel;
key = new SecretKey[unfilledLevel+1];
}
public void setKey(int level, byte[] bdata)
{
key[level] = new SecretKeySpec(bdata, "AES");
}
public void setSFKey( byte[] bdata)
{
// System.out.print("setSFKey " );
// for (int i=0;i<6;i++)
// System.out.print ( bdata[i]+" " );
// System.out.println( );
sfk = new SecretKeySpec(bdata, "AES");
}
public void setBlockData(int pos, byte[] bdata)
{
bPos++;
System.arraycopy(bdata, 0, shffule[pos], 0, CommInfo.blockSize);
}
public void setBlockData( byte[] bdata)
{
System.arraycopy(bdata, 0, shffule[bPos++], 0, CommInfo.blockSize);
}
public void setBlockDataWithOnionDecryption(int pos, byte[] bdata, int level)
{
// System.out.println("shuffleData: onion decryption: -> level:"+level+" pos:"+pos);
// scp.initDec(key[level], null);
// scp.enc_decData(bdata, CommInfo.blockSize);
System.arraycopy(bdata, 0, shffule[pos], 0, CommInfo.blockSize);
}
public void psuedo_random_permute() {
byte[] bData = new byte[CommInfo.blockSize];
// for (int i = 0; i < filledLevelLength; i++) {
// System.out.println("i: "+i+" "+shffule[i][0]);
// }
for (int i = 0; i <filledLevelLength; i++) {
int j = Util.fpeForPermution(i, sfk, filledLevelLength);
System.arraycopy(shffule[i], 0, bData, 0, CommInfo.blockSize);
System.arraycopy(shffule[j], 0, shffule[i], 0, CommInfo.blockSize);
System.arraycopy(bData, 0, shffule[j], 0, CommInfo.blockSize);
// System.out.println("permute: "+i+" "+j);
}
}
public void onionEncryption() {
// for (int i = 0; i <filledLevelLength; i++) {
// scp.initEnc(sfk, null);
// scp.enc_decData(shffule[i], CommInfo.blockSize);
// }
}
}

View File

@ -0,0 +1,152 @@
package nankai.oram.server;
import java.io.UnsupportedEncodingException;
import nankai.oram.common.CommInfo;
import nankai.oram.common.MongDBUtil;
import nankai.oram.server.partition.PartitionORAMServer;
import org.bson.Document;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
public class ThinORAMserver {
public static ThinORAMserver instance;
byte cloud;
boolean initFlag;
int N;
int n_levels;
int n_partitions;
int n_blocks;
int n_realBlocks_p;//the real number of blocks in a partition
int n_capacity;//the max capacity of a partition -- need the top level
public MongDBUtil dbUtil;
byte[] bBlockData;
byte s_buffer[][];//shuffule buffer - a large memory
private ThinORAMserver()
{
bBlockData=new byte[CommInfo.blockSize];
initFlag=false;
dbUtil=new MongDBUtil();
dbUtil.connect("localhost", 27017);
cloud = 0;
}
public static ThinORAMserver getInstance()
{
if (instance==null)
instance=new ThinORAMserver();
return instance;
}
/**
* This function will create the database for the ORAM
*/
public boolean init(int paritions, int capacity, int levels, byte cloud)
{
if (initFlag)
return false;
n_partitions = paritions;
n_capacity = capacity;
n_levels = levels;
this.cloud = cloud;
//Create DB and open DB
if (!dbUtil.createDB("ThinPartitionORAM"+cloud))
return false;
//init partitions: create the table/collection for the partitions
try {
initPartitions();
} catch (UnsupportedEncodingException e) {
// TODO ×Ô¯Éú³ÉµÄ catch ¿é
e.printStackTrace();
return false;
}
initFlag=true;
return true;
}
public boolean openDB(byte cloud)
{
this.cloud=cloud;
if (!dbUtil.openDB("ThinPartitionORAM"+cloud))
return false;
return true;
}
public boolean writeBlock(int p, int _id, byte[] blockData, int pos) throws UnsupportedEncodingException
{
System.arraycopy(blockData, pos, bBlockData, 0, CommInfo.blockSize);
MongoCollection<Document> collection = dbUtil.getCollection("part_"+p);
String str=new String(bBlockData, "ISO-8859-1");
collection.findOneAndReplace(new Document("_id", _id), new Document("_id", _id).append("data", str));
return true;
}
public boolean readBlock(int p, int _id, byte[] receiveData) {
boolean bError = false;
try{
MongoCollection<Document> collection = dbUtil
.getCollection("part_" + p);
// Find the data and return them
FindIterable<Document> findIterable = collection.find(new Document(
"_id", _id));
MongoCursor<Document> mongoCursor = findIterable.iterator();
if (mongoCursor.hasNext()) {
Document doc1 = mongoCursor.next();
String bData = (String) doc1.get("data");
byte[] bs = bData.getBytes("ISO-8859-1");
System.arraycopy(bs, 0, receiveData, 0, CommInfo.blockSize);
return true;
}
}catch(Exception ex)
{
bError=true;
ex.printStackTrace();
}finally{
if (bError)
System.out.println("!!!!!!!!!!!!!!!!!readBlock mongdbError,p:"+p+" _id:"+_id);
}
return false;
}
private void initPartitions() throws UnsupportedEncodingException
{
int i=0;
for (i=0;i<n_partitions;i++)
{
dbUtil.createCollection("part_"+i);
//insert all the data records into the collection
MongoCollection<Document> collection = dbUtil.getCollection("part_"+i);
//Each level, there are max 2^i real blocks, but more than 2^i dummy blocks
for (int j = 0; j < n_capacity; j++) {
/*collection.insertOne(new Document("_id", j).append("data",
new String(bBlockData, "ISO-8859-1")));*/
collection.insertOne(new Document("_id", j).append("data",
bBlockData ));
}
/***************************************
* Each level, there are 2^(i+1) blocks
* ***********************************/
}
}
}

View File

@ -0,0 +1,640 @@
package nankai.oram.server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import javax.crypto.SecretKey;
import nankai.oram.client.MCloudCommInfo;
import nankai.oram.common.CommInfo;
import nankai.oram.common.CommandType;
import nankai.oram.common.ResponseType;
import nankai.oram.common.SocketClientUtil;
import nankai.oram.common.Util;
public class ThinPartitionServerThread extends Thread {
Socket socket = null; // 保存与本线程相关的Socket对象
byte recvCmd[];
byte recvMsg[];
byte sendMsg[];
ThinORAMserver oram;
public ThinPartitionServerThread(Socket socket) {
this.socket = socket;
recvCmd = new byte[29];
recvMsg = new byte[1024];
sendMsg = new byte[1024];
oram = ThinORAMserver.getInstance();
//System.out.println(" new connection ......... ");
}
public void run() {
DataInputStream in = null;
DataOutputStream out = null;
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
byte type = 0;
int len = 0;
while (true) {
type = 0;
len = 0;
while ((len = in.read(recvCmd, 0, 1)) > 0) {
type = recvCmd[0];
// System.out
// .println("-----------------------------------------------------------");
// System.out.println("receive a command type:" + type + " len "
// + len);
break;
}
//close the thread
if (type == CommandType.closeThread)
break;
switch (type) {
case CommandType.openDB:
{
in.read(recvCmd, 1, 1);
oram.openDB(recvCmd[1]);
out.writeByte(ResponseType.normal);
out.flush();
break;
}
case CommandType.initORAM: {
len = in.read(recvCmd, 1, 13);
if (len != 13) {
System.out.println("initORAM error data! " + len);
out.writeByte(ResponseType.wrong);
out.flush();
} else
initORAM(out);
break;
}
case CommandType.readCloud: {
len = in.read(recvCmd, 1, 8);
if (len != 8) {
System.out.println("readCloud error data! " + len);
out.writeByte(ResponseType.wrong);
out.flush();
} else {
/**************************************
* partition+_id
* **********************************/
readCloud(out, in);
}
break;
}
case CommandType.noticeWriteCloud: {
len = in.read(recvCmd, 1, 21);
// content: session ID | unfilled - partition | other cloud for shuffling | length of ids
if (len != 21) {
System.out.println("noticeWriteCloud error data! " + len);
out.writeByte(ResponseType.wrong);
out.flush();
} else {
/**************************************
* partition+_id
* **********************************/
noticeWriteCloud(out, in);
}
break;
}
case CommandType.directWriteCloud:
{
len = in.read(recvCmd, 1, 12);
// content: session ID | unfilled - partition | other cloud for shuffling | length of ids
if (len != 12) {
System.out.println("directWriteCloud error data! " + len);
out.writeByte(ResponseType.wrong);
out.flush();
} else {
/**************************************
* partition+_id
* **********************************/
directWriteCloud(out, in);
}
break;
}
case CommandType.noticeShuffle: {
len = in.read(recvCmd, 1, 28);
// content: session ID | unfilled - partition | other cloud for shuffling | length of ids
if (len != 28) {
System.out.println("noticeWriteCloud error data! " + len);
out.writeByte(ResponseType.wrong);
out.flush();
} else {
/**************************************
* partition+_id
* **********************************/
noticeShuffle(out, in);
}
break;
}
case CommandType.shuffleData:{
len = in.read(recvCmd, 1, 12);
if (len != 12) {
System.out.println("shuffleData error data! " + len);
for (int i=0;i<len;i++)
System.out.print(recvCmd[i]+" ");
out.writeByte(ResponseType.wrong);
out.flush();
} else {
/**************************************
* partition+_id
* **********************************/
shuffleData(out, in);
}
break;
}
}
}
} catch (Exception e) {
System.out.println("Error.?>>>>> " + e);
e.printStackTrace();
} finally {
try {
out.close(); // 关闭Socket输出流
in.close();// 关闭Socket输入流
socket.close(); // 关闭Socket
} catch (IOException e1) {
e1.printStackTrace();
}
}
//System.out.println("closing............................ ");
}
private void initORAM(DataOutputStream out) throws IOException {
/*********
* CMD 9, CMDTYPE | PARTITIONS | CAPACITY
* *********/
// System.out.println("init oram");
int paritions = Util.byteToInt(recvCmd, 1, 4);
int capacity = Util.byteToInt(recvCmd, 5, 4);
int levels = Util.byteToInt(recvCmd, 9, 4);
byte cloud = recvCmd[13];
// System.out.println("init paritions capacity:" + paritions + " "
// + capacity);
oram.init(paritions, capacity, levels, cloud);
// System.out.println("init OK.");
out.writeByte(ResponseType.normal);
out.flush();
}
/**
* When receive this data, the cloud would read data and send them to the other cloud
* @param out
* @param in
* @throws IOException
*/
private void shuffleData(DataOutputStream out, DataInputStream in)
throws IOException {
/****************************************
* (2)Send All the data, onionkeys in slots to the otherCloud
*
* CommandType: shuffleData
* Content: session ID | unfilled levels number |
* onion keys and slots data
* ************************************/
byte[] sessionID = new byte[8];
System.arraycopy(recvCmd, 1, sessionID, 0, 8);
int idsLen = Util.byteToInt(recvCmd, 9, 4);
//System.out.println("4. shuffleData " + sessionID[0]);
/**************************************************************
* Get the session Object, must be received, because client first send noticeShuffle,
* and then the target cloud sends the shuffled data
*************************************************************/
SessionManager manager=SessionManager.getInstance();
SessionObject session = manager.getObject(sessionID);
if (session==null)
{
//create it
System.out.println("Cannot find the session OBJECT!!!!!!!!!!!!!!!!!!!!!!!"+sessionID[0]+" "+sessionID[5]);
return;
//session=new SessionObject(sessionID);
}
//verify the length
if (idsLen != session.idsLen)
System.out.println("wrong ID number!!!!!!!!!!!!!!!!!!!!!!! idsLen:"+idsLen+" "+session.idsLen);
//System.out.println("shuffleData: idsLen "+idsLen);
int filledLevelLength = session.filledLevelLength;
/***********************************************
* Receive the block data from other cloud
*
* Firstly, onion decrypt them
*******************************************/
byte[] recBlcokData = new byte[CommInfo.blockSize];
for (int i=0;i<idsLen; i++)
{
if (in.read(recBlcokData, 0, CommInfo.blockSize) <= 0) {
System.out.println("shuffleData: ERROR id block data!!!!!!!!!!!!!!!!!!!!!!!!");
}
/******************** do the onion decryption ********************************/
session.setBlockDataWithOnionDecryption(filledLevelLength - idsLen + i, recBlcokData, session.levels[i]);
}
/*****************************************
* Finally, shuffule them
*******************************************/
// System.out.println("begin psuedo_random_permute ");
session.psuedo_random_permute();
//re-encrypt them and send backs
session.onionEncryption();
/***********************
* return back the data
* ********************************/
byte[] backCmd=new byte[5];
backCmd[0]=CommandType.backData;
Util.intToByte(backCmd, 1, session.filledLevelLength);
out.write(backCmd, 0, 5);
out.flush();
for (int i=0;i<session.filledLevelLength;i++)
{
out.write(session.shffule[i], 0, CommInfo.blockSize);
out.flush();
}
//The end of the session
manager.removeObject(session);
}
private void directWriteCloud(DataOutputStream out, DataInputStream in)
throws IOException {
/****************************************
* (1)Send All the data, onionkeys in slots to the otherCloud
*
* CommandType: shuffleData
* Content: session ID | unfilled levels number |
* onion keys and slots data
* ************************************/
//System.out.println("directWriteCloud");
int partition = Util.byteToInt(recvCmd, 1, 4);
int unfilledLevel = Util.byteToInt(recvCmd, 5, 4);
int filledLevelLength = Util.byteToInt(recvCmd, 9, 4); ;
/*******************
* Has received the write operation command?
* If not, create the session object
* *********************/
byte[] recBlcokData = new byte[CommInfo.blockSize];
int beginID=(1 << (unfilledLevel + 1)) - 2;
for (int i=0;i<filledLevelLength;i++)
{
if (in.read(recBlcokData, 0, CommInfo.blockSize) <= 0) {
System.out.println("ERROR read data!!!!!!!!!!!!!!!!!!!!!!!!");
}else{
oram.writeBlock(partition, beginID+i, recBlcokData, 0);
}
//System.out.println("i: "+i+ " "+recBlcokData[0]);
}
//read the sfk
byte[] sfk=new byte[2];
if (in.read(sfk, 0, 2) <= 0) {
System.out.println("ERROR read key data!!!!!!!!!!!!!!!!!!!!!!!!");
}
out.writeByte(ResponseType.normal);
out.flush();
}
/**
* When receive this data, the cloud would read data and send them to the other cloud
* @param out
* @param in
* @throws IOException
*/
private void noticeShuffle(DataOutputStream out, DataInputStream in)
throws IOException {
/****************************************
* (1)Send All the data, onionkeys in slots to the otherCloud
*
* CommandType: shuffleData
* Content: session ID | unfilled levels number |
* onion keys and slots data
* ************************************/
//System.out.println("1. noticeShuffle");
byte[] sessionID = new byte[8];
System.arraycopy(recvCmd, 1, sessionID, 0, 8);
int partition = Util.byteToInt(recvCmd, 9, 4);
int unfilledLevel = Util.byteToInt(recvCmd, 13, 4);
int filledLevelLength = Util.byteToInt(recvCmd, 17, 4);
int idsLen = Util.byteToInt(recvCmd, 21, 4);
int evictSize = Util.byteToInt(recvCmd, 25, 4);
// System.out.println(" partition "+ partition +" unfilledLevel "+ unfilledLevel+" filledLevelLength "+filledLevelLength+" idsLen "+idsLen );
int rndLength = filledLevelLength - idsLen - 2*evictSize;
if (rndLength<0)
System.out.println(" rndLength "+ rndLength +" filledLevelLength "+filledLevelLength+" idsLen "+idsLen+" evictSize "+evictSize );
if (filledLevelLength <=0 )
;//System.out.println("ERROR!!!!!!!!!!!!!!!!!!!!!!!!");
/*******************
* Has received the write operation command?
* If not, create the session object
* *********************/
SessionManager manager=SessionManager.getInstance();
SessionObject session = manager.getObject(sessionID);
if (session==null)
{
//create it
session=new SessionObject(sessionID);
}
//receive the IDs
byte[] levels = new byte[idsLen];
if (idsLen>0){
// read all the ids
// if (in.read(levels, 0, idsLen) <= 0)
// System.out.println("ERROR read IDs data!!!!!!!!!!!!!!!!!!!!!!!!");
readSocketLongData(in, idsLen, levels);
}else{
;//System.out.println("ids Len is 0!!");
}
session.setLevels(levels, idsLen);
//receive each data and buffer them
session.createShuffle(filledLevelLength);
byte[] recBlcokData = new byte[CommInfo.blockSize];
for (int i=0;i< 2*evictSize ;i++)
{
if (in.read(recBlcokData, 0, CommInfo.blockSize) <= 0) {
System.out.println("ERROR read data!!!!!!!!!!!!!!!!!!!!!!!!");
}
//System.out.println("i: "+i+ " "+recBlcokData[0]);
session.setBlockData(i, recBlcokData);
}
/*******************************************************
* read the random value and generate the dummy data
******************************************************/
byte[] rnds=new byte[rndLength*4];
{
readSocketLongData(in, rndLength*4, rnds);
for (int i=0;i<rndLength;i++)
{
int did=Util.byteToInt(rnds, i*4, 4);
//add the dummy block into the buffer
session.setBlockData(i+2*evictSize, this.generateXORBlock(did));
}
}
//receive the onion keys
session.createkey(unfilledLevel);
byte[] bkeyData = new byte[CommInfo.keySize];
for (int i=MCloudCommInfo.severBeginLevel; i<=unfilledLevel; i++)
{
if (in.read(bkeyData, 0, CommInfo.keySize) <= 0) {
System.out.println("ERROR read key data!!!!!!!!!!!!!!!!!!!!!!!!");
}
session.setKey(i, bkeyData);
}
//read the sfk
byte[] sfk=new byte[16];
if (in.read(sfk, 0, 16) <= 0) {
System.out.println("ERROR read key data!!!!!!!!!!!!!!!!!!!!!!!!");
}
session.setSFKey(sfk);
manager.addObject(session);
out.writeByte(ResponseType.normal);
out.flush();
}
public byte[] generateXORBlock(int dummyID)
{
//Encrypt the 0x00 default value by the userkey
byte[] data=new byte[CommInfo.blockSize];
for (int i=0;i<CommInfo.blockSize;i++)
{
data[i] = 0;
}
// SecretKey userKey;
// /****************************
// * The first 4 bytes is the dummmyID and the random value, to make sure it is less than 0
// *
// * But now, to simplify the implementation, we ignore the random value for the same 0000000
// * ******************************/
//
// byte[] iv = Util.generateIV(dummyID);
//encrypt
// SymmetricCypto scp=new SymmetricCypto(CommInfo.keySize);
// scp.initEnc(userKey, iv);
// scp.enc_decData(data, CommInfo.blockSize);
return data;
}
/**
* When receive this data, the cloud would read data and send them to the other cloud
* @param out
* @param in
* @throws IOException
*/
private void noticeWriteCloud(DataOutputStream out, DataInputStream in)
throws IOException {
/****************************************
* (1)Notice this cloud to send the data to the otherCloud for shuffling
* CommandType: writeCloud
* content: session ID | unfilled - partition | other cloud for shuffling | length of ids
*
* When receive this data, the cloud would read data and send them to the other cloud
* ************************************/
//System.out.println("3. noticeWriteCloud "+recvCmd[1]);
byte[] sessionID = new byte[8];
System.arraycopy(recvCmd, 1, sessionID, 0, 8);
int partition = Util.byteToInt(recvCmd, 9, 4);
int unfilledLevel = Util.byteToInt(recvCmd, 13, 4);
int cloud = recvCmd[17];
int idsLen = Util.byteToInt(recvCmd, 18, 4);
byte[] ids = null;
// 4 ID + 1 level
if (idsLen > 0) {
ids = new byte[idsLen*4];
// if (in.read(ids, 0, idsLen*4)!=idsLen*4)
// System.out.println("ids Error!!!");
readSocketLongData(in, idsLen*4, ids);
}else{
;//System.out.println("data length is 0!");
}
/************************
* SEND COMMAND TO OTHER CLOUD
* ***************************/
byte[] cmd=new byte[13];
cmd[0]=CommandType.shuffleData;
System.arraycopy(sessionID, 0, cmd, 1, 8);//session ID
Util.intToByte(cmd, 9, idsLen);//idsLen
SocketClientUtil SCU=new SocketClientUtil(MCloudCommInfo.ip[cloud], MCloudCommInfo.port[cloud]);
SCU.connect();
// System.out.println("Ready for shuffle data command sending!");
// for (int i=0;i<13;i++)
// System.out.print(cmd[i]+" ");
SCU.send(cmd, 13);
byte[] bData = new byte[CommInfo.blockSize];
for (int i = 0; i < idsLen; i++) {
int _id = Util.byteToInt(ids, i * 4, 4);
// System.out.println("read _id: "+_id+" partition: "+partition);
//IDS 4 id | 1 level
// if (_id == 0) {
// System.out
// .println("noticeWriteCloud :!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!idsLen!!!!!!"
// + idsLen);
// for (int z = 0; z < idsLen * 4; z++)
// System.out.print(ids[z] + " ");
//
// for (int z = 0; z < idsLen ; z++)
// {
// int _did = Util.byteToInt(ids, z * 4, 4);
// System.out.print(_did + " ");
// }
// }
oram.readBlock(partition, _id, bData);
SCU.send(bData, CommInfo.blockSize);
}
//Then, waiting for the response
byte[] backCmd=new byte[5];
if (SCU.receiving(backCmd, 5)!=5 || backCmd[0]!=CommandType.backData)
System.out.println("wrong back command!");
int length=Util.byteToInt(backCmd, 1, 4);
int beginID=(1 << (unfilledLevel + 1)) - 2;
for (int i=0;i<length; i++)
{
if (SCU.receiving(bData, CommInfo.blockSize)!=CommInfo.blockSize)
System.out.println("wrong back data!");
else{
//System.out.println("write _id: "+(beginID+i)+" beginID: "+beginID);
//store it in the database
oram.writeBlock(partition, beginID+i, bData, 0);
}
}
SCU.disConnect();
out.writeByte(ResponseType.normal);
out.flush();
}
private void readSocketLongData(DataInputStream in, int dataLen, byte[] ids)
throws IOException {
if (dataLen<512){
if (in.read(ids, 0, dataLen)!=dataLen)
System.out.println("ids Error!!!");
}else{
int num = dataLen / 512 ;
int leftLen = dataLen % 512;
int hasRead = 0;
for (int i=0;i<num;i++)
{
if (in.read(ids, hasRead, 512)!=512)
System.out.println("noticeWriteCloud 512 Error!!!");
hasRead += 512;
}
if (leftLen>0){
if (in.read(ids, hasRead, leftLen)!=leftLen)
System.out.println("noticeWriteCloud leftLen Error!!!");
}
}
}
private void readCloud(DataOutputStream out, DataInputStream in)
throws IOException {
/*********
* P + ID
* *********/
// System.out.println("readCloud");
int p = Util.byteToInt(recvCmd, 1, 4);
int len = Util.byteToInt(recvCmd, 5, 4); // the next length of all the
// IDs
//System.out.println("readCloud p _id :" + p + " len: " + len);
byte[] bData = new byte[CommInfo.blockSize];
if (len>0){
byte[] ids = new byte[len * 4];
// read all the ids
while (in.read(ids, 0, len * 4) > 0) {
break;
}
for (int i = 0; i < CommInfo.blockSize; i++)
bData[i] = 0;
byte[] bRnd = new byte[CommInfo.blockSize];
for (int i = 0; i < len; i++) {
int _id = Util.byteToInt(ids, i * 4, 4);
if (_id == 0)
System.out
.println("readCloud :!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
oram.readBlock(p, _id, bRnd);
for (int j = 0; j < CommInfo.blockSize; j++)
bData[j] ^= bRnd[j];
}
}
out.writeByte(ResponseType.normalWithValue);
out.flush();
out.write(bData, 0, CommInfo.blockSize);
out.flush();
}
}

View File

@ -0,0 +1,59 @@
package nankai.oram.server;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import nankai.oram.client.MCloudCommInfo;
public class ThinServer {
private int queueSize = 100;
private static int port = 2121;
public ThinServer() {
try {
boolean listening = true; // 是否对客户端进行监听
ServerSocket serverSocket = null; // 服务器端Socket对象
try {
// 创建一个ServerSocket在端口2121监听客户请求
serverSocket = new ServerSocket();
//关闭serverSocket时立即释放serverSocket绑定端口以便端口重用默认为false
serverSocket.setReuseAddress(true);
//accept等待连接超时时间为1000毫秒默认为0永不超时
//serverSocket.setSoTimeout(10000);
//为所有accept方法返回的socket对象设置接收缓存区大小单位为字节默认值和操作系统有关
serverSocket.setReceiveBufferSize(128*1024);
//设置性能参数可设置任意整数数值越大相应的参数重要性越高连接时间延迟带宽
serverSocket.setPerformancePreferences(3, 2, 1);
//服务端绑定至端口10为服务端连接请求队列长度
serverSocket.bind(new InetSocketAddress(port), queueSize);
System.out.println("Server starts..." + port);
} catch (Exception e) {
System.out.println("Can not listen to. " + e);
}
while (listening) {
// 监听到客户请求,根据得到的Socket对象和客户计数创建服务线程,并启动之
//new ServerThread(server.accept()).start();
new ThinPartitionServerThread(serverSocket.accept()).start();
}
} catch (Exception e) {
System.out.println("Error.... " + e);
}
}
public static void main(String[] args) {
/**
* To run in a computer to simulate the multiple servers, we use the parameters of main to tell the socket bind port
*/
if (args.length>0){
//the pos is cloud - 1
int cloud = Integer.parseInt(args[0]);
ThinServer.port=MCloudCommInfo.port[cloud-1];
System.out.println("cloud "+cloud+" port:"+ThinServer.port);
}
new ThinServer();
}
}