IBR-DTN  1.0.0
JPAKEProtocol.cpp
Go to the documentation of this file.
1 /*
2  * JPAKEProtocol.cpp
3  *
4  * Copyright (C) 2014 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  * Thomas Schrader <schrader.thomas@gmail.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22 
26 #include "core/BundleCore.h"
27 #include <ibrcommon/ssl/HMacStream.h>
28 
29 #include <openssl/sha.h>
30 
31 #define JPAKE_PRIME_LENGTH 1024
32 
33 
34 namespace dtn
35 {
36  namespace security
37  {
38  JPAKEProtocol::JPAKEState::JPAKEState()
39  : ctx(NULL)
40  {
41  }
42 
43  JPAKEProtocol::JPAKEState::~JPAKEState()
44  {
45  if (ctx) JPAKE_CTX_free(ctx);
46  }
47 
49  : KeyExchangeProtocol(manager, 2)
50  {
51  }
52 
54  {
55  }
56 
57  KeyExchangeSession* JPAKEProtocol::createSession(const dtn::data::EID &peer, unsigned int uniqueId)
58  {
59  return new KeyExchangeSession(getProtocol(), peer, uniqueId, new JPAKEState());
60  }
61 
63  {
64  // get session state
65  JPAKEState &state = session.getState<JPAKEState>();
66 
67  // JPAKE_STEP1 erzeugen
68  BIGNUM* p;
69  p = BN_new();
70  //BN_generate_prime_ex(p, JPAKE_PRIME_LENGTH, 1, NULL, NULL, NULL);
71 
72  BN_hex2bn(&p, "F9E5B365665EA7A05A9C534502780FEE6F1AB5BD4F49947FD036DBD7E905269AF46EF28B0FC07487EE4F5D20FB3C0AF8E700F3A2FA3414970CBED44FEDFF80CE78D800F184BB82435D137AADA2C6C16523247930A63B85661D1FC817A51ACD96168E95898A1F83A79FFB529368AA7833ABD1B0C3AEDDB14D2E1A2F71D99F763F");
73 
74  BIGNUM* q;
75  q = BN_new();
76  BN_rshift1(q, p);
77 
78  const std::string password = data.str();
79 
80  BIGNUM* secret = BN_new();
81  BN_bin2bn((const unsigned char*)password.c_str(), (int)password.size(), secret);
82 
83  BIGNUM* g = BN_new();
84  BN_set_word(g, 2);
85 
86  state.ctx = JPAKE_CTX_new(toHex(dtn::core::BundleCore::local.getString()).c_str(), toHex(session.getPeer().getString()).c_str(), p, g, q, secret);
87 
88  JPAKE_STEP1 send1;
89  JPAKE_STEP1_init(&send1);
90  JPAKE_STEP1_generate(&send1, state.ctx);
91 
92  KeyExchangeData request(KeyExchangeData::REQUEST, session);
93 
94  write(request, send1.p1.gx);
95  write(request, send1.p1.zkpx.gr);
96  write(request, send1.p1.zkpx.b);
97  write(request, send1.p2.gx);
98  write(request, send1.p2.zkpx.gr);
99  write(request, send1.p2.zkpx.b);
100  write(request, p);
101  write(request, q);
102 
103  manager.submit(session, request);
104 
105  JPAKE_STEP1_release(&send1);
106 
107  BN_free(p);
108  BN_free(q);
109  BN_free(secret);
110  BN_free(g);
111  }
112 
114  {
115  // get session state
116  JPAKEState &state = session.getState<JPAKEState>();
117 
118  switch (data.getStep())
119  {
120  case 0:
121  {
122  if (data.getAction() == KeyExchangeData::REQUEST)
123  {
124  state.step1 = data.str();
125 
127  KeyExchangeEvent::raise(session.getPeer(), request);
128  }
129  else
130  {
131  // copy previous step to a stream
132  std::stringstream step1(state.step1);
133 
134  JPAKE_STEP1 received1;
135  JPAKE_STEP1_init(&received1);
136  read(step1, &received1.p1.gx);
137  read(step1, &received1.p1.zkpx.gr);
138  read(step1, &received1.p1.zkpx.b);
139  read(step1, &received1.p2.gx);
140  read(step1, &received1.p2.zkpx.gr);
141  read(step1, &received1.p2.zkpx.b);
142 
143  BIGNUM* p = BN_new();
144  read(step1, &p);
145  BIGNUM* q = BN_new();
146  read(step1, &q);
147  BIGNUM* secret = BN_new();
148  BN_bin2bn((const unsigned char*)data.str().c_str(), (int)data.str().size(), secret);
149  BIGNUM* g = BN_new();
150  BN_set_word(g, 2);
151 
152  state.ctx = JPAKE_CTX_new(toHex(dtn::core::BundleCore::local.getString()).c_str(), toHex(session.getPeer().getString()).c_str(), p, g, q, secret);
153 
154  if (!JPAKE_STEP1_process(state.ctx, &received1))
155  {
156  JPAKE_STEP1_release(&received1);
157  BN_free(p);
158  BN_free(q);
159  BN_free(secret);
160  BN_free(g);
161  throw ibrcommon::Exception("Error while processing STEP1");
162  }
163 
164  JPAKE_STEP1_release(&received1);
165 
166  JPAKE_STEP1 send1;
167  JPAKE_STEP1_init(&send1);
168  JPAKE_STEP1_generate(&send1, state.ctx);
169 
170  KeyExchangeData response(KeyExchangeData::RESPONSE, session);
171  response.setStep(1);
172 
173  write(response, send1.p1.gx);
174  write(response, send1.p1.zkpx.gr);
175  write(response, send1.p1.zkpx.b);
176  write(response, send1.p2.gx);
177  write(response, send1.p2.zkpx.gr);
178  write(response, send1.p2.zkpx.b);
179 
180  manager.submit(session, response);
181 
182  JPAKE_STEP1_release(&send1);
183 
184  BN_free(p);
185  BN_free(q);
186  BN_free(secret);
187  BN_free(g);
188  }
189  break;
190  }
191 
192  case 1:
193  {
194  if (data.getAction() == KeyExchangeData::REQUEST)
195  {
196  // nothing to do?
197  }
198  else
199  {
200  JPAKE_STEP1 received1;
201  JPAKE_STEP1_init(&received1);
202  read(data, &received1.p1.gx);
203  read(data, &received1.p1.zkpx.gr);
204  read(data, &received1.p1.zkpx.b);
205  read(data, &received1.p2.gx);
206  read(data, &received1.p2.zkpx.gr);
207  read(data, &received1.p2.zkpx.b);
208 
209  if (!JPAKE_STEP1_process(state.ctx, &received1))
210  {
211  JPAKE_STEP1_release(&received1);
212  throw ibrcommon::Exception("Error while processing STEP1");
213  }
214 
215  JPAKE_STEP1_release(&received1);
216 
217  JPAKE_STEP2 send2;
218  JPAKE_STEP2_init(&send2);
219  JPAKE_STEP2_generate(&send2, state.ctx);
220 
221  KeyExchangeData request(KeyExchangeData::REQUEST, session);
222  request.setStep(2);
223 
224  write(request, send2.gx);
225  write(request, send2.zkpx.gr);
226  write(request, send2.zkpx.b);
227 
228  manager.submit(session, request);
229 
230  JPAKE_STEP2_release(&send2);
231  }
232  break;
233  }
234 
235  case 2:
236  {
237  if (data.getAction() == KeyExchangeData::REQUEST)
238  {
239  // Berechne J-PAKE-Parameter und sende jpake_response 2 (2) am anderen
240  JPAKE_STEP2 received2;
241  JPAKE_STEP2_init(&received2);
242  read(data, &received2.gx);
243  read(data, &received2.zkpx.gr);
244  read(data, &received2.zkpx.b);
245 
246  if (!JPAKE_STEP2_process(state.ctx, &received2))
247  {
248  JPAKE_STEP2_release(&received2);
249  throw ibrcommon::Exception("Error while processing STEP2");
250  }
251 
252  JPAKE_STEP2_release(&received2);
253 
254  JPAKE_STEP2 send2;
255  JPAKE_STEP2_init(&send2);
256  JPAKE_STEP2_generate(&send2, state.ctx);
257 
258  KeyExchangeData response(KeyExchangeData::RESPONSE, session);
259  response.setStep(2);
260 
261  write(response, send2.gx);
262  write(response, send2.zkpx.gr);
263  write(response, send2.zkpx.b);
264 
265  manager.submit(session, response);
266 
267  JPAKE_STEP2_release(&send2);
268  }
269  else
270  {
271  // Berechne hash und sende control_request (3) an anderen
272  JPAKE_STEP2 received2;
273  JPAKE_STEP2_init(&received2);
274  read(data, &received2.gx);
275  read(data, &received2.zkpx.gr);
276  read(data, &received2.zkpx.b);
277 
278  if (!JPAKE_STEP2_process(state.ctx, &received2))
279  {
280  JPAKE_STEP2_release(&received2);
281  throw ibrcommon::Exception("Error while processing STEP2");
282  }
283 
284  JPAKE_STEP2_release(&received2);
285 
286  JPAKE_STEP3A send3;
287  JPAKE_STEP3A_init(&send3);
288  JPAKE_STEP3A_generate(&send3, state.ctx);
289 
290  KeyExchangeData request(KeyExchangeData::REQUEST, session);
291  request.setStep(3);
292 
293  request.write((char*) send3.hhk, SHA_DIGEST_LENGTH);
294 
295  manager.submit(session, request);
296 
297  JPAKE_STEP3A_release(&send3);
298  }
299  break;
300  }
301 
302  case 3:
303  {
304  if (data.getAction() == KeyExchangeData::REQUEST)
305  {
306  // Berechne hash, sende control response (3) an anderen und eventuell wrongpassword
307  JPAKE_STEP3A received3;
308  JPAKE_STEP3A_init(&received3);
309  data.read((char*)&received3.hhk, SHA_DIGEST_LENGTH);
310 
311  if (!JPAKE_STEP3A_process(state.ctx, &received3))
312  {
313  JPAKE_STEP3A_release(&received3);
314  throw ibrcommon::Exception("Error while processing STEP3A");
315  }
316 
317  JPAKE_STEP3A_release(&received3);
318 
319  JPAKE_STEP3B send3;
320  JPAKE_STEP3B_init(&send3);
321  JPAKE_STEP3B_generate(&send3, state.ctx);
322 
323  KeyExchangeData response(KeyExchangeData::RESPONSE, session);
324  response.setStep(3);
325 
326  response.write((char*) send3.hk, SHA_DIGEST_LENGTH);
327 
328  manager.submit(session, response);
329 
330  JPAKE_STEP3B_release(&send3);
331  }
332  else
333  {
334  // Berechne hmac-Parameter und sende hmac_request (4) an anderen oder wrong_password
335  JPAKE_STEP3B received3;
336  JPAKE_STEP3B_init(&received3);
337  data.read((char*)&received3.hk, SHA_DIGEST_LENGTH);
338 
339  if (!JPAKE_STEP3B_process(state.ctx, &received3))
340  {
341  JPAKE_STEP3B_release(&received3);
342  throw ibrcommon::Exception("Error while processing STEP3B");
343  }
344 
345  JPAKE_STEP3B_release(&received3);
346 
347  std::stringstream secretBuf;
348  write(secretBuf, JPAKE_get_shared_key(state.ctx));
349 
350  // get local public key
352 
354  ibrcommon::HMacStream hstream((unsigned char*) secretBuf.str().c_str(), (int) secretBuf.str().size());
355  hstream << publicKey << std::flush;
356 
357  // bundle erzeugen: EID, hmac/publicKey, request, round 1
358  KeyExchangeData request(KeyExchangeData::REQUEST, session);
359  request.setStep(4);
360 
361  request << dtn::data::BundleString(ibrcommon::HashStream::extract(hstream));
362  request << publicKey;
363 
364  manager.submit(session, request);
365  }
366  break;
367  }
368 
369  case 4:
370  {
371  if (data.getAction() == KeyExchangeData::REQUEST)
372  {
373  // Berechne HMAC-Parameter, sende hmac_response (4) an anderen und jpake complete bzw. new key
374 
375  std::stringstream secretBuf;
376  write(secretBuf,JPAKE_get_shared_key(state.ctx));
377 
379  data >> hmac;
380  dtn::data::BundleString publicK;
381  data >> publicK;
382 
383  ibrcommon::HMacStream hmacstream((unsigned char*) secretBuf.str().c_str(), (int) secretBuf.str().size());
384  hmacstream << publicK << std::flush;
385 
386  if (hmac != ibrcommon::HMacStream::extract(hmacstream))
387  {
388  throw ibrcommon::Exception("Error while comparing hmac");
389  }
390 
391  // write key in tmp file
393 
394  // get local public key
396 
398  ibrcommon::HMacStream hstream((unsigned char*) secretBuf.str().c_str(), (int) secretBuf.str().size());
399  hstream << publicKey << std::flush;
400 
401  KeyExchangeData response(KeyExchangeData::RESPONSE, session);
402  response.setStep(4);
403 
404  response << dtn::data::BundleString(ibrcommon::HashStream::extract(hstream));
405  response << publicKey;
406 
407  manager.submit(session, response);
408 
409  manager.finish(session);
410  }
411  else
412  {
413  // Sende jpake_complete bzw new key
414 
415  std::stringstream secretBuf;
416  write(secretBuf, JPAKE_get_shared_key(state.ctx));
417 
419  data >> hmac;
420 
421  dtn::data::BundleString publicK;
422  data >> publicK;
423 
424  ibrcommon::HMacStream hstream((unsigned char*) secretBuf.str().c_str(), (int) secretBuf.str().size());
425  hstream << publicK << std::flush;
426 
427  if (hmac != ibrcommon::HMacStream::extract(hstream))
428  {
429  throw ibrcommon::Exception("Error while comparing hmac");
430  }
431 
432  // write key in tmp file
434 
435  manager.finish(session);
436  }
437  break;
438  }
439  }
440  }
441 
442  void JPAKEProtocol::write(std::ostream &stream, const BIGNUM* bn)
443  {
444  unsigned char* buf = new unsigned char[(BN_num_bits(bn) + 1) * sizeof(char)];
445  dtn::data::Number length = BN_bn2bin(bn, (unsigned char*)buf);
446 
447  if (length > 0)
448  {
449  stream << length;
450  stream.write((char*)buf, length.get<size_t>());
451  delete[] buf;
452  }
453  else
454  {
455  delete[] buf;
456  throw ibrcommon::Exception("Error while parsing BIGNUM to string");
457  }
458  }
459 
460  void JPAKEProtocol::read(std::istream &stream, BIGNUM **bn)
461  {
462  dtn::data::Number length;
463  stream >> length;
464 
465  unsigned char* buf = new unsigned char[length.get<size_t>()];
466  stream.read((char*)buf, length.get<size_t>());
467  *bn = BN_bin2bn((unsigned char*)buf, (int) length.get<size_t>(), NULL);
468  delete[] buf;
469 
470  if (*bn == NULL)
471  {
472  throw ibrcommon::Exception("Error while parsing string to BIGNUM");
473  }
474  }
475  } /* namespace security */
476 } /* namespace dtn */
static SecurityKeyManager & getInstance()
const dtn::data::EID & getPeer() const
static dtn::data::EID local
Definition: BundleCore.h:79
virtual KeyExchangeSession * createSession(const dtn::data::EID &peer, unsigned int uniqueId)
void putKey(const std::string &data, const dtn::security::SecurityKey::KeyType type, const dtn::security::SecurityKey::TrustLevel trust) const
virtual const std::string getData() const
Definition: SecurityKey.cpp:64
virtual void step(KeyExchangeSession &session, KeyExchangeData &data)
void read(std::istream &stream)
Definition: SDNV.h:425
virtual void finish(KeyExchangeSession &session)=0
dtn::security::SecurityKey get(const dtn::data::EID &ref, const dtn::security::SecurityKey::KeyType type=dtn::security::SecurityKey::KEY_UNSPEC) const
virtual void submit(KeyExchangeSession &session, const KeyExchangeData &data)=0
static std::string toHex(const std::string &data)
virtual void begin(KeyExchangeSession &session, KeyExchangeData &data)
std::string getString() const
Definition: EID.cpp:374
JPAKEProtocol(KeyExchangeManager &manager)
static void raise(const dtn::data::EID &eid, const dtn::security::KeyExchangeData &data)