mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-02-17 21:34:10 -05:00
finished implementing decryption routines. Still needs fixing compilation
This commit is contained in:
parent
6626538cab
commit
1c12178874
@ -404,42 +404,30 @@ bool GxsSecurity::validateNxsMsg(const RsNxsMsg& msg, const RsTlvKeySignature& s
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key)
|
||||
bool GxsSecurity::initEncryption(GxsSecurity::MultiEncryptionContext& encryption_context, const std::list<RsTlvSecurityKey>& keys)
|
||||
{
|
||||
// encrypting for a single security key. This is a proxy function.
|
||||
|
||||
return encrypt(out,outlen,in,inlen,std::vector<RsTlvSecurityKey>(1,key)) ;
|
||||
}
|
||||
|
||||
#ifdef TODO
|
||||
bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const std::vector<RsTlvSecurityKey>& keys)
|
||||
{
|
||||
#ifdef DISTRIB_DEBUG
|
||||
std::cerr << "GxsSecurity::encrypt() " << std::endl;
|
||||
#endif
|
||||
|
||||
if(keys.empty())
|
||||
return false ;
|
||||
|
||||
// prepare an array of encrypted keys ek and public keys puk
|
||||
|
||||
unsigned char ** ek = new unsigned char *[keys.size()] ;
|
||||
EVP_PKEY **pubk = new EVP_PKEY *[keys.size()] ;
|
||||
int * ekl = new int [keys.size()] ;
|
||||
|
||||
memset(ek ,0,keys.size()*sizeof(unsigned char *)) ;
|
||||
memset(pubk,0,keys.size()*sizeof(EVP_PKEY *)) ;
|
||||
memset(ekl ,0,keys.size()*sizeof(int )) ;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
encryption_context.clear() ;
|
||||
|
||||
encryption_context.ek = new unsigned char *[keys.size()] ;
|
||||
encryption_context.ekl = new int [keys.size()] ;
|
||||
|
||||
EVP_PKEY **pubk = new EVP_PKEY *[keys.size()] ;
|
||||
memset(pubk,0,keys.size()*sizeof(EVP_PKEY *)) ;
|
||||
|
||||
memset(encryption_context.ek ,0,keys.size()*sizeof(unsigned char *)) ;
|
||||
memset(encryption_context.ekl ,0,keys.size()*sizeof(int )) ;
|
||||
|
||||
for(uint32_t i=0;i<keys.size();++i)
|
||||
{
|
||||
RSA *tmpkey = ::extractPublicKey(keys[i]) ;
|
||||
RSA *rsa_publish_pub = RSAPublicKey_dup(tmpkey) ;
|
||||
RSA_free(tmpkey) ;
|
||||
|
||||
if(rsa_publish_pub == NULL)
|
||||
if(rsa_publish_pub == NULL)
|
||||
throw std::runtime_error("Wrong key in input key table. Cannot extract public key.") ;
|
||||
|
||||
pubk[i] = EVP_PKEY_new();
|
||||
@ -447,30 +435,37 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
|
||||
|
||||
int max_evp_key_size = EVP_PKEY_size(pubk[i]);
|
||||
|
||||
ek [i] = (unsigned char*)malloc(max_evp_key_size);
|
||||
ekl[i] = max_evp_key_size ;
|
||||
|
||||
total_ekl += max_evp_key_size ;
|
||||
encryption_context.ek [i] = (unsigned char*)malloc(max_evp_key_size);
|
||||
encryption_context.ekl[i] = max_evp_key_size ;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
|
||||
unsigned char iv[EVP_MAX_IV_LENGTH];
|
||||
EVP_CIPHER_CTX_init(&encryption_context.ctx);
|
||||
|
||||
const EVP_CIPHER *cipher = EVP_aes_128_cbc();
|
||||
|
||||
// intialize context and send store encrypted cipher key in ek
|
||||
|
||||
if(!EVP_SealInit(&ctx, cipher, ek, ekl, iv, pubk, keys.size()))
|
||||
throw std::runtime_error("Error in EVP_SealInit. Cannot init encryption. Something's wrong.") ;
|
||||
|
||||
// now paste all encrypted keys into the output buffer
|
||||
|
||||
for(uint32_t i=0;i<keys.size();++i)
|
||||
{
|
||||
}
|
||||
|
||||
if(!EVP_SealInit(&encryption_context.ctx, cipher, encryption_context.ek, encryption_context.ekl, encryption_context.iv, pubk, keys.size()))
|
||||
throw std::runtime_error("Error in EVP_SealInit. Cannot init encryption. Something's wrong.") ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "(EE) cannot init encryption context: " << e.what << std::endl;
|
||||
encryption_context.clear() ;
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, GxsSecurity::MultiEncryptionContext& encryption_context)
|
||||
{
|
||||
// encrypting for a single security key. This is a proxy function.
|
||||
|
||||
out = NULL ;
|
||||
|
||||
try
|
||||
{
|
||||
int eklen, net_ekl;
|
||||
int out_currOffset = 0;
|
||||
int out_offset = 0;
|
||||
@ -478,74 +473,49 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
|
||||
int size_net_ekl = sizeof(net_ekl);
|
||||
|
||||
int cipher_block_size = EVP_CIPHER_block_size(cipher);
|
||||
int max_outlen = inlen + cipher_block_size + EVP_MAX_IV_LENGTH + max_evp_key_size + size_net_ekl;
|
||||
|
||||
int max_outlen = 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*)malloc(inlen + cipher_block_size + size_net_ekl + eklen + EVP_MAX_IV_LENGTH);
|
||||
out = (uint8_t*)malloc(max_outlen) ;
|
||||
|
||||
if(out == NULL)
|
||||
{
|
||||
std::cerr << "Malloc error for size " << inlen + cipher_block_size + size_net_ekl + eklen + EVP_MAX_IV_LENGTH << std::endl;
|
||||
throw std::runtime_error("GxsSecurity::encrypt(): cannot allocate memory") ;
|
||||
}
|
||||
|
||||
net_ekl = htonl(eklen);
|
||||
memcpy((unsigned char*)out + out_offset, &net_ekl, size_net_ekl);
|
||||
out_offset += size_net_ekl;
|
||||
|
||||
memcpy((unsigned char*)out + out_offset, ek, eklen);
|
||||
out_offset += eklen;
|
||||
|
||||
memcpy((unsigned char*)out + out_offset, iv, EVP_MAX_IV_LENGTH);
|
||||
out_offset += EVP_MAX_IV_LENGTH;
|
||||
|
||||
// now encrypt actual data
|
||||
if(!EVP_SealUpdate(&ctx, (unsigned char*) out + out_offset, &out_currOffset, (unsigned char*) in, inlen))
|
||||
{
|
||||
free(out) ;
|
||||
out = NULL ;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!EVP_SealUpdate(&encryption_context.ctx, (unsigned char*)out, &out_currOffset, (unsigned char*) in, inlen))
|
||||
throw std::runtime_error("(EE) EVP_SealUpdate failed. Cannot encrypt.") ;
|
||||
|
||||
// move along to partial block space
|
||||
out_offset += out_currOffset;
|
||||
out_currOffset = 0 ;
|
||||
|
||||
// add padding
|
||||
if(!EVP_SealFinal(&ctx, (unsigned char*) out + out_offset, &out_currOffset))
|
||||
{
|
||||
free(out) ;
|
||||
out = NULL ;
|
||||
return false;
|
||||
}
|
||||
if(!EVP_SealFinal(&encryption_context.ctx, (unsigned char*)&out[out_offset], &out_currOffset))
|
||||
throw std::runtime_error("(EE) EVP_SealFinal failed. Cannot encrypt.") ;
|
||||
|
||||
// move to end
|
||||
out_offset += out_currOffset;
|
||||
|
||||
// make sure offset has not gone passed valid memory bounds
|
||||
if(out_offset > max_outlen)
|
||||
{
|
||||
free(out) ;
|
||||
out = NULL ;
|
||||
return false;
|
||||
}
|
||||
|
||||
// free encrypted key data
|
||||
free(ek);
|
||||
throw std::runtime_error("(EE) GxsSecurity::encrypt(): exceeded memory bounds! This is a serious bug.") ;
|
||||
|
||||
outlen = out_offset;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "(EE) GxsSecurity::encrypt(): ERROR: " << e.what() << std::endl;
|
||||
return false ;
|
||||
if(out)
|
||||
free(out) ;
|
||||
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GxsSecurity::encrypt_single(uint8_t *& out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key)
|
||||
bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key)
|
||||
{
|
||||
#ifdef DISTRIB_DEBUG
|
||||
std::cerr << "GxsSecurity::encrypt() " << std::endl;
|
||||
@ -650,6 +620,91 @@ bool GxsSecurity::encrypt_single(uint8_t *& out, uint32_t &outlen, const uint8_t
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
try
|
||||
{
|
||||
encryption_context.clear() ;
|
||||
|
||||
encryption_context.ek = new unsigned char *[1] ;
|
||||
encryption_context.ekl = new int [1] ;
|
||||
|
||||
RSA *rsa_publish = extractPrivateKey(key) ;
|
||||
|
||||
if(rsa_publish == NULL)
|
||||
{
|
||||
#ifdef DISTRIB_DEBUG
|
||||
std::cerr << "GxsSecurity(): Could not generate publish key " << grpId
|
||||
<< std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
EVP_PKEY *privateKey = EVP_PKEY_new();
|
||||
EVP_PKEY_assign_RSA(privateKey, rsa_publish);
|
||||
|
||||
encryption_context.ek[0] = (unsigned char*)malloc(EVP_PKEY_size(privateKey));
|
||||
encryption_context.ekl[0] = encrypted_session_key_size ;
|
||||
|
||||
memcpy(encryption_context.ek[0],encrypted_session_key,encrypted_session_key_size) ;
|
||||
|
||||
EVP_CIPHER_CTX_init(&encryption_context.ctx);
|
||||
|
||||
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
|
||||
|
||||
if(!EVP_OpenInit(&encryption_context.ctx, cipher, encryption_context.ek[0], encryption_context.ekl[0], IV, privateKey))
|
||||
{
|
||||
std::cerr << "(EE) Cannot decrypt data. Most likely reason: private GXS key is missing." << std::endl;
|
||||
encryption_context.clear() ;
|
||||
return false;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "(EE) cannot init decryption context: " << e.what << std::endl;
|
||||
encryption_context.clear() ;
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
bool GxsSecurity::decrypt(uint8_t *&out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, MultiEncryptionContext& encryption_context)
|
||||
{
|
||||
out = (uint8_t*)malloc(inlen); // this is conservative
|
||||
|
||||
if(out == NULL)
|
||||
{
|
||||
std::cerr << "gxssecurity::decrypt(): cannot allocate memory of size " << inlen << " to decrypt data." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int out_currOffset = 0 ;
|
||||
|
||||
if(!EVP_OpenUpdate(&encryption_context.ctx, (unsigned char*) out, &out_currOffset, (unsigned char*)in, inlen))
|
||||
{
|
||||
std::cerr << "(EE) EVP_OpenUpdate failed! Decryption context is probably not inited correctly" << std::endl;
|
||||
free(out) ;
|
||||
out = NULL ;
|
||||
outlen=0 ;
|
||||
return false;
|
||||
}
|
||||
|
||||
outlen = out_currOffset;
|
||||
|
||||
if(!EVP_OpenFinal(&ctx, (unsigned char*)out + out_currOffset, &out_currOffset))
|
||||
{
|
||||
free(out) ;
|
||||
out = NULL ;
|
||||
outlen=0 ;
|
||||
return false;
|
||||
}
|
||||
|
||||
outlen += out_currOffset;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key)
|
||||
{
|
||||
@ -707,7 +762,11 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
|
||||
|
||||
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
|
||||
|
||||
if(!EVP_OpenInit(&ctx, cipher, ek, eklen, iv, privateKey)) return false;
|
||||
if(!EVP_OpenInit(&ctx, cipher, ek, eklen, iv, privateKey))
|
||||
{
|
||||
std::cerr << "(EE) Cannot decrypt data. Most likely reason: private GXS key is missing." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(inlen < in_offset)
|
||||
{
|
||||
|
@ -42,6 +42,36 @@
|
||||
class GxsSecurity
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief The MultiEncryptionContext struct
|
||||
*
|
||||
* This structure is used to store encryption keys generated when encrypting for multiple keys at once, so that
|
||||
* the client doesn't need to know about all the libcrypto variables involved.
|
||||
* Typically, the client will first ask to init a MultiEncryptionContext by providing several GXS ids,
|
||||
* and then pass the structure as a parameter to encrypt some data with the same key.
|
||||
*/
|
||||
class MultiEncryptionContext
|
||||
{
|
||||
public:
|
||||
MultiEncryptionContext() { ekl = NULL; ek=NULL; nk=0 ; }
|
||||
~MultiEncryptionContext() { clear() ;}
|
||||
|
||||
void clear() ;
|
||||
|
||||
// The functions below give access to the encrypted symmetric key to be used.
|
||||
//
|
||||
int n_encrypted_keys() const ;
|
||||
RsGxsId encrypted_key_id (int i) ;
|
||||
unsigned char *encrypted_key_data(int i) ;
|
||||
int encrypted_key_size(int i) ;
|
||||
|
||||
protected:
|
||||
int *ekl ; // array of encrypted keys length
|
||||
unsigned char **ek ; // array of encrypted keys
|
||||
int nk ; // number of encrypted keys
|
||||
EVP_CIPHER_CTX ctx; // EVP encryption context
|
||||
unsigned char iv[EVP_MAX_IV_LENGTH]; // initialization vector of the cipher.
|
||||
};
|
||||
/*!
|
||||
* Extracts a public key from a private key.
|
||||
*/
|
||||
@ -65,6 +95,16 @@ class GxsSecurity
|
||||
*/
|
||||
static bool encrypt(uint8_t *&out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const RsTlvSecurityKey& key) ;
|
||||
|
||||
/*!
|
||||
* Encrypts/decrypt data using envelope encryption using the key pre-computed in the encryption context passed as
|
||||
* parameter.
|
||||
*/
|
||||
static bool initEncryption(MultiEncryptionContext& encryption_context, const std::list<RsTlvSecurityKey> &keys) ;
|
||||
static bool initDecryption(MultiEncryptionContext& encryption_context, const RsTlvSecurityKey& key, unsigned char *IV, uint32_t IV_size, unsigned char *encrypted_session_key, uint32_t encrypted_session_key_size) ;
|
||||
|
||||
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) ;
|
||||
|
||||
/**
|
||||
* Decrypts data using evelope decryption (taken from open ssl's evp_sealinit )
|
||||
* only full publish key holders can decrypt data for a group
|
||||
|
@ -2663,21 +2663,94 @@ bool RsGxsNetService::encryptTransaction(NxsTransaction *tr)
|
||||
delete *it ;
|
||||
|
||||
tr->mItems = encrypted_items ;
|
||||
|
||||
// 5 - make session key item and push it front.
|
||||
|
||||
RsNxsSessionKeyItem *session_key_item = new RsNxsSessionKeyItem() ;
|
||||
|
||||
memcpy(session_key_item->initialization_vector,muctx.IV,EVP_MAX_IV_LENGTH) ;
|
||||
|
||||
for(int i=0;i<muctx->n_encrypted_keys();++i)
|
||||
{
|
||||
std::cerr << " addign session key for ID " << muctx.encrypted_key_id(i) << std::endl;
|
||||
RsTlvBinaryData data ;
|
||||
|
||||
data.setBinData(muctx.encrypted_key_data(i), muctx.encrypted_key_size(i)) ;
|
||||
|
||||
session_key_item->encrypted_session_keys[muctx.encrypted_key_id(i)] = data ;
|
||||
}
|
||||
|
||||
tr->mItems.push_front(session_key_item) ;
|
||||
}
|
||||
|
||||
bool RsGxsNetService::decryptTransaction(NxsTransaction *tr)
|
||||
{
|
||||
std::cerr << "RsGxsNetService::decryptTransaction()" << std::endl;
|
||||
std::cerr << " Circle Id: " << tr->destination_circle << std::endl;
|
||||
|
||||
// 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.
|
||||
|
||||
RsNxsSessionKeyItem *esk = NULL;
|
||||
|
||||
for(std::list<RsNxsItem*>::const_iterator it(tr->mItems.begin());it!=tr->mItems.end();++it)
|
||||
if(NULL != (esk = dynamic_cast<RsNxsSessionKeyItem*>(*it)))
|
||||
break ;
|
||||
|
||||
if(esk == NULL)
|
||||
{
|
||||
std::cerr << " (II) nothing to decrypt. No session key packet in this transaction." << std::endl;
|
||||
return false ;
|
||||
}
|
||||
// 2 - Try to decrypt the session key. If not, return false. That probably means
|
||||
// we don't own that identity.
|
||||
|
||||
GxsSecurity::MultiEncryptionContext muctx ;
|
||||
|
||||
if(!GxsSecurity::initDecryption(muctx,key,esk.initialization_vector.bin_data,esk.initialization_vector.bin_len,ek.bin_data,ek.bin_len))
|
||||
{
|
||||
std::cerr << " (EE) cannot decrypt transaction. initDecryption() failed." << std::endl;
|
||||
return false ;
|
||||
}
|
||||
|
||||
// 3 - Using session key, decrypt all packets, by calling GXSSecurity.
|
||||
|
||||
// 4 - Deserialise packets from the decrypted data and restore the clear transaction.
|
||||
std::list<RsNxsItem*> decrypted_items ;
|
||||
RsNxsEncryptedDataItem encrypted_item ;
|
||||
RsNxsSerialiser serial ;
|
||||
|
||||
for(std::list<RsNxsItem*>::const_iterator it(tr->mItems.begin());it!=tr->mItems.end();++it)
|
||||
if(NULL != (encrypted_item = dynamic_cast<RsNxsEncryptedDataItem*>(*it)))
|
||||
{
|
||||
unsigned char *tempmem;
|
||||
uint32_t tempmemsize ;
|
||||
|
||||
if(!GxsSecurity::decrypt(muctx,tempmem,tempmemsize,encrypted_item->aes_encrypted_data.bin_data, encrypted_item.aes_encrypted_data.bin_len))
|
||||
{
|
||||
std::cerr << " (EE) Cannot decrypt item. Something went wrong. Skipping this item." << std::endl;
|
||||
continue ;
|
||||
}
|
||||
|
||||
RsNxsItem *item = serial.deserialise(tempmem,tempmemsize) ;
|
||||
|
||||
std::cerr << " Decrypted an item of type " << std::hex << item->getType() << std::dec << std::endl;
|
||||
|
||||
decrypted_items.push_back(item) ;
|
||||
|
||||
free(tempmem) ;
|
||||
}
|
||||
|
||||
// 4 - put back in transaction.
|
||||
|
||||
std::cerr << " replacing items with clear items" << std::endl;
|
||||
|
||||
for(std::list<RsNxsItem*>::const_iterator it(tr->mItems.begin());it!=tr->mItems.end();++it)
|
||||
delete *it ;
|
||||
|
||||
tr->mItems = encrypted_items ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
void RsGxsNetService::cleanTransactionItems(NxsTransaction* tr) const
|
||||
|
@ -239,7 +239,8 @@ public:
|
||||
|
||||
/// Session key encrypted for the whole group
|
||||
///
|
||||
RsTlvBinaryData encrypted_key_data ;
|
||||
RsTlvBinaryData initialisation_vector ;
|
||||
std::map<RsGxsId, RsTlvBinaryData> encrypted_session_keys;
|
||||
};
|
||||
/*!
|
||||
* Use to send to peer list of grps
|
||||
|
@ -53,6 +53,7 @@ virtual bool SetTlv(void *data, uint32_t size, uint32_t *offset) const;
|
||||
virtual bool GetTlv(void *data, uint32_t size, uint32_t *offset);
|
||||
virtual std::ostream &print(std::ostream &out, uint16_t indent) const; /*! Error/Debug util function */
|
||||
|
||||
// mallocs the necessary size, and copies data into the allocated buffer in bin_data
|
||||
bool setBinData(const void *data, uint32_t size);
|
||||
|
||||
uint16_t tlvtype; /// set/checked against TLV input
|
||||
|
Loading…
x
Reference in New Issue
Block a user