mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
added code for single item encryption/decryption
This commit is contained in:
parent
08e4c90cc2
commit
6995212a8b
@ -34,7 +34,9 @@
|
||||
* #define GXS_SECURITY_DEBUG 1
|
||||
***/
|
||||
|
||||
static const uint32_t HEADER_MULTI_ENCRYPTION_FORMAT_v001 = 0xFACE;
|
||||
static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_HEADER = 0xFACE;
|
||||
static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_HEADER_SIZE = 2 ;
|
||||
static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_NUMBER_OF_KEYS_SIZE = 2 ;
|
||||
|
||||
static RsGxsId getRsaKeyFingerprint(RSA *pubkey)
|
||||
{
|
||||
@ -407,7 +409,7 @@ bool GxsSecurity::validateNxsMsg(const RsNxsMsg& msg, const RsTlvKeySignature& s
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
bool GxsSecurity::initEncryption(GxsSecurity::MultiEncryptionContext& encryption_context, const std::vector<RsTlvSecurityKey>& keys)
|
||||
{
|
||||
// prepare an array of encrypted keys ek and public keys puk
|
||||
@ -521,6 +523,7 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key)
|
||||
{
|
||||
@ -684,9 +687,6 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
|
||||
throw std::runtime_error("malloc error on encrypted keys") ;
|
||||
}
|
||||
|
||||
static const int HEADER_SIZE = 2 ;
|
||||
static const int NUMBER_OF_KEYS_SIZE = 2 ;
|
||||
|
||||
const EVP_CIPHER *cipher = EVP_aes_128_cbc();
|
||||
int cipher_block_size = EVP_CIPHER_block_size(cipher);
|
||||
|
||||
@ -699,7 +699,7 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
|
||||
for(uint32_t i=0;i<keys.size();++i)
|
||||
total_ek_size += eklen[i] + 1 ;
|
||||
|
||||
int max_outlen = HEADER_SIZE + NUMBER_OF_KEYS_SIZE + total_ek_size + EVP_MAX_IV_LENGTH + (inlen + cipher_block_size) ;
|
||||
int max_outlen = MULTI_ENCRYPTION_FORMAT_v001_HEADER_SIZE + MULTI_ENCRYPTION_FORMAT_v001_NUMBER_OF_KEYS_SIZE + total_ek_size + EVP_MAX_IV_LENGTH + (inlen + cipher_block_size) ;
|
||||
|
||||
// now assign memory to out accounting for data, and cipher block size, key length, and key length val
|
||||
out = (uint8_t*)rs_malloc(max_outlen);
|
||||
@ -711,8 +711,8 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
|
||||
|
||||
// header
|
||||
|
||||
out[out_offset++] = HEADER_MULTI_ENCRYPTION_FORMAT_v001 & 0xff ;
|
||||
out[out_offset++] = (HEADER_MULTI_ENCRYPTION_FORMAT_v001 >> 8) & 0xff ;
|
||||
out[out_offset++] = MULTI_ENCRYPTION_FORMAT_v001_HEADER & 0xff ;
|
||||
out[out_offset++] = (MULTI_ENCRYPTION_FORMAT_v001_HEADER >> 8) & 0xff ;
|
||||
|
||||
// number of keys
|
||||
|
||||
@ -776,6 +776,8 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
bool GxsSecurity::initDecryption(GxsSecurity::MultiEncryptionContext& encryption_context, const RsTlvSecurityKey& key,unsigned char *IV,uint32_t IV_size,unsigned char *encrypted_session_key,uint32_t encrypted_session_key_size)
|
||||
{
|
||||
// prepare an array of encrypted keys ek and public keys puk
|
||||
@ -861,6 +863,7 @@ bool GxsSecurity::decrypt(uint8_t *&out, uint32_t &outlen, const uint8_t *in, ui
|
||||
|
||||
return true ;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key)
|
||||
{
|
||||
@ -934,7 +937,7 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
|
||||
return false;
|
||||
}
|
||||
|
||||
if(inlen < in_offset)
|
||||
if(inlen < (uint32_t)in_offset)
|
||||
{
|
||||
std::cerr << "Severe error in " << __PRETTY_FUNCTION__ << ": cannot encrypt. " << std::endl;
|
||||
return false ;
|
||||
@ -966,7 +969,146 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in, uint32_t inlen, const std::vector<RsTlvSecurityKey>& keys)
|
||||
{
|
||||
// Decrypts (in,inlen) into (out,outlen) using one of the given RSA public keys, trying them all in a row.
|
||||
// The format of the encrypted data is:
|
||||
//
|
||||
// [--- ID ---|--- number of encrypted keys---| n * (--- Encrypted session key length ---|--- Encrypted session keys ---) |--- IV ---|---- Encrypted data ---]
|
||||
// 2 bytes 2 byte = n 1 byte = X X bytes EVP_MAX_IV_LENGTH Rest of packet
|
||||
//
|
||||
// This method can be used to decrypt multi-encrypted data, if passing he correct encrypted key block (corresponding to the given key)
|
||||
|
||||
#ifdef DISTRIB_DEBUG
|
||||
std::cerr << "GxsSecurity::decrypt() " << std::endl;
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
// check that the input block has a valid format.
|
||||
|
||||
uint32_t offset = 0 ;
|
||||
uint16_t format_id = in[offset] + (in[offset+1] << 8) ;
|
||||
|
||||
if(format_id != MULTI_ENCRYPTION_FORMAT_v001_HEADER)
|
||||
{
|
||||
std::cerr << "Unrecognised format in encrypted block. Header id = " << std::hex << format_id << std::dec << std::endl;
|
||||
throw std::runtime_error("Unrecognised format in encrypted block.") ;
|
||||
}
|
||||
offset += MULTI_ENCRYPTION_FORMAT_v001_HEADER_SIZE;
|
||||
|
||||
// read number of encrypted keys
|
||||
|
||||
uint32_t number_of_keys = in[offset] + (in[offset+1] << 8) ;
|
||||
offset += MULTI_ENCRYPTION_FORMAT_v001_NUMBER_OF_KEYS_SIZE;
|
||||
|
||||
// reach the actual data offset
|
||||
|
||||
uint32_t encrypted_block_offset = offset ;
|
||||
uint32_t encrypted_keys_offset = offset ;
|
||||
uint32_t encrypted_block_size = 0 ;
|
||||
|
||||
for(uint32_t i=0;i<number_of_keys;++i)
|
||||
{
|
||||
uint8_t s = in[encrypted_block_offset++] ;
|
||||
encrypted_block_offset += s ;
|
||||
|
||||
if(encrypted_block_offset >= inlen)
|
||||
throw std::runtime_error("Offset error") ;
|
||||
}
|
||||
|
||||
// read IV offset
|
||||
|
||||
uint32_t IV_offset = encrypted_block_offset ;
|
||||
encrypted_block_offset += EVP_MAX_IV_LENGTH ;
|
||||
|
||||
if(encrypted_block_offset >= inlen)
|
||||
throw std::runtime_error("Offset error") ;
|
||||
|
||||
encrypted_block_size = inlen - encrypted_block_offset ;
|
||||
std::cerr << " number of keys in envelop: " << number_of_keys << std::endl;
|
||||
std::cerr << " IV offset : " << IV_offset << std::endl;
|
||||
std::cerr << " encrypted block offset : " << encrypted_block_offset << std::endl;
|
||||
std::cerr << " encrypted block size : " << encrypted_block_size << std::endl;
|
||||
|
||||
// decrypt
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
bool succeed = false;
|
||||
|
||||
for(uint32_t j=0;j<keys.size() && !succeed;++j)
|
||||
{
|
||||
RSA *rsa_private = extractPrivateKey(keys[j]) ;
|
||||
EVP_PKEY *privateKey = NULL;
|
||||
|
||||
std::cerr << " trying key " << keys[j].keyId << std::endl;
|
||||
|
||||
if(rsa_private != NULL)
|
||||
{
|
||||
privateKey = EVP_PKEY_new();
|
||||
EVP_PKEY_assign_RSA(privateKey, rsa_private);
|
||||
}
|
||||
else
|
||||
{
|
||||
RSA_free(rsa_private) ;
|
||||
std::cerr << "(EE) Cannot extract private key from key Id " << keys[j].keyId << ". This is a bug. Non owned key?" << std::endl;
|
||||
continue ;
|
||||
}
|
||||
|
||||
uint32_t sff = encrypted_keys_offset ;
|
||||
|
||||
for(uint32_t i=0;i<number_of_keys && !succeed;++i)
|
||||
{
|
||||
succeed = EVP_OpenInit(&ctx, EVP_aes_128_cbc(), in+sff+1, in[sff], in+IV_offset, privateKey);
|
||||
|
||||
std::cerr << " encrypted key at offset " << sff << ": " << succeed << std::endl;
|
||||
|
||||
sff += 1 + in[sff] ;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(privateKey) ;
|
||||
}
|
||||
|
||||
if(!succeed)
|
||||
throw std::runtime_error("No matching key available.") ;
|
||||
|
||||
std::cerr << " now decrypting with the matching key." << std::endl;
|
||||
|
||||
out = (uint8_t*)rs_malloc(encrypted_block_size) ;
|
||||
|
||||
if(out == NULL)
|
||||
throw std::runtime_error("Memory allocation error") ;
|
||||
|
||||
int out_currOffset = 0 ;
|
||||
|
||||
if(!EVP_OpenUpdate(&ctx, (unsigned char*) out, &out_currOffset, (unsigned char*)in + encrypted_block_offset, encrypted_block_size))
|
||||
throw std::runtime_error("Decryption error in EVP_OpenUpdate") ;
|
||||
|
||||
outlen = out_currOffset;
|
||||
|
||||
if(!EVP_OpenFinal(&ctx, (unsigned char*)out + out_currOffset, &out_currOffset))
|
||||
throw std::runtime_error("Decryption error in EVP_OpenFinal") ;
|
||||
|
||||
outlen += out_currOffset;
|
||||
|
||||
std::cerr << " successfully decrypted block of size " << outlen << std::endl;
|
||||
return true;
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
// cleanup and return false
|
||||
|
||||
std::cerr << " (EE) error caught: " << e.what() << std::endl;
|
||||
if(out)
|
||||
{
|
||||
free(out) ;
|
||||
out = NULL ;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool GxsSecurity::validateNxsGrp(const RsNxsGrp& grp, const RsTlvKeySignature& sign, const RsTlvSecurityKey& key)
|
||||
{
|
||||
#ifdef GXS_SECURITY_DEBUG
|
||||
|
@ -112,7 +112,7 @@ class GxsSecurity
|
||||
*/
|
||||
static bool encrypt(uint8_t *&out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key) ;
|
||||
static bool encrypt(uint8_t *&out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const std::vector<RsTlvSecurityKey>& keys) ;
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
/*!
|
||||
* Encrypts/decrypt data using envelope encryption using the key pre-computed in the encryption context passed as
|
||||
* parameter.
|
||||
@ -126,6 +126,7 @@ class GxsSecurity
|
||||
*/
|
||||
static bool encrypt(uint8_t *&out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, MultiEncryptionContext& encryption_context) ;
|
||||
static bool decrypt(uint8_t *&out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, MultiEncryptionContext& encryption_context) ;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Decrypts data using evelope decryption (taken from open ssl's evp_sealinit )
|
||||
@ -137,6 +138,7 @@ class GxsSecurity
|
||||
* @return false if encryption failed
|
||||
*/
|
||||
static bool decrypt(uint8_t *&out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key) ;
|
||||
static bool decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in, uint32_t inlen, const std::vector<RsTlvSecurityKey>& keys);
|
||||
|
||||
/*!
|
||||
* uses grp signature to check if group has been
|
||||
|
@ -2141,7 +2141,7 @@ void RsGxsNetService::processTransactions()
|
||||
|
||||
// move to completed transactions
|
||||
|
||||
// try to decrypt, if needed. This function returns true if the transaction is not encrypted.
|
||||
// Try to decrypt the items that need to be decrypted. This function returns true if the transaction is not encrypted.
|
||||
|
||||
if(decryptTransaction(tr))
|
||||
{
|
||||
@ -3477,6 +3477,8 @@ bool RsGxsNetService::encryptTransaction(NxsTransaction *tr)
|
||||
#ifdef NXS_NET_DEBUG_7
|
||||
GXSNETDEBUG_P_ (peerId) << " Encrypting..." << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MULTI_ENCRYPTION_WITH_SESSION_KEY
|
||||
GxsSecurity::MultiEncryptionContext muctx ;
|
||||
GxsSecurity::initEncryption(muctx,recipient_keys);
|
||||
|
||||
@ -3552,6 +3554,46 @@ bool RsGxsNetService::encryptTransaction(NxsTransaction *tr)
|
||||
}
|
||||
|
||||
tr->mItems.push_front(session_key_item) ;
|
||||
#else
|
||||
std::list<RsNxsItem*> encrypted_items ;
|
||||
|
||||
for(std::list<RsNxsItem*>::const_iterator it(tr->mItems.begin());it!=tr->mItems.end();++it)
|
||||
{
|
||||
uint32_t size = (*it)->serial_size() ;
|
||||
RsTemporaryMemory tempmem( size ) ;
|
||||
|
||||
if(!(*it)->serialise(tempmem,size))
|
||||
{
|
||||
std::cerr << " (EE) Cannot serialise item. Something went wrong." << std::endl;
|
||||
continue ;
|
||||
}
|
||||
|
||||
unsigned char *encrypted_data = NULL ;
|
||||
uint32_t encrypted_len = 0 ;
|
||||
|
||||
if(!GxsSecurity::encrypt(encrypted_data, encrypted_len,tempmem,size,recipient_keys))
|
||||
{
|
||||
std::cerr << " (EE) Cannot multi-encrypt item. Something went wrong." << std::endl;
|
||||
continue ;
|
||||
}
|
||||
|
||||
RsNxsEncryptedDataItem *enc_item = new RsNxsEncryptedDataItem(mServType) ;
|
||||
|
||||
enc_item->aes_encrypted_data.bin_len = encrypted_len ;
|
||||
enc_item->aes_encrypted_data.bin_data = encrypted_data ;
|
||||
enc_item->transactionNumber = (*it)->transactionNumber ;
|
||||
enc_item->PeerId((*it)->PeerId()) ;
|
||||
|
||||
encrypted_items.push_back(enc_item) ;
|
||||
#ifdef NXS_NET_DEBUG_7
|
||||
GXSNETDEBUG_P_(peerId) << " encrypted item of size " << encrypted_len << std::endl;
|
||||
#endif
|
||||
}
|
||||
for(std::list<RsNxsItem*>::const_iterator it(tr->mItems.begin());it!=tr->mItems.end();++it)
|
||||
delete *it ;
|
||||
|
||||
tr->mItems = encrypted_items ;
|
||||
#endif
|
||||
|
||||
return true ;
|
||||
}
|
||||
@ -3564,6 +3606,7 @@ bool RsGxsNetService::decryptTransaction(NxsTransaction *tr)
|
||||
GXSNETDEBUG_P_(peerId) << " Circle Id: " << tr->destination_circle << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MULTI_ENCRYPTION_WITH_SESSION_KEY
|
||||
// 1 - Checks that the transaction is encrypted. It should contain
|
||||
// one packet with an encrypted session key for the group,
|
||||
// and as many encrypted data items as necessary.
|
||||
@ -3660,20 +3703,83 @@ bool RsGxsNetService::decryptTransaction(NxsTransaction *tr)
|
||||
|
||||
free(tempmem) ;
|
||||
}
|
||||
#else
|
||||
std::list<RsNxsItem*> decrypted_items ;
|
||||
std::vector<RsTlvSecurityKey> private_keys ;
|
||||
|
||||
// 4 - put back in transaction.
|
||||
// get all private keys. Normally we should look into the circle name and only supply the keys that we have
|
||||
|
||||
std::list<RsGxsId> own_keys ;
|
||||
|
||||
mGixs->getOwnIds(own_keys) ;
|
||||
|
||||
for(std::list<RsGxsId>::const_iterator it(own_keys.begin());it!=own_keys.end();++it)
|
||||
{
|
||||
RsTlvSecurityKey private_key ;
|
||||
|
||||
if(mGixs->getPrivateKey(*it,private_key))
|
||||
{
|
||||
std::cerr << "(EE) Cannot retrieve private key for ID " << *it << std::endl;
|
||||
return false ;
|
||||
}
|
||||
private_keys.push_back(private_key) ;
|
||||
std::cerr << " retrived private key " << *it << std::endl;
|
||||
}
|
||||
|
||||
for(std::list<RsNxsItem*>::iterator it(tr->mItems.begin());it!=tr->mItems.end();++it)
|
||||
{
|
||||
RsNxsEncryptedDataItem *encrypted_item = dynamic_cast<RsNxsEncryptedDataItem*>(*it) ;
|
||||
|
||||
if(encrypted_item == NULL)
|
||||
{
|
||||
std::cerr << " skipping unencrypted item..." << std::endl;
|
||||
continue ;
|
||||
}
|
||||
|
||||
// we do this only when something actually needs to be decrypted.
|
||||
|
||||
unsigned char *decrypted_mem = NULL;
|
||||
uint32_t decrypted_len =0;
|
||||
|
||||
std::cerr << " Trying to decrypt item..." ;
|
||||
|
||||
if(!GxsSecurity::decrypt(decrypted_mem,decrypted_len, (uint8_t*)encrypted_item->aes_encrypted_data.bin_data,encrypted_item->aes_encrypted_data.bin_len,private_keys))
|
||||
{
|
||||
std::cerr << "Failed! Cannot decrypt transaction. Giving up." << std::endl;
|
||||
return false ;
|
||||
}
|
||||
std::cerr << "Succeeded! deserialising..." << std::endl;
|
||||
|
||||
// deserialise the item
|
||||
|
||||
RsItem *ditem = RsNxsSerialiser(mServType).deserialise(decrypted_mem,&decrypted_len) ;
|
||||
|
||||
if(ditem == NULL)
|
||||
{
|
||||
std::cerr << " Cannot deserialise. Item encoding error!" << std::endl;
|
||||
return false ;
|
||||
}
|
||||
RsNxsItem *nxsitem = dynamic_cast<RsNxsItem*>(ditem) ;
|
||||
|
||||
if(nxsitem == NULL)
|
||||
{
|
||||
std::cerr << " Deserialised item is not an NxsItem. Weird. Dropping transaction." << std::endl;
|
||||
return false ;
|
||||
}
|
||||
|
||||
// replace the encrypted item with the clear one
|
||||
std::cerr << " Replacing the encrypted item with the clear one." << std::endl;
|
||||
|
||||
it = tr->mItems.erase(it) ;
|
||||
tr->mItems.insert(it,nxsitem) ;
|
||||
--it ; // this is to make sure the ++it in the for loop is not goign to skip the item just after the one being inserted
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NXS_NET_DEBUG_7
|
||||
GXSNETDEBUG_P_(peerId) << " Decryption successful: replacing items with clear items" << std::endl;
|
||||
#endif
|
||||
|
||||
for(std::list<RsNxsItem*>::const_iterator it(tr->mItems.begin());it!=tr->mItems.end();++it)
|
||||
delete *it ;
|
||||
|
||||
tr->mItems = decrypted_items ;
|
||||
|
||||
return true ;
|
||||
|
||||
}
|
||||
|
||||
void RsGxsNetService::cleanTransactionItems(NxsTransaction* tr) const
|
||||
|
Loading…
Reference in New Issue
Block a user