added code for single item encryption/decryption

This commit is contained in:
csoler 2016-02-18 21:30:52 -05:00
parent 08e4c90cc2
commit 6995212a8b
3 changed files with 270 additions and 20 deletions

View File

@ -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

View File

@ -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

View File

@ -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