added crypto functions and msg sending/receiving for private distant chat

git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-GenericTunneling@6299 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2013-04-08 21:25:32 +00:00
parent cd2d702e44
commit e9a51455eb
6 changed files with 254 additions and 38 deletions

View File

@ -2233,7 +2233,9 @@ int RsServer::StartupRetroShare()
p3turtle *tr = new p3turtle(mLinkMgr,ftserver) ;
rsTurtle = tr ;
pqih -> addService(tr);
ftserver->connectToTurtleRouter(tr) ;
chatSrv->connectToTurtleRouter(tr) ;
pqih -> addService(ad);
pqih -> addService(msgSrv);

View File

@ -25,8 +25,10 @@
#include <math.h>
#include "util/rsdir.h"
#include "util/rsaes.h"
#include "util/rsrandom.h"
#include "util/rsstring.h"
#include "turtle/p3turtle.h"
#include "retroshare/rsiface.h"
#include "retroshare/rspeers.h"
#include "pqi/pqibin.h"
@ -55,15 +57,23 @@ static const time_t MIN_DELAY_BETWEEN_PUBLIC_LOBBY_REQ = 20 ; // don't ask fo
p3ChatService::p3ChatService(p3LinkMgr *lm, p3HistoryMgr *historyMgr)
:p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm) , mHistoryMgr(historyMgr)
{
addSerialType(new RsChatSerialiser());
_serializer = new RsChatSerialiser() ;
_own_avatar = NULL ;
_custom_status_string = "" ;
_time_shift_average = 0.0f ;
_default_nick_name = rsPeers->getPeerName(rsPeers->getOwnId());
_should_reset_lobby_counts = false ;
mTurtle = NULL ;
last_visible_lobby_info_request_time = 0 ;
addSerialType(_serializer) ;
}
void p3ChatService::connectToTurtleRouter(p3turtle *tr)
{
mTurtle = tr ;
tr->registerTunnelService(this) ;
}
int p3ChatService::tick()
@ -608,38 +618,41 @@ void p3ChatService::receiveChatQueue()
RsItem *item ;
while(NULL != (item=recvItem()))
{
handleIncomingItem(item) ;
}
void p3ChatService::handleIncomingItem(RsItem *item)
{
#ifdef CHAT_DEBUG
std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ;
std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ;
#endif
// RsChatMsgItems needs dynamic_cast, since they have derived siblings.
//
RsChatMsgItem *ci = dynamic_cast<RsChatMsgItem*>(item) ;
if(ci != NULL)
{
if(! handleRecvChatMsgItem(ci))
delete ci ;
// RsChatMsgItems needs dynamic_cast, since they have derived siblings.
//
RsChatMsgItem *ci = dynamic_cast<RsChatMsgItem*>(item) ;
if(ci != NULL)
{
if(! handleRecvChatMsgItem(ci))
delete ci ;
continue ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only.
}
switch(item->PacketSubType())
{
case RS_PKT_SUBTYPE_CHAT_STATUS: handleRecvChatStatusItem (dynamic_cast<RsChatStatusItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_AVATAR: handleRecvChatAvatarItem (dynamic_cast<RsChatAvatarItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE: handleRecvLobbyInvite (dynamic_cast<RsChatLobbyInviteItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE: handleConnectionChallenge (dynamic_cast<RsChatLobbyConnectChallengeItem*>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_EVENT: handleRecvChatLobbyEventItem (dynamic_cast<RsChatLobbyEventItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE: handleFriendUnsubscribeLobby (dynamic_cast<RsChatLobbyUnsubscribeItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST: handleRecvChatLobbyListRequest(dynamic_cast<RsChatLobbyListRequestItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST: handleRecvChatLobbyList (dynamic_cast<RsChatLobbyListItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_deprecated: handleRecvChatLobbyList (dynamic_cast<RsChatLobbyListItem_deprecated *>(item)) ; break ;
default:
std::cerr << "Unhandled item subtype " << item->PacketSubType() << " in p3ChatService: " << std::endl;
}
delete item ;
return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only.
}
switch(item->PacketSubType())
{
case RS_PKT_SUBTYPE_CHAT_STATUS: handleRecvChatStatusItem (dynamic_cast<RsChatStatusItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_AVATAR: handleRecvChatAvatarItem (dynamic_cast<RsChatAvatarItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE: handleRecvLobbyInvite (dynamic_cast<RsChatLobbyInviteItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_CHALLENGE: handleConnectionChallenge (dynamic_cast<RsChatLobbyConnectChallengeItem*>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_EVENT: handleRecvChatLobbyEventItem (dynamic_cast<RsChatLobbyEventItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_UNSUBSCRIBE: handleFriendUnsubscribeLobby (dynamic_cast<RsChatLobbyUnsubscribeItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST: handleRecvChatLobbyListRequest(dynamic_cast<RsChatLobbyListRequestItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST: handleRecvChatLobbyList (dynamic_cast<RsChatLobbyListItem *>(item)) ; break ;
case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_deprecated: handleRecvChatLobbyList (dynamic_cast<RsChatLobbyListItem_deprecated *>(item)) ; break ;
default:
std::cerr << "Unhandled item subtype " << item->PacketSubType() << " in p3ChatService: " << std::endl;
}
delete item ;
}
void p3ChatService::handleRecvChatLobbyListRequest(RsChatLobbyListRequestItem *clr)
@ -2737,4 +2750,146 @@ void p3ChatService::cleanLobbyCaches()
sendConnectionChallenge(*it) ;
}
bool p3ChatService::handleTunnelRequest(const std::string& hash,const std::string& peer_id,std::string& description_info_string)
{
std::map<TurtleFileHash,DistantChatInvite>::const_iterator it = _distant_chat_invites.find(hash) ;
std::cerr << "p3ChatService::handleTunnelRequest: received tunnel request for hash " << hash << std::endl;
if(it == _distant_chat_invites.end())
return false ;
std::cerr << "Responding ok." << std::endl;
return true ;
}
void p3ChatService::receiveTurtleData( RsTurtleGenericTunnelItem *gitem,const std::string& hash,
const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction)
{
std::cerr << "p3ChatService::receiveTurtleData(): Received turtle data. " << std::endl;
std::cerr << " hash = " << hash << std::endl;
std::cerr << " vpid = " << virtual_peer_id << std::endl;
std::cerr << " dir = " << virtual_peer_id << std::endl;
RsTurtleGenericDataItem *item = dynamic_cast<RsTurtleGenericDataItem*>(gitem) ;
if(item == NULL)
{
std::cerr << "(EE) item is not a data item. That is an error." << std::endl;
return ;
}
std::cerr << " size = " << item->data_size << std::endl;
std::cerr << " data = " << (void*)item->data_bytes << std::endl;
uint8_t aes_key[16] ;
{
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
std::map<std::string,DistantChatPeerInfo>::iterator it = _distant_chat_peers.find(virtual_peer_id) ;
if(it == _distant_chat_peers.end())
{
std::cerr << "(EE) item is not coming out of a registered tunnel. Weird. hash=" << hash << ", peer id = " << virtual_peer_id << std::endl;
return ;
}
it->second.last_contact = time(NULL) ;
memcpy(aes_key,it->second.aes_key,8) ;
}
// Call the AES crypto module
// - the IV is the first 8 bytes of item->data_bytes
if(item->data_size < 8)
{
std::cerr << "(EE) item encrypted data stream is too small: size = " << item->data_size << std::endl;
return ;
}
uint32_t decrypted_size ;
uint8_t *decrypted_data = new uint8_t[RsAES::get_buffer_size(item->data_size-8)];
if(!RsAES::aes_decrypt_8_16((uint8_t*)item->data_bytes+8,item->data_size-8,aes_key,(uint8_t*)item->data_bytes,decrypted_data,decrypted_size))
{
std::cerr << "(EE) packet decryption failed." << std::endl;
delete[] decrypted_data ;
return ;
}
std::cerr << "(II) Decrypted data: size=" << decrypted_size << std::endl;
// Now try deserialise the decrypted data to make an RsItem out of it.
//
RsItem *citem = _serializer->deserialise(decrypted_data,&decrypted_size) ;
delete[] decrypted_data ;
if(citem == NULL)
{
std::cerr << "(EE) item could not be de-serialized. That is an error." << std::endl;
return ;
}
// Setup the virtual peer to be the origin, and pass it on.
//
citem->PeerId(virtual_peer_id) ;
handleIncomingItem(citem) ; // Treats the item, and deletes it
}
void p3ChatService::sendTurtleData(RsChatItem *item, const std::string& virtual_peer_id)
{
uint32_t rssize = item->serial_size();
uint8_t *buff = new uint8_t[rssize] ;
if(!item->serialise(buff,rssize))
{
std::cerr << "(EE) p3ChatService::sendTurtleData(): Could not serialise item!" << std::endl;
delete[] buff ;
return ;
}
uint8_t aes_key[16] ;
{
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
std::map<std::string,DistantChatPeerInfo>::iterator it = _distant_chat_peers.find(virtual_peer_id) ;
if(it == _distant_chat_peers.end())
{
std::cerr << "(EE) item is not coming out of a registered tunnel. Weird. peer id = " << virtual_peer_id << std::endl;
delete[] buff ;
return ;
}
it->second.last_contact = time(NULL) ;
memcpy(aes_key,it->second.aes_key,8) ;
}
// Now encrypt this data using AES.
//
uint32_t encrypted_size ;
uint8_t *encrypted_data = new uint8_t[RsAES::get_buffer_size(rssize)];
uint64_t IV = RSRandom::random_u64() ; // make a random 8 bytes IV
if(!RsAES::aes_crypt_8_16(buff,rssize,aes_key,(uint8_t*)&IV,encrypted_data,encrypted_size))
{
std::cerr << "(EE) packet encryption failed." << std::endl;
delete[] encrypted_data ;
delete[] buff ;
return ;
}
delete[] buff ;
// make a TurtleGenericData item out of it:
//
RsTurtleGenericDataItem *gitem = new RsTurtleGenericDataItem ;
gitem->data_size = encrypted_size + 8 ;
gitem->data_bytes = malloc(gitem->data_size) ;
memcpy(gitem->data_bytes ,&IV,8) ;
memcpy(gitem->data_bytes+8,encrypted_data,encrypted_size) ;
delete[] encrypted_data ;
delete item ;
mTurtle->sendTurtleData(virtual_peer_id,gitem) ;
}

View File

@ -33,10 +33,13 @@
#include "serialiser/rsmsgitems.h"
#include "services/p3service.h"
#include "pgp/pgphandler.h"
#include "turtle/turtleclientservice.h"
#include "retroshare/rsmsgs.h"
class p3LinkMgr;
class p3HistoryMgr;
class p3turtle ;
//!The basic Chat service.
/**
@ -45,7 +48,7 @@ class p3HistoryMgr;
* This service uses rsnotify (callbacks librs clients (e.g. rs-gui))
* @see NotifyBase
*/
class p3ChatService: public p3Service, public p3Config, public pqiMonitor
class p3ChatService: public p3Service, public p3Config, public pqiMonitor, public RsTurtleClientService
{
public:
p3ChatService(p3LinkMgr *cm, p3HistoryMgr *historyMgr);
@ -191,6 +194,7 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
// Receive chat queue
void receiveChatQueue();
void handleIncomingItem(RsItem *); // called by the former, and turtle handler for incoming encrypted items
void initRsChatInfo(RsChatMsgItem *c, ChatInfo &i);
@ -289,9 +293,55 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor
std::map<std::string,ChatLobbyId> _lobby_ids ;
std::string _default_nick_name ;
float _time_shift_average ;
time_t last_lobby_challenge_time ; // prevents bruteforce attack
time_t last_lobby_challenge_time ; // prevents bruteforce attack
time_t last_visible_lobby_info_request_time ; // allows to ask for updates
bool _should_reset_lobby_counts ;
RsChatSerialiser *_serializer ;
// ===========================================================//
// Members related to anonymous distant chat. //
// ===========================================================//
struct DistantChatInvite
{
unsigned char aes_key[16] ;
time_t validity_time_stamp ;
std::string virtual_peer_id ;
};
struct DistantChatPeerInfo
{
time_t last_contact ; // used to send keep alive packets
unsigned char aes_key[16] ; // key to encrypt packets
};
// This map contains the ongoing invites. This is the list where to look to
// handle tunnel requests.
//
std::map<TurtleFileHash,DistantChatInvite> _distant_chat_invites ;
// This maps contains the current peers to talk to with distant chat.
//
std::map<std::string,DistantChatPeerInfo> _distant_chat_peers ;
// Creates the invite if the public key of the distant peer is available.
// Om success, stores the invite in the map above, so that we can respond to tunnel requests.
//
bool createDistantChatInvite(PGPIdType pgp_id,time_t time_of_validity,TurtleFileHash& hash) ;
// Overloaded from RsTurtleClientService
virtual bool handleTunnelRequest(const std::string& hash,const std::string& peer_id,std::string& description_info_string) ;
virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const std::string& hash,const std::string& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
// Utility functions
void cleanDistantChatInvites() ;
void sendTurtleData(RsChatItem *,const std::string& virtual_peer_id) ;
p3turtle *mTurtle ;
public:
void connectToTurtleRouter(p3turtle *) ;
};
class p3ChatService::StateStringInfo

View File

@ -84,7 +84,7 @@ int main(int argc,char *argv[])
unsigned char output_data[source_string.size() + 16] ;
uint32_t output_data_length = source_string.size() + 16 ;
CHECK(RsAes::aes_crypt_8_16( (const uint8_t*)source_string.c_str(),source_string.length(),key_data,salt,output_data,output_data_length)) ;
CHECK(RsAES::aes_crypt_8_16( (const uint8_t*)source_string.c_str(),source_string.length(),key_data,salt,output_data,output_data_length)) ;
std::cerr << "Round " << i << " salt=" ;
printHex(salt,8) ;
@ -95,7 +95,7 @@ int main(int argc,char *argv[])
unsigned char output_data2[output_data_length + 16] ;
uint32_t output_data_length2 = output_data_length + 16 ;
CHECK(RsAes::aes_decrypt_8_16(output_data,output_data_length,key_data,salt,output_data2,output_data_length2)) ;
CHECK(RsAES::aes_decrypt_8_16(output_data,output_data_length,key_data,salt,output_data2,output_data_length2)) ;
std::cerr << " output_length = " << output_data_length2 << ", decrypted string = " ;
printHex(output_data2,output_data_length2) ;

View File

@ -28,7 +28,12 @@
#include "rsaes.h"
bool RsAes::aes_crypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key_data[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length)
uint32_t RsAES::get_buffer_size(uint32_t n)
{
return n + AES_BLOCK_SIZE ;
}
bool RsAES::aes_crypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key_data[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length)
{
int nrounds = 5;
uint8_t key[32], iv[32];
@ -70,7 +75,7 @@ bool RsAes::aes_crypt_8_16(const uint8_t *input_data,uint32_t input_data_length,
return true;
}
bool RsAes::aes_decrypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key_data[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length)
bool RsAES::aes_decrypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key_data[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length)
{
int nrounds = 5;
uint8_t key[32], iv[32];

View File

@ -25,12 +25,12 @@
#include <stdint.h>
class RsAes
class RsAES
{
public:
// Crypt/decrypt data using a 16 bytes key and a 8 bytes salt.
//
// output_data allocation is left to the client. The size should be at least input_data_length+16 bytes.
// output_data allocation is left to the client. The size should be at least RsAES::get_buffer_size(input_data_length)
//
// Return value:
// true: encryption/decryption ok
@ -39,5 +39,9 @@ class RsAes
//
static bool aes_crypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length) ;
static bool aes_decrypt_8_16(const uint8_t *input_data,uint32_t input_data_length,uint8_t key[16],uint8_t salt[8],uint8_t *output_data,uint32_t& output_data_length) ;
// computes the safe buffer size to store encrypted/decrypted data for the given input stream size
//
static uint32_t get_buffer_size(uint32_t size) ;
};