IBR-DTNSuite  0.10
PayloadConfidentialBlock.cpp
Go to the documentation of this file.
1 /*
2  * PayloadConfidentialBlock.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
24 #include "ibrdtn/data/Bundle.h"
25 #include "ibrdtn/data/SDNV.h"
26 
27 #include <openssl/err.h>
28 #include <openssl/rsa.h>
30 #include <ibrcommon/Logger.h>
31 
32 #include <stdint.h>
33 #include <typeinfo>
34 #include <algorithm>
35 
36 #ifdef __DEVELOPMENT_ASSERTIONS__
37 #include <cassert>
38 #endif
39 
40 namespace dtn
41 {
42  namespace security
43  {
45 
47  {
48  return new PayloadConfidentialBlock();
49  }
50 
53  {
54  }
55 
57  {
58  }
59 
61  {
62  // contains the random salt
63  uint32_t salt;
64 
65  // contains the random key
66  unsigned char ephemeral_key[ibrcommon::AES128Stream::key_size_in_bytes];
67 
68  unsigned char iv[ibrcommon::AES128Stream::iv_len];
69  unsigned char tag[ibrcommon::AES128Stream::tag_len];
70 
71  // create a new correlator value
72  dtn::data::Number correlator = createCorrelatorValue(bundle);
73 
74  // create a random salt and key
76 
77  // count all PCBs
78  dtn::data::Size pcbs_size = std::count(bundle.begin(), bundle.end(), PayloadConfidentialBlock::BLOCK_TYPE);
79 
80  // count all PIBs
81  dtn::data::Size pibs_size = std::count(bundle.begin(), bundle.end(), PayloadIntegrityBlock::BLOCK_TYPE);
82 
83  // encrypt PCBs and PIBs
85  while (find_pcb.next(bundle.end()))
86  {
87  SecurityBlock::encryptBlock<PayloadConfidentialBlock>(bundle, find_pcb, salt, ephemeral_key).setCorrelator(correlator);
88  }
89 
91  while (find_pib.next(bundle.end()))
92  {
93  SecurityBlock::encryptBlock<PayloadConfidentialBlock>(bundle, find_pib, salt, ephemeral_key).setCorrelator(correlator);
94  }
95 
96  // create a new payload confidential block
98 
99  // set the correlator
100  if (pcbs_size > 0 || pibs_size > 0)
101  pcb.setCorrelator(correlator);
102 
103  // get reference to the payload block
105  ibrcommon::BLOB::Reference blobref = plb.getBLOB();
106 
107  // encrypt payload - BEGIN
108  {
109  ibrcommon::BLOB::iostream stream = blobref.iostream();
110  ibrcommon::AES128Stream aes_stream(ibrcommon::CipherStream::CIPHER_ENCRYPT, *stream, ephemeral_key, salt);
111 
112  // encrypt in place
113  ((ibrcommon::CipherStream&)aes_stream).encrypt(*stream);
114 
115  // check if this is a fragment
117  {
118  // ... and set the corresponding cipher suit params
120  }
121 
122  // get the IV
123  aes_stream.getIV(iv);
124 
125  // get the tag
126  aes_stream.getTag(tag);
127  }
128  // encrypt payload - END
129 
130  // set the source and destination address of the new block
131  if (source != bundle.source.getNode()) pcb.setSecuritySource( source );
132  if (long_key.reference != bundle.destination.getNode()) pcb.setSecurityDestination( long_key.reference );
133 
134  // set replicate in every fragment to true
135  pcb.set(REPLICATE_IN_EVERY_FRAGMENT, true);
136 
137  // store encypted key, tag, iv and salt
138  addSalt(pcb._ciphersuite_params, salt);
139 
140  // get the RSA key
141  RSA *rsa_key = long_key.getRSA();
142 
143  // encrypt the random key and add it to the ciphersuite params
145 
146  // free the RSA key
147  long_key.free(rsa_key);
148 
151 
154  }
155 
157  {
158  // list of block to delete if the process is successful
159  std::list<const dtn::data::Block*> erasure_list;
160 
161  // load the RSA key
162  RSA *rsa_key = long_key.getRSA();
163 
164  try {
165  // array for the current symmetric AES key
167 
168  // correlator of the first PCB
169  dtn::data::Number correlator = 0;
170  bool decrypt_related = false;
171 
172  // iterate through all blocks
173  for (dtn::data::Bundle::iterator it = bundle.begin(); it != bundle.end(); ++it)
174  {
175  try {
176  dynamic_cast<const PayloadIntegrityBlock&>(**it);
177 
178  // add this block to the erasure list for later deletion
179  erasure_list.push_back(&**it);
180  } catch (const std::bad_cast&) { };
181 
182  try {
183  const PayloadConfidentialBlock &pcb = dynamic_cast<const PayloadConfidentialBlock&>(**it);
184 
185  // get salt and key
186  uint32_t salt = getSalt(pcb._ciphersuite_params);
187 
188  // decrypt related blocks
189  if (decrypt_related)
190  {
191  // try to decrypt the block
192  try {
193  decryptBlock(bundle, it, salt, key);
194 
195  // success! add this block to the erasue list
196  erasure_list.push_back(&**it);
197  } catch (const ibrcommon::Exception&) {
198  IBRCOMMON_LOGGER_TAG("PayloadConfidentialBlock", critical) << "tag verfication failed, reversing decryption..." << IBRCOMMON_LOGGER_ENDL;
199  decryptBlock(bundle, it, salt, key);
200 
201  // abort the decryption and discard the bundle?
202  throw ibrcommon::Exception("decrypt of correlated block reversed, tag verfication failed");
203  }
204  }
205  // if security destination does match the key, then try to decrypt the payload
206  else if (pcb.isSecurityDestination(bundle, long_key.reference) &&
208  {
209  // try to decrypt the symmetric AES key
211  {
212  IBRCOMMON_LOGGER_TAG("PayloadConfidentialBlock", critical) << "could not get symmetric key decrypted" << IBRCOMMON_LOGGER_ENDL;
213  throw ibrcommon::Exception("decrypt failed - could not get symmetric key decrypted");
214  }
215 
216  // try to decrypt the payload
217  if (!decryptPayload(bundle, key, salt))
218  {
219  // reverse decryption
220  IBRCOMMON_LOGGER_TAG("PayloadConfidentialBlock", critical) << "tag verfication failed, reversing decryption..." << IBRCOMMON_LOGGER_ENDL;
221  decryptPayload(bundle, key, salt);
222  throw ibrcommon::Exception("decrypt reversed - tag verfication failed");
223  }
224 
225  // success! add this block to the erasue list
226  erasure_list.push_back(&**it);
227 
228  // check if first PCB has a correlator
230  {
231  // ... and decrypt all correlated block with the same key
232  decrypt_related = true;
233 
234  // store the correlator
235  correlator = pcb._correlator;
236  }
237  else
238  {
239  // no correlated blocks should exists
240  // stop here with decryption
241  break;
242  }
243  }
244  else
245  {
246  // exit here, because we can not decrypt the first PCB.
247  throw ibrcommon::Exception("unable to decrypt the first PCB");
248  }
249  } catch (const std::bad_cast&) { };
250  }
251 
252  // delete all block in the erasure list
253  for (std::list<const dtn::data::Block* >::const_iterator it = erasure_list.begin(); it != erasure_list.end(); ++it)
254  {
255  bundle.remove(**it);
256  }
257  } catch (const std::exception&) {
258  long_key.free(rsa_key);
259  throw;
260  }
261 
262  long_key.free(rsa_key);
263  }
264 
265  bool PayloadConfidentialBlock::decryptPayload(dtn::data::Bundle& bundle, const unsigned char ephemeral_key[ibrcommon::AES128Stream::key_size_in_bytes], const uint32_t salt)
266  {
267  // TODO handle fragmentation
270 
271  // the array for the extracted iv
272  unsigned char iv[ibrcommon::AES128Stream::iv_len];
274 
275  // the array for the extracted tag
276  unsigned char tag[ibrcommon::AES128Stream::tag_len];
278 
279  // get the reference to the corresponding BLOB object
280  ibrcommon::BLOB::Reference blobref = plb.getBLOB();
281 
282  // decrypt the payload and get the integrity signature (tag)
283  {
284  ibrcommon::BLOB::iostream stream = blobref.iostream();
286  ((ibrcommon::CipherStream&)decrypt).decrypt(*stream);
287 
288  // get the decrypt tag
289  if (!decrypt.verify(tag))
290  {
291  IBRCOMMON_LOGGER_TAG("PayloadConfidentialBlock", error) << "integrity signature of the decrypted payload is invalid" << IBRCOMMON_LOGGER_ENDL;
292  return false;
293  }
294  }
295 
296  return true;
297  }
298  }
299 }