IBR-DTNSuite  0.8
ibrdtn/ibrdtn/security/PayloadConfidentialBlock.cpp
Go to the documentation of this file.
00001 #include "ibrdtn/security/PayloadConfidentialBlock.h"
00002 #include "ibrdtn/security/PayloadIntegrityBlock.h"
00003 #include "ibrdtn/data/Bundle.h"
00004 #include "ibrdtn/data/SDNV.h"
00005 
00006 #include <openssl/err.h>
00007 #include <openssl/rsa.h>
00008 #include <ibrcommon/thread/MutexLock.h>
00009 #include <ibrcommon/Logger.h>
00010 
00011 #include <stdint.h>
00012 #include <typeinfo>
00013 
00014 #ifdef __DEVELOPMENT_ASSERTIONS__
00015 #include <cassert>
00016 #endif
00017 
00018 namespace dtn
00019 {
00020         namespace security
00021         {
00022                 dtn::data::Block* PayloadConfidentialBlock::Factory::create()
00023                 {
00024                         return new PayloadConfidentialBlock();
00025                 }
00026 
00027                 PayloadConfidentialBlock::PayloadConfidentialBlock()
00028                 : SecurityBlock(PAYLOAD_CONFIDENTIAL_BLOCK, PCB_RSA_AES128_PAYLOAD_PIB_PCB)
00029                 {
00030                 }
00031 
00032                 PayloadConfidentialBlock::~PayloadConfidentialBlock()
00033                 {
00034                 }
00035 
00036                 void PayloadConfidentialBlock::encrypt(dtn::data::Bundle& bundle, const dtn::security::SecurityKey &long_key, const dtn::data::EID& source)
00037                 {
00038                         // contains the random salt
00039                         u_int32_t salt;
00040 
00041                         // contains the random key
00042                         unsigned char ephemeral_key[ibrcommon::AES128Stream::key_size_in_bytes];
00043 
00044                         unsigned char iv[ibrcommon::AES128Stream::iv_len];
00045                         unsigned char tag[ibrcommon::AES128Stream::tag_len];
00046 
00047                         // get all PCBs
00048                         const std::list<const PayloadConfidentialBlock* > pcbs = bundle.getBlocks<PayloadConfidentialBlock>();
00049 
00050                         // get all PIBs
00051                         const std::list<const PayloadIntegrityBlock* > pibs = bundle.getBlocks<PayloadIntegrityBlock>();
00052 
00053                         // create a new payload confidential block
00054                         PayloadConfidentialBlock& pcb = bundle.push_front<PayloadConfidentialBlock>();
00055 
00056                         // create a random salt and key
00057                         createSaltAndKey(salt, ephemeral_key, ibrcommon::AES128Stream::key_size_in_bytes);
00058 
00059                         // encrypt payload - BEGIN
00060                         dtn::data::PayloadBlock& plb = bundle.getBlock<dtn::data::PayloadBlock>();
00061                         ibrcommon::BLOB::Reference blobref = plb.getBLOB();
00062 
00063                         {
00064                                 ibrcommon::BLOB::iostream stream = blobref.iostream();
00065                                 ibrcommon::AES128Stream aes_stream(ibrcommon::CipherStream::CIPHER_ENCRYPT, *stream, ephemeral_key, salt);
00066 
00067                                 // encrypt in place
00068                                 ((ibrcommon::CipherStream&)aes_stream).encrypt(*stream);
00069 
00070                                 // check if this is a fragment
00071                                 if (bundle.get(dtn::data::PrimaryBlock::FRAGMENT))
00072                                 {
00073                                         // ... and set the corresponding cipher suit params
00074                                         addFragmentRange(pcb._ciphersuite_params, bundle._fragmentoffset, stream.size());
00075                                 }
00076 
00077                                 // get the IV
00078                                 aes_stream.getIV(iv);
00079 
00080                                 // get the tag
00081                                 aes_stream.getTag(tag);
00082                         }
00083                         // encrypt payload - END
00084 
00085                         // set the source and destination address of the new block
00086                         if (source != bundle._source.getNode()) pcb.setSecuritySource( source );
00087                         if (long_key.reference != bundle._destination.getNode()) pcb.setSecurityDestination( long_key.reference );
00088 
00089                         // set replicate in every fragment to true
00090                         pcb.set(REPLICATE_IN_EVERY_FRAGMENT, true);
00091 
00092                         // store encypted key, tag, iv and salt
00093                         addSalt(pcb._ciphersuite_params, salt);
00094 
00095                         // get the RSA key
00096                         RSA *rsa_key = long_key.getRSA();
00097 
00098                         // encrypt the random key and add it to the ciphersuite params
00099                         addKey(pcb._ciphersuite_params, ephemeral_key, ibrcommon::AES128Stream::key_size_in_bytes, rsa_key);
00100 
00101                         // free the RSA key
00102                         long_key.free(rsa_key);
00103 
00104                         pcb._ciphersuite_params.set(SecurityBlock::initialization_vector, iv, ibrcommon::AES128Stream::iv_len);
00105                         pcb._ciphersuite_flags |= SecurityBlock::CONTAINS_CIPHERSUITE_PARAMS;
00106 
00107                         pcb._security_result.set(SecurityBlock::PCB_integrity_check_value, tag, ibrcommon::AES128Stream::tag_len);
00108                         pcb._ciphersuite_flags |= SecurityBlock::CONTAINS_SECURITY_RESULT;
00109 
00110                         // create correlator
00111                         u_int64_t correlator = createCorrelatorValue(bundle);
00112 
00113                         if (pcbs.size() > 0 || pibs.size() > 0)
00114                                 pcb.setCorrelator(correlator);
00115 
00116                         // encrypt PCBs and PIBs
00117                         for (std::list<const PayloadConfidentialBlock*>::const_iterator it = pcbs.begin(); it != pcbs.end(); it++)
00118                                 SecurityBlock::encryptBlock<PayloadConfidentialBlock>(bundle, (dtn::data::Block&)**it, salt, ephemeral_key).setCorrelator(correlator);
00119 
00120                         for (std::list<const PayloadIntegrityBlock*>::const_iterator it = pibs.begin(); it != pibs.end(); it++)
00121                                 SecurityBlock::encryptBlock<PayloadConfidentialBlock>(bundle, (dtn::data::Block&)**it, salt, ephemeral_key).setCorrelator(correlator);
00122                 }
00123 
00124                 void PayloadConfidentialBlock::decrypt(dtn::data::Bundle& bundle, const dtn::security::SecurityKey &long_key)
00125                 {
00126                         // list of block to delete if the process is successful
00127                         std::list<const dtn::data::Block*> erasure_list;
00128                         
00129                         // load the RSA key
00130                         RSA *rsa_key = long_key.getRSA();
00131 
00132                         try {
00133                                 // array for the current symmetric AES key
00134                                 unsigned char key[ibrcommon::AES128Stream::key_size_in_bytes];
00135 
00136                                 // correlator of the first PCB
00137                                 uint64_t correlator = 0;
00138                                 bool decrypt_related = false;
00139 
00140                                 // get all blocks of this bundle
00141                                 const std::list<const dtn::data::Block*> blocks = bundle.getBlocks();
00142 
00143                                 // iterate through all blocks
00144                                 for (std::list<const dtn::data::Block* >::const_iterator it = blocks.begin(); it != blocks.end(); it++)
00145                                 {
00146                                         try {
00147                                                 dynamic_cast<const PayloadIntegrityBlock&>(**it);
00148 
00149                                                 // add this block to the erasure list for later deletion
00150                                                 erasure_list.push_back(*it);
00151                                         } catch (const std::bad_cast&) { };
00152 
00153                                         try {
00154                                                 const PayloadConfidentialBlock &pcb = dynamic_cast<const PayloadConfidentialBlock&>(**it);
00155 
00156                                                 // get salt and key
00157                                                 u_int32_t salt = getSalt(pcb._ciphersuite_params);
00158 
00159                                                 // decrypt related blocks
00160                                                 if (decrypt_related)
00161                                                 {
00162                                                         // try to decrypt the block
00163                                                         try {
00164                                                                 decryptBlock(bundle, (dtn::security::SecurityBlock&)**it, salt, key);
00165 
00166                                                                 // success! add this block to the erasue list
00167                                                                 erasure_list.push_back(*it);
00168                                                         } catch (const ibrcommon::Exception&) {
00169                                                                 IBRCOMMON_LOGGER(critical) << "tag verfication failed, reversing decryption..." << IBRCOMMON_LOGGER_ENDL;
00170                                                                 decryptBlock(bundle, (dtn::security::SecurityBlock&)**it, salt, key);
00171 
00172                                                                 // abort the decryption and discard the bundle?
00173                                                                 throw ibrcommon::Exception("decrypt of correlated block reversed, tag verfication failed");
00174                                                         }
00175                                                 }
00176                                                 // if security destination does match the key, then try to decrypt the payload
00177                                                 else if (pcb.isSecurityDestination(bundle, long_key.reference) &&
00178                                                         (pcb._ciphersuite_id == SecurityBlock::PCB_RSA_AES128_PAYLOAD_PIB_PCB))
00179                                                 {
00180                                                         // try to decrypt the symmetric AES key
00181                                                         if (!getKey(pcb._ciphersuite_params, key, ibrcommon::AES128Stream::key_size_in_bytes, rsa_key))
00182                                                         {
00183                                                                 IBRCOMMON_LOGGER(critical) << "could not get symmetric key decrypted" << IBRCOMMON_LOGGER_ENDL;
00184                                                                 throw ibrcommon::Exception("decrypt failed - could not get symmetric key decrypted");
00185                                                         }
00186 
00187                                                         // try to decrypt the payload
00188                                                         if (!decryptPayload(bundle, key, salt))
00189                                                         {
00190                                                                 // reverse decryption
00191                                                                 IBRCOMMON_LOGGER(critical) << "tag verfication failed, reversing decryption..." << IBRCOMMON_LOGGER_ENDL;
00192                                                                 decryptPayload(bundle, key, salt);
00193                                                                 throw ibrcommon::Exception("decrypt reversed - tag verfication failed");
00194                                                         }
00195 
00196                                                         // success! add this block to the erasue list
00197                                                         erasure_list.push_back(*it);
00198 
00199                                                         // check if first PCB has a correlator
00200                                                         if (pcb._ciphersuite_flags & CONTAINS_CORRELATOR)
00201                                                         {
00202                                                                 // ... and decrypt all correlated block with the same key
00203                                                                 decrypt_related = true;
00204 
00205                                                                 // store the correlator
00206                                                                 correlator = pcb._correlator;
00207                                                         }
00208                                                         else
00209                                                         {
00210                                                                 // no correlated blocks should exists
00211                                                                 // stop here with decryption
00212                                                                 break;
00213                                                         }
00214                                                 }
00215                                                 else
00216                                                 {
00217                                                         // exit here, because we can not decrypt the first PCB.
00218                                                         throw ibrcommon::Exception("unable to decrypt the first PCB");
00219                                                 }
00220                                         } catch (const std::bad_cast&) { };
00221                                 }
00222 
00223                                 // delete all block in the erasure list
00224                                 for (std::list<const dtn::data::Block* >::const_iterator it = erasure_list.begin(); it != erasure_list.end(); it++)
00225                                 {
00226                                         bundle.remove(**it);
00227                                 }
00228                         } catch (const std::exception&) {
00229                                 long_key.free(rsa_key);
00230                                 throw;
00231                         }
00232 
00233                         long_key.free(rsa_key);
00234                 }
00235 
00236                 bool PayloadConfidentialBlock::decryptPayload(dtn::data::Bundle& bundle, const unsigned char ephemeral_key[ibrcommon::AES128Stream::key_size_in_bytes], const u_int32_t salt)
00237                 {
00238                         // TODO handle fragmentation
00239                         PayloadConfidentialBlock& pcb = bundle.getBlock<PayloadConfidentialBlock>();
00240                         dtn::data::PayloadBlock& plb = bundle.getBlock<dtn::data::PayloadBlock>();
00241 
00242                         // the array for the extracted iv
00243                         unsigned char iv[ibrcommon::AES128Stream::iv_len];
00244                         pcb._ciphersuite_params.get(SecurityBlock::initialization_vector, iv, ibrcommon::AES128Stream::iv_len);
00245 
00246                         // the array for the extracted tag
00247                         unsigned char tag[ibrcommon::AES128Stream::tag_len];
00248                         pcb._security_result.get(SecurityBlock::PCB_integrity_check_value, tag, ibrcommon::AES128Stream::tag_len);
00249 
00250                         // get the reference to the corresponding BLOB object
00251                         ibrcommon::BLOB::Reference blobref = plb.getBLOB();
00252 
00253                         // decrypt the payload and get the integrity signature (tag)
00254                         {
00255                                 ibrcommon::BLOB::iostream stream = blobref.iostream();
00256                                 ibrcommon::AES128Stream decrypt(ibrcommon::CipherStream::CIPHER_DECRYPT, *stream, ephemeral_key, salt, iv);
00257                                 ((ibrcommon::CipherStream&)decrypt).decrypt(*stream);
00258 
00259                                 // get the decrypt tag
00260                                 if (!decrypt.verify(tag))
00261                                 {
00262                                         IBRCOMMON_LOGGER(error) << "integrity signature of the decrypted payload is invalid" << IBRCOMMON_LOGGER_ENDL;
00263                                         return false;
00264                                 }
00265                         }
00266 
00267                         return true;
00268                 }
00269         }
00270 }