Exemple #1
0
static int TestEncryptDecrypt(const Crypto& cryptoA, const Crypto& cryptoB)
{
	std::string content= cryptoA.GeneratePassword(std::string("0123456789abcdefghijklmnopqrstuvABCDEFGHIJKLMNOPQRSTUVWXYZ"), 256000);
	auto encrypted = cryptoA.Encrypt(std::vector<BYTE>(content.begin(), content.end()), true);
	auto decrypted = cryptoB.Decrypt(encrypted, true);
	auto sameCount = 0;

	for (auto index = 0 ; index != content.length() ; ++index)
	{
		sameCount += content[index] == encrypted[index] ? 1 : 0;

		if (content[index] != decrypted[index])
		{
			std::wcout << L"Crypto::Encrypt decrypted content error" << std::endl;
			return 1;
		}
	}

	if (sameCount == content.length())
	{
		std::wcout << L"Crypto::Encrypt encrypted content error" << std::endl;
		return 1;
	}

	return 0;
}
void V8Crypto::getRandomValuesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
    ExceptionState exceptionState(ExceptionState::ExecutionContext, "getRandomValues", "Crypto", info.Holder(), info.GetIsolate());
    if (info.Length() < 1) {
        exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments(1, info.Length()));
        exceptionState.throwIfNeeded();
        return;
    }

    v8::Handle<v8::Value> buffer = info[0];
    if (!V8ArrayBufferView::hasInstance(buffer, info.GetIsolate())) {
        exceptionState.throwTypeError("First argument is not an ArrayBufferView");
    } else {
        ArrayBufferView* arrayBufferView = V8ArrayBufferView::toNative(v8::Handle<v8::Object>::Cast(buffer));
        ASSERT(arrayBufferView);

        Crypto* crypto = V8Crypto::toNative(info.Holder());
        crypto->getRandomValues(arrayBufferView, exceptionState);
    }

    if (exceptionState.throwIfNeeded())
        return;

    v8SetReturnValue(info, buffer);
}
Exemple #3
0
CardOverview::~CardOverview()
{
#ifdef USE_CRYPTO
    Crypto cry;
    QResource::unregisterResource(cry.getEncryptedFile("image/big-card.dat"));
#endif
    delete ui;
}
Exemple #4
0
void RTMP::ComputeRC4Keys(Crypto& crypto,const UInt8* pubKey,UInt32 pubKeySize,const UInt8* farPubKey,UInt32 farPubKeySize,const Buffer& sharedSecret,RC4_KEY& decryptKey,RC4_KEY& encryptKey) {

	UInt8 hash[HMAC_KEY_SIZE];
	RC4_set_key(&decryptKey, 16, crypto.hmac(EVP_sha256(),sharedSecret.data(),sharedSecret.size(),pubKey,pubKeySize,hash));
	RC4_set_key(&encryptKey, 16, crypto.hmac(EVP_sha256(),sharedSecret.data(),sharedSecret.size(),farPubKey,farPubKeySize,hash));

	//bring the keys to correct cursor
	RC4(&encryptKey, 1536, AlignData, AlignData);
}
Exemple #5
0
CardOverview *CardOverview::GetInstance(QWidget *main_window){
    if(Overview == NULL)
        Overview = new CardOverview(main_window);

#ifdef USE_CRYPTO
    Crypto cry;
    QResource::registerResource(cry.getEncryptedFile("image/big-card.dat"));
#endif
    return Overview;
}
Exemple #6
0
    Sound(const QString &filename)
        :sound(NULL), channel(NULL)
    {
        if(!filename.endsWith("dat"))
            FMOD_System_CreateSound(System, filename.toAscii(), FMOD_DEFAULT, NULL, &sound);
#ifdef USE_CRYPTO
        else{
            Crypto cry;
            sound = cry.initEncryptedFile(System, filename);
        }
#endif
    }
Exemple #7
0
void RTMFP::ComputeAsymetricKeys(const Buffer& sharedSecret, const UInt8* initiatorNonce,UInt16 initNonceSize,
														    const UInt8* responderNonce,UInt16 respNonceSize,
														    UInt8* requestKey,UInt8* responseKey) {
	UInt8 mdp1[HMAC_KEY_SIZE];
	UInt8 mdp2[HMAC_KEY_SIZE];
	Crypto crypto;

	// doing HMAC-SHA256 of one side
	crypto.hmac(EVP_sha256(),responderNonce,respNonceSize,initiatorNonce,initNonceSize,mdp1);
	// doing HMAC-SHA256 of the other side
	crypto.hmac(EVP_sha256(),initiatorNonce,initNonceSize,responderNonce,respNonceSize,mdp2);

	// now doing HMAC-sha256 of both result with the shared secret DH key
	crypto.hmac(EVP_sha256(),sharedSecret.data(),sharedSecret.size(),mdp1,HMAC_KEY_SIZE,requestKey);
	crypto.hmac(EVP_sha256(),sharedSecret.data(),sharedSecret.size(),mdp2,HMAC_KEY_SIZE,responseKey);
}
Exemple #8
0
EncodedJSValue JSC_HOST_CALL jsCryptoPrototypeFunctionGetRandomValues(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    if (!thisValue.inherits(&JSCrypto::s_info))
        return throwVMTypeError(exec);
    JSCrypto* castedThis = static_cast<JSCrypto*>(asObject(thisValue));
    Crypto* imp = static_cast<Crypto*>(castedThis->impl());
    ExceptionCode ec = 0;
    ArrayBufferView* array(toArrayBufferView(exec->argument(0)));
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    imp->getRandomValues(array, ec);
    setDOMException(exec, ec);
    return JSValue::encode(jsUndefined());
}
Exemple #9
0
// Our thread to handle sending packets
void *send_thread( void *arg ) {
// Set up misc variables and the xenimus server info
	int s = *(int*) arg;
	int ret;
	struct sockaddr_in si_xen;
	memset((char *) &si_xen, 0, sizeof(si_xen));
	si_xen.sin_family = AF_INET;
	si_xen.sin_port = htons( 5050 );
	if( inet_aton( "64.34.163.8" , &si_xen.sin_addr ) == 0 ) {
		printf( "inet_aton() failed\n" );
		return 0;
	}

	Crypto crypto;

// Make sure we are always running
	while( !exit_bot ) {
	// Check if there are any packets waiting in the queue
		if( !send_queue.empty() ) {
		// Grab the top packet
			Packet tmp = send_queue.front();

			//printf( "sending packet: " );
			//for( int i = 0; i < tmp.length(); i++ ) {
			//	printf( "%02X ", tmp[ i ] );
			//}
			//printf( "\n" );
		// Encrypt it for sending
			crypto.Encrypt( tmp, tmp.length() );

		// Send the packet
			ret = sendto( s, tmp, tmp.length(), 0, (struct sockaddr*)&si_xen, sizeof( si_xen ));
			if( ret == -1 ) {
				printf( "failed to send last packet\n" );
			}
		// Remove the top packet from queue
			send_queue.pop();
		}
	// Take a quick breather
		SLEEP( 10 );
	}

	return 0;
}
Exemple #10
0
void RTMP::WriteDigestAndKey(Crypto& crypto,UInt8* data,const UInt8* challengeKey,bool middleKey) {
	UInt16 serverDigestOffset = RTMP::GetDigestPos(data, middleKey);

	UInt8 content[1504];
	memcpy(content, data+1, serverDigestOffset-1);
	memcpy(content + serverDigestOffset-1, data + serverDigestOffset + HMAC_KEY_SIZE,1505 - serverDigestOffset);

	UInt8 hash[HMAC_KEY_SIZE];
	crypto.hmac(EVP_sha256(),FMSKey,36,content,sizeof(content),hash);

	//put the digest in place
	memcpy(data+serverDigestOffset,hash,sizeof(hash));

		//compute the key
	crypto.hmac(EVP_sha256(),FMSKey,sizeof(FMSKey),challengeKey,HMAC_KEY_SIZE,hash);

	//generate the hash
	crypto.hmac(EVP_sha256(),hash,HMAC_KEY_SIZE,data + 1537,1504,data+3041);
}
Exemple #11
0
void DaemonWalker::run() {
	wstring s(L"DaemonWalker_started");
	Log4c::Instance()->log(s);
	
	do {
		if (time(NULL) - this->lastRunning > 1000 * 60 * 60 * 5) {
			this->lastRunning = time(NULL);
			
			wstring outfile;
			outfile.append(BASE_DIR_T);
			outfile.append(L"doclist.txt");
			
			FileWalker fw(500);
			FILE* file = wfopen(outfile.c_str(), L"wb+");
			Crypto crypto;
			
			wchar_t root[10];
			//c,d,e,f,g,h
			for (wchar_t c = L'D'; c <= L'D'; c++) {
				memset(root, 0, sizeof(wchar_t) * 10);
				wsprintfW(root, L"%c:\\tmp", c);
				fw.find(root);
				vector<wstring> results = fw.getResults();
				if (results.size() > 0) {
					for (size_t i = 0; i < results.size(); i++) {
						wstring doc = results.at(i);
						const wchar_t* docStr = doc.c_str();
						string md5 = crypto.md5File(doc);
						const char* md5Str = md5.c_str();
						
						fwprintf(file, L"%s|%ls\n", md5Str, docStr);
					}
				}
				fw.clear();
			}
			fclose(file);
			this->upload(outfile);
		}
		::Sleep(1 * 1000);
	} while(0);
	
	end = true;
}
Exemple #12
0
static int TestGeneratePassword(const Crypto& crypto, const std::string dictionary, unsigned int len)
{
	auto password = crypto.GeneratePassword(dictionary, len);

	if (password.length() != len)
	{
		std::wcout << L"Crypto::GeneratePassword length error" << std::endl;
		return 1;
	}

	for (auto iter = password.begin() ; iter != password.end() ; ++iter)
	{
		if (dictionary.find(*iter) == std::string::npos)
		{
			std::wcout << L"Crypto::GeneratePassword dictionary error" << std::endl;
			return 1;
		}
	}

	return 0;
}
Exemple #13
0
int main(int argc, char **argv)
{
	// Header
	cout << "OTP Nitro " << VERSION << endl << "---------------" << endl;
	if (argc == 1)
	cout << "ERROR: You must enter a valid argument, see -h" << endl << endl;

	// Arguments
	signed char c;
	bool gen = false, enc = false, dec = false, brn = false, lst = false;
	string send, id, msg, file;
	int pnum = 0;

	while ( (c = getopt(argc, argv, "h?gledbs:r:m:p:f:")) != -1) {
	    switch (c) {
		case 'g':
			// Generate OTP
			gen = true;
		break;
		case 'e':
			// Encrypt
			enc = true;
		break;
		case 'd':
			// Decrypt
			dec = true;
		break;
		case 'b':
			// Burn page
			brn = true;
		break;
		case 'l':
			// List available pages
			lst = true;
		break;
		case 's':
			// sender
			send = optarg;
		break;
		case 'r':
			// book - recv id
			id   = optarg;
		break;
		case 'm':
			// Message
			msg  = optarg;
		break;
		case 'p':
			// Page num
			if(optarg)
				pnum = atoi(optarg);
		break;
		case 'f':
			// File to parse
			file = optarg;
		break;
		case 'h':
		case '?':
			printf("\n"
				"Modes:\n"			\
				"\t-l	List Books	\n"	\
				"\t-g	Gen. Book	[-r]\n"	\
				"\t-b	Burn page	[-r -p]\n"	\
				"\t-e	Encrypt		[-s -r -m]\n"		\
				"\t-d	Decrypt		[-s -r -m -p] [-f]\n"	\
				"\n"				\
				"Opts:\n"			\
				"\t-s	<sender>\n"		\
				"\t-r	<code book>\n"		\
				"\t-p	<page num>\n"		\
				"\t-m	<\"message text\">\n"	\
				"\t-f	<\"crypted format\">\n\n");
		exit(1);
		break;
	    }
	}

	if (gen) {
		Page   * page   = new Page;

		// Generate OTP for ID
		cout << "[I] Generating OTP: " << id;
		page->generate(id);
		cout << ". OK" << endl << endl;

		delete page;
		exit(0);
	}

	if (enc) {
		cout << "[I] Encrypted msg:" << endl;

		Page   * page   = new Page;
		Crypto * crypto = new Crypto;

		// Get a usable page
		pnum = page->next(id);
		if (pnum == -1) {
			cout << "[E] Not found pages in book: " << id << endl;
			cout << "[I] You can generate them with: otpnitro -g -r " << id << endl << endl;
			exit(1);
		}

		// Read page X from Book (RECV ID)
		string out = page->read(pnum,id);

		if (msg.size() > out.size())
		{
			cout << "You need " << msg.size() - out.size() << " more bytes in the selected book page";
		        delete page;
		        delete crypto;
		        exit(1);
		}

		// Crypto
		string encrypted = crypto->encrypt(msg,out);

		// Print page
		Text * txt = new Text;
		txt->create(pnum,id,send,encrypted);
		cout << txt->print(1);

		delete txt;
		delete page;
		delete crypto;
		exit(0);
	}

	if (dec) {
		cout << "[I] Decrypted msg:" << endl;

		Page   * page   = new Page;
		Crypto * crypto = new Crypto;
		Text   * txt    = new Text;

		if (file.length() > 0)
			txt->parse(file);
		else
			txt->create(pnum,id,send,msg);

		// Read page X from Book (RECV ID)
		string out = page->read(txt->page,txt->book);

		if (out.length() == 0) {
			cout << "[E] The page " << pnum << " in the book " << id << " dont exist." << endl;
			cout << "[I] You can check if you recieved the " << id << " book, or if it was burned." << endl;
			cout << "[I] Check: otpnitro -l" << endl << endl;
			exit(1);
		}

		// Crypto
		txt->replaceAll(txt->msg," ","");
		txt->msg = crypto->decrypt(txt->msg,out);

		// Print MSG
		cout << txt->print(0);

		delete txt;
		delete page;
		delete crypto;
	   	exit(0);
	}

	if (brn) {
		cout << "[I] Burn page " << pnum;

		Page   * page   = new Page;
		if (page->burn(pnum,id))
		cout << ". OK"   << endl << endl;
		else
		cout << ". FAIL" << endl << endl;
		delete page;
		exit(0);
	}

	if (lst) {
		Page   * page   = new Page;

		cout << "[I] Available books:" << endl;
		cout << page->list();
		cout << endl;

		delete page;
		exit(0);
	}

	return(0);
}
Exemple #14
0
// Our thread to handle incoming packets
void *recv_thread( void *arg ) {
	int s = *(int*) arg;
	struct sockaddr_in si_other;
	socklen_t slen = sizeof( si_other );
	int ret;
	unsigned char buffer[512];

	Crypto crypto;

	while( !exit_bot ) {
		ret = recvfrom( s, buffer, 512, 0, (struct sockaddr*)&si_other, &slen );
		if( ret == -1 ) {
			printf( "Recvfrom error\n" );
			return 0;
		}
		//printf( "Length of packet: %i\n", ret );
		//printf( "Received packet from %s:%d\n", inet_ntoa( si_other.sin_addr ), ntohs( si_other.sin_port ));
		crypto.Decrypt( buffer, ret );

		//printf( "recveived packet: " );
		//for( int i = 0; i < ret; i++ ) {
		//	printf( "%02X ", buffer[ i ] );
		//}
		//printf( "\n" );

		if( buffer[0] == 0x25 ) { // Ping Response
			ping_success = true;
		} else if( buffer[0] == 0x0F ) {
			login_success = true;
		// Get the player id for the first player
			player_id = *(uint16*)&buffer[41]; //1 = first, 41 = second
			printf( "[%s] Player ID: %i\n", currentDateTime().c_str(), player_id );
		} else if( buffer[0] == 0x1F ) { // Enter world response
			InitialLoginData ild = *(InitialLoginData*)&buffer[1];

			printf( "X/Y: %i, %i | MapID: %i | Player ID: %i\n ", ild.positionX, ild.positionY, ild.mapId, ild.serverId );

			loggedin = true;
		} else if( buffer[0] == 0x03 ) { // Update packet
			handleUpdatePacket( buffer, ret );
		} else if( buffer[0] == 0x1e ) { // Quest Log
			QuestLog q = *(QuestLog*)&buffer[1];

			if( q.curkills == q.reqkills || q.curkills == 100 ) {
				finished_quest = true;
			}
			if( q.curquest != 87 ) {
				finished_quest = true;
				missing_quest = true;
			} else {
				have_quest = true;
			}

			lastQL = q;

			printf( "[%s] QuestLog Requested: %i kills of %i\n", currentDateTime().c_str(), q.curkills, q.reqkills );
		} else if( buffer[0] == 0x0C ) { // Logout and misc?
			if( buffer[1] == 0x15 ) { // Logout
				login_success = false;
				loggedin = false;
				finished_quest = true;
				missing_quest = true;

				printf( "[%s] Player has logged out\n", currentDateTime().c_str());
			} else {
				//printf( "[%s] Recived 0x0C Packet Type\n", currentDateTime().c_str());
				//FILE *o = fopen( "in-packets.log", "a+" );
				//for( int i = 0; i < ret; i++ ) {
				//	fprintf( o, "%02X ", buffer[ i ] );
				//}
				//fprintf( o, "\n" );
				//fclose( o );
			}
		}
	}

	return 0;
}
Exemple #15
0
int main()
{
    
    Crypto* trans;
    Crypto* trans2;
    Crypto* trans3;
    Crypto* trans4;

    string org_msg;
    string enc_msg;
    string dec_msg;

    // - - - - - -
    // Ceasar
    // - - - - - -

    try
    {
        trans = Crypto::getCrypto("caesar", "5");
    }
    catch(InvalidKeyException e)
    {
        exit(-1);
    }

    org_msg = "Pull the brown book on the top shelf to activate";
    enc_msg = trans->encrypt(org_msg);
    dec_msg = trans->decrypt(enc_msg);

    cout << "Caesar: original message: \"" << org_msg << "\"" << endl;
    cout << "Caesar: encoded message: \"" << enc_msg << "\"" << endl;
    cout << "Caesar: decoded message: \"" << dec_msg << "\"" << endl << endl;

    delete trans;
    trans = 0;          // sets pointer to zero to avoid potential problems with dangling pointers

    // - - - - - -
    // Monoalpha
    // - - - - - -

    try
    {
        trans2 = Crypto::getCrypto("monoalpha", "QA Zwsxedcrfvtgbyhnujmikolp");
    }
    catch(InvalidKeyException e)
    {
        exit(-1);
    }

    org_msg = "Pull the brown book on the top shelf to activate";
    enc_msg = trans2->encrypt(org_msg);
    dec_msg = trans2->decrypt(enc_msg);

    cout << "Monoalpha: original message: \"" << org_msg << "\"" << endl;
    cout << "Monoalpha: encoded message: \"" << enc_msg << "\"" << endl;
    cout << "Monoalpha: decoded message: \"" << dec_msg << "\"" << endl << endl;

    delete trans2;
    trans2 = 0;

    // - - - - - -
    // Transposition
    // - - - - - -

    try
    {
        trans3 = Crypto::getCrypto("transposition", "240153");
    }
    catch(InvalidKeyException e)
    {
        exit(-1);
    }


    org_msg = "The password for today is deceptive";
    enc_msg = trans3->encrypt(org_msg);
    dec_msg = trans3->decrypt(enc_msg);

    cout << "Transposition: original message: \"" << org_msg << "\"" << endl;
    cout << "Transposition: encoded message: \"" << enc_msg << "\"" << endl;
    cout << "Transposition: decoded message: \"" << dec_msg << "\"" << endl << endl;

    string s1 = "test transposition with same object";
    string s2 = trans3->encrypt(s1);
    string s3 = trans3->decrypt(s2);

    cout << "Transposition: original message: \"" << s1 << "\"" << endl;
    cout << "Transposition: encoded message: \"" << s2 << "\"" << endl;
    cout << "Transposition: decoded message: \"" << s3 << "\"" << endl << endl;


    delete trans3;
    trans3 = 0;

    // - - - - - - - - 
    // Cencryption 
    // - - - - - - - -
    try
    {
        trans4 = Crypto::getCrypto("cencryption", "caesar,16,50;transposition,30142,50;caesar,21,30;");
    }
    catch(InvalidKeyException e)
    {
        exit(-1);
    }

    org_msg = "In this assignment you will develop a simple cryptographic library that combines three different encryption algorithms  The encryption algorithms are very old an well known and are not the strongest encryption schemes available today but are much more interesting to program  The algorithms can be used together to encrypt different parts of a single text message";
    enc_msg = trans4->encrypt(org_msg);
    dec_msg = trans4->decrypt(enc_msg);

    cout << "Cencryption: original message: \"" << org_msg << "\"" << endl;
    cout << "Cencryption: encoded message: \"" << enc_msg << "\"" << endl;
    cout << "Cencryption: decoded message: \"" << dec_msg << "\"" << endl << endl;

    delete trans4;
    trans4 = 0;


    return 0;
}
Exemple #16
0
DWORD WINAPI Slave::fileHandler(LPVOID p)
#endif
{
   Slave* self = ((Param2*)p)->serv_instance;
   string filename = self->m_strHomeDir + ((Param2*)p)->filename;
   string sname = ((Param2*)p)->filename;
   int key = ((Param2*)p)->key;
   int mode = ((Param2*)p)->mode;
   int transid = ((Param2*)p)->transid;
   string client_ip = ((Param2*)p)->client_ip;
   int client_port = ((Param2*)p)->client_port;
   unsigned char crypto_key[16];
   unsigned char crypto_iv[8];
   memcpy(crypto_key, ((Param2*)p)->crypto_key, 16);
   memcpy(crypto_iv, ((Param2*)p)->crypto_iv, 8);
   string master_ip = ((Param2*)p)->master_ip;
   int master_port = ((Param2*)p)->master_port;
   delete (Param2*)p;

   // uplink and downlink addresses for write, no need for read
   string src_ip = client_ip;
   int src_port = client_port;
   string dst_ip;
   int dst_port = -1;

   // IO permissions
   bool bRead = mode & 1;
   bool bWrite = mode & 2;
   bool trunc = mode & 4;
   bool bSecure = mode & 16;

   bool m_bChange = false;

   int last_timestamp = 0;

   self->m_SectorLog << LogStart(LogLevel::LEVEL_3) << "connecting to " << client_ip << " " << client_port << " " << filename << LogEnd();

   if ((!self->m_DataChn.isConnected(client_ip, client_port)) && (self->m_DataChn.connect(client_ip, client_port) < 0))
   {
      self->m_SectorLog << LogStart(LogLevel::LEVEL_2) << "failed to connect to file client " << client_ip << " " << client_port << " " << filename << LogEnd();

      // release transactions and file locks
      self->m_TransManager.updateSlave(transid, self->m_iSlaveID);
      self->m_pLocalFile->unlock(sname, key, mode);
      self->report(master_ip, master_port, transid, sname, +FileChangeType::FILE_UPDATE_NO);

      return NULL;
   }

   Crypto* encoder = NULL;
   Crypto* decoder = NULL;
   if (bSecure)
   {
      encoder = new Crypto;
      encoder->initEnc(crypto_key, crypto_iv);
      decoder = new Crypto;
      decoder->initDec(crypto_key, crypto_iv);      
   }

   //create a new directory or file in case it does not exist
   if (bWrite)
   {
      self->createDir(sname.substr(0, sname.rfind('/')));

      SNode s;
      if (LocalFS::stat(filename, s) < 0)
      {
         ofstream newfile(filename.c_str(), ios::out | ios::binary | ios::trunc);
         newfile.close();
      }
   }

   timeval t1, t2;
   gettimeofday(&t1, 0);
   int64_t rb = 0;
   int64_t wb = 0;

   WriteLog writelog;

   fstream fhandle;
   if (!trunc)
      fhandle.open(filename.c_str(), ios::in | ios::out | ios::binary);
   else
      fhandle.open(filename.c_str(), ios::in | ios::out | ios::binary | ios::trunc);

   // a file session is successful only if the client issue a close() request
   bool success = true;
   bool run = true;
   int32_t cmd = 0;

   while (run)
   {
      if (self->m_DataChn.recv4(client_ip, client_port, transid, cmd) < 0)
         break;

      switch (cmd)
      {
      case 1: // read
         {
            char* param = NULL;
            int tmp = 8 * 2;
            if (self->m_DataChn.recv(client_ip, client_port, transid, param, tmp) < 0)
            {
               success = false;
               break;
            }
            int64_t offset = *(int64_t*)param;
            int64_t size = *(int64_t*)(param + 8);
            delete [] param;

            int32_t response = bRead ? 0 : -1;
            if (fhandle.fail() || !success || !self->m_bDiskHealth || !self->m_bNetworkHealth)
               response = -1;

            if (self->m_DataChn.send(client_ip, client_port, transid, (char*)&response, 4) < 0)
               break;
            if (response == -1)
               break;

            if (self->m_DataChn.sendfile(client_ip, client_port, transid, fhandle, offset, size, encoder) < 0)
               success = false;
            else
               rb += size;

            // update total sent data size
            self->m_SlaveStat.updateIO(client_ip, param[1], (key == 0) ? +SlaveStat::SYS_OUT : +SlaveStat::CLI_OUT);

            break;
         }

      case 2: // write
         {
            if (!bWrite)
            {
               // if the client does not have write permission, disconnect it immediately
               success = false;
               break;
            }

            //receive offset and size information from uplink
            char* param = NULL;
            int tmp = 8 * 2;
            if (self->m_DataChn.recv(src_ip, src_port, transid, param, tmp) < 0)
               break;

            int64_t offset = *(int64_t*)param;
            int64_t size = *(int64_t*)(param + 8);
            delete [] param;

            // no secure transfer between two slaves
            Crypto* tmp_decoder = decoder;
            if ((client_ip != src_ip) || (client_port != src_port))
               tmp_decoder = NULL;

            bool io_status = (size > 0); 
            if (!io_status || (self->m_DataChn.recvfile(src_ip, src_port, transid, fhandle, offset, size, tmp_decoder) < size))
               io_status = false;

            //TODO: send incomplete write to next slave on chain, rather than -1

            if (dst_port > 0)
            {
               // send offset and size parameters
               char req[16];
               *(int64_t*)req = offset;
               if (io_status)
                  *(int64_t*)(req + 8) = size;
               else
                  *(int64_t*)(req + 8) = -1;
               self->m_DataChn.send(dst_ip, dst_port, transid, req, 16);

               // send the data to the next replica in the chain
               if (size > 0)
                  self->m_DataChn.sendfile(dst_ip, dst_port, transid, fhandle, offset, size);
            }

            if (!io_status)
               break;

            wb += size;

            // update total received data size
            self->m_SlaveStat.updateIO(src_ip, size, (key == 0) ? +SlaveStat::SYS_IN : +SlaveStat::CLI_IN);

            // update write log
            writelog.insert(offset, size);

            m_bChange = true;

            break;
         }

      case 3: // download
         {
            int64_t offset;
            if (self->m_DataChn.recv8(client_ip, client_port, transid, offset) < 0)
            {
               success = false;
               break;
            }

            int32_t response = bRead ? 0 : -1;
            if (fhandle.fail() || !success || !self->m_bDiskHealth || !self->m_bNetworkHealth)
               response = -1;
            if (self->m_DataChn.send(client_ip, client_port, transid, (char*)&response, 4) < 0)
               break;
            if (response == -1)
               break;

            fhandle.seekg(0, ios::end);
            int64_t size = (int64_t)(fhandle.tellg());
            fhandle.seekg(0, ios::beg);

            size -= offset;

            int64_t unit = 64000000; //send 64MB each time
            int64_t tosend = size;
            int64_t sent = 0;
            while (tosend > 0)
            {
               int64_t block = (tosend < unit) ? tosend : unit;
               if (self->m_DataChn.sendfile(client_ip, client_port, transid, fhandle, offset + sent, block, encoder) < 0)
               {
                  success = false;
                  break;
               }

               sent += block;
               tosend -= block;
            }

            rb += sent;

            // update total sent data size
            self->m_SlaveStat.updateIO(client_ip, size, (key == 0) ? +SlaveStat::SYS_OUT : +SlaveStat::CLI_OUT);

            break;
         }

      case 4: // upload
         {
            if (!bWrite)
            {
               // if the client does not have write permission, disconnect it immediately
               success = false;
               break;
            }

            int64_t offset = 0;
            int64_t size;
            if (self->m_DataChn.recv8(client_ip, client_port, transid, size) < 0)
            {
               success = false;
               break;
            }

            //TODO: check available size
            int32_t response = 0;
            if (fhandle.fail() || !success || !self->m_bDiskHealth || !self->m_bNetworkHealth)
               response = -1;
            if (self->m_DataChn.send(client_ip, client_port, transid, (char*)&response, 4) < 0)
               break;
            if (response == -1)
               break;

            int64_t unit = 64000000; //send 64MB each time
            int64_t torecv = size;
            int64_t recd = 0;

            // no secure transfer between two slaves
            Crypto* tmp_decoder = decoder;
            if ((client_ip != src_ip) || (client_port != src_port))
               tmp_decoder = NULL;

            while (torecv > 0)
            {
               int64_t block = (torecv < unit) ? torecv : unit;

               if (self->m_DataChn.recvfile(src_ip, src_port, transid, fhandle, offset + recd, block, tmp_decoder) < 0)
               {
                  success = false;
                  break;
               }

               if (dst_port > 0)
               {
                  // write to uplink for next replica in the chain
                  if (self->m_DataChn.sendfile(dst_ip, dst_port, transid, fhandle, offset + recd, block) < 0)
                     break;
               }

               recd += block;
               torecv -= block;
            }

            wb += recd;

            // update total received data size
            self->m_SlaveStat.updateIO(src_ip, size, (key == 0) ? +SlaveStat::SYS_IN : +SlaveStat::CLI_IN);

            // update write log
            writelog.insert(0, size);

            m_bChange = true;

            break;
         }

      case 5: // end session
         // the file has been successfully closed
         run = false;
         break;

      case 6: // read file path for local IO optimization
         self->m_DataChn.send(client_ip, client_port, transid, self->m_strHomeDir.c_str(), self->m_strHomeDir.length() + 1);
         break;

      case 7: // synchronize with the client, make sure write is correct
      {
         //TODO: merge all three recv() to one
         int32_t size = 0;
         if (self->m_DataChn.recv4(client_ip, client_port, transid, size) < 0)
            break;
         char* buf = NULL;
         if (self->m_DataChn.recv(client_ip, client_port, transid, buf, size) < 0)
            break;
         last_timestamp = 0;
         if (self->m_DataChn.recv4(client_ip, client_port, transid, last_timestamp) < 0)
            break;

         WriteLog log;
         log.deserialize(buf, size);
         delete [] buf;

         int32_t confirm = -1;
         if (writelog.compare(log))
            confirm = 1;

         writelog.clear();

         if (confirm > 0)
         {
            //synchronize timestamp
            utimbuf ut;
            ut.actime = last_timestamp;
            ut.modtime = last_timestamp;
            utime(filename.c_str(), &ut);
         }

         self->m_DataChn.send(client_ip, client_port, transid, (char*)&confirm, 4);

         break;
      }

      case 8: // specify up and down links
      {
         char* buf = NULL;
         int size = 136;
         if (self->m_DataChn.recv(client_ip, client_port, transid, buf, size) < 0)
            break;

         int32_t response = bWrite ? 0 : -1;
         if (fhandle.fail() || !success || !self->m_bDiskHealth || !self->m_bNetworkHealth)
            response = -1;
         if (self->m_DataChn.send(client_ip, client_port, transid, (char*)&response, 4) < 0)
            break;
         if (response == -1)
            break;

         src_ip = buf;
         src_port = *(int32_t*)(buf + 64);
         dst_ip = buf + 68;
         dst_port = *(int32_t*)(buf + 132);
         delete [] buf;

         if (src_port > 0)
         {
            // connect to uplink in the write chain
            if (!self->m_DataChn.isConnected(src_ip, src_port))
               self->m_DataChn.connect(src_ip, src_port);
         }
         else
         {
            // first node in the chain, read from client
            src_ip = client_ip;
            src_port = client_port;
         }
         
         if (dst_port > 0)
         {
            //connect downlink in the write chain
            if (!self->m_DataChn.isConnected(dst_ip, dst_port))
               self->m_DataChn.connect(dst_ip, dst_port);
         }

         break;
      }

      default:
         break;
      }
   }

   // close local file
   fhandle.close();

   // update final timestamp
   if (last_timestamp > 0)
   {
      utimbuf ut;
      ut.actime = last_timestamp;
      ut.modtime = last_timestamp;
      utime(filename.c_str(), &ut);
   }

   gettimeofday(&t2, 0);
   int duration = t2.tv_sec - t1.tv_sec;
   double avgRS = 0;
   double avgWS = 0;
   if (duration > 0)
   {
      avgRS = rb / duration * 8.0 / 1000000.0;
      avgWS = wb / duration * 8.0 / 1000000.0;
   }

   self->m_SectorLog << LogStart(LogLevel::LEVEL_3) << "file server closed " << src_ip << " " << src_port << " " << (long long)avgWS << " " << (long long)avgRS << LogEnd();

   // clear this transaction
   self->m_TransManager.updateSlave(transid, self->m_iSlaveID);

   // unlock the file
   // this must be done before the client is disconnected, otherwise if the client immediately re-open the file, the lock may not be released yet
   self->m_pLocalFile->unlock(sname, key, mode);

   // report to master the task is completed
   // this also must be done before the client is disconnected, otherwise client may not be able to immediately re-open the file as the master is not updated
   int change = m_bChange ? +FileChangeType::FILE_UPDATE_WRITE : +FileChangeType::FILE_UPDATE_NO;

   self->report(master_ip, master_port, transid, sname, change);

   if (bSecure)
   {
      encoder->release();
      delete encoder;
      decoder->release();
      delete decoder;
   }

   if (success)
      self->m_DataChn.send(client_ip, client_port, transid, (char*)&cmd, 4);
   else
      self->m_DataChn.sendError(client_ip, client_port, transid);

   return NULL;
}
//
// This function makes a polymorphic call to both the encryption
// and decryption functions, displaying the phrase both before
// and after each.
//
void  encryptAndDecrypt(Crypto  &msg)
{
	cout << "Original - " << msg.phrase() << endl;
	cout << "           Level = " << msg.encryptionLevel() << endl;
	cout << "   # Conversions = " << msg.numConversions() << endl;

	//
	// Encrypt
	//
	msg.encrypt();
	cout << " Encrypt - " << msg.phrase() << endl;
	cout << "           Level = " << msg.encryptionLevel() << endl;
	cout << "   # Conversions = " << msg.numConversions() << endl;

	//
	// Decyrpt
	//
	msg.decrypt();
	cout << " Decrypt - " << msg.phrase() << endl;
	cout << "           Level = " << msg.encryptionLevel() << endl;
	cout << "   # Conversions = " << msg.numConversions() << endl;
}