NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
block-cipher.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
22 #include "block-cipher.hpp"
23 #include "../detail/openssl.hpp"
24 
25 #include <boost/lexical_cast.hpp>
26 
27 namespace ndn {
28 namespace security {
29 namespace transform {
30 
32 {
33 public:
34  Impl()
35  : m_cipher(BIO_new(BIO_f_cipher()))
36  , m_sink(BIO_new(BIO_s_mem()))
37  {
38  BIO_push(m_cipher, m_sink);
39  }
40 
42  {
43  BIO_free_all(m_cipher);
44  }
45 
46 public:
47  BIO* m_cipher;
48  BIO* m_sink; // BIO_f_cipher alone does not work without a sink
49 };
50 
52  const uint8_t* key, size_t keyLen,
53  const uint8_t* iv, size_t ivLen)
54  : m_impl(new Impl)
55 {
56  switch (algo) {
58  initializeAesCbc(key, keyLen, iv, ivLen, op);
59  break;
60  default:
61  BOOST_THROW_EXCEPTION(Error(getIndex(), "Cipher algorithm " +
62  boost::lexical_cast<std::string>(algo) + " is not supported"));
63  }
64 }
65 
66 void
67 BlockCipher::preTransform()
68 {
69  fillOutputBuffer();
70 }
71 
72 size_t
73 BlockCipher::convert(const uint8_t* data, size_t dataLen)
74 {
75  if (dataLen == 0)
76  return 0;
77 
78  int wLen = BIO_write(m_impl->m_cipher, data, dataLen);
79 
80  if (wLen <= 0) { // fail to write data
81  if (!BIO_should_retry(m_impl->m_cipher)) {
82  // we haven't written everything but some error happens, and we cannot retry
83  BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input"));
84  }
85  return 0;
86  }
87  else { // update number of bytes written
88  fillOutputBuffer();
89  return wLen;
90  }
91 }
92 
93 void
94 BlockCipher::finalize()
95 {
96  if (BIO_flush(m_impl->m_cipher) != 1)
97  BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to flush"));
98 
99  while (!isConverterEmpty()) {
100  fillOutputBuffer();
101  while (!isOutputBufferEmpty()) {
103  }
104  }
105 }
106 
107 void
108 BlockCipher::fillOutputBuffer()
109 {
110  int nRead = BIO_pending(m_impl->m_sink);
111  if (nRead <= 0)
112  return;
113 
114  // there is something to read from BIO
115  auto buffer = make_unique<OBuffer>(nRead);
116  int rLen = BIO_read(m_impl->m_sink, &(*buffer)[0], nRead);
117  if (rLen < 0)
118  return;
119 
120  if (rLen < nRead)
121  buffer->erase(buffer->begin() + rLen, buffer->end());
122  setOutputBuffer(std::move(buffer));
123 }
124 
125 bool
126 BlockCipher::isConverterEmpty() const
127 {
128  return (BIO_pending(m_impl->m_sink) <= 0);
129 }
130 
131 void
132 BlockCipher::initializeAesCbc(const uint8_t* key, size_t keyLen,
133  const uint8_t* iv, size_t ivLen,
134  CipherOperator op)
135 {
136  if (keyLen != ivLen)
137  BOOST_THROW_EXCEPTION(Error(getIndex(), "Key length must be the same as IV length"));
138 
139  const EVP_CIPHER* cipherType = nullptr;
140  switch (keyLen) {
141  case 16:
142  cipherType = EVP_aes_128_cbc();
143  break;
144  case 24:
145  cipherType = EVP_aes_192_cbc();
146  break;
147  case 32:
148  cipherType = EVP_aes_256_cbc();
149  break;
150  default:
151  BOOST_THROW_EXCEPTION(Error(getIndex(), "Key length is not supported"));
152  }
153  BIO_set_cipher(m_impl->m_cipher, cipherType, key, iv, static_cast<int>(op));
154 }
155 
156 unique_ptr<Transform>
158  const uint8_t* key, size_t keyLen,
159  const uint8_t* iv, size_t ivLen)
160 {
161  return make_unique<BlockCipher>(algo, op, key, keyLen, iv, ivLen);
162 }
163 
164 } // namespace transform
165 } // namespace security
166 } // namespace ndn
Copyright (c) 2011-2015 Regents of the University of California.
size_t getIndex() const
Get the module index.
BlockCipherAlgorithm
bool isOutputBufferEmpty() const
Check if output buffer is empty.
unique_ptr< Transform > blockCipher(BlockCipherAlgorithm algo, CipherOperator op, const uint8_t *key, size_t keyLen, const uint8_t *iv, size_t ivLen)
void setOutputBuffer(unique_ptr< OBuffer > buffer)
Set output buffer to buffer.
Base class of transformation error.
void flushOutputBuffer()
Read the content from output buffer and write it into next module.
BlockCipher(BlockCipherAlgorithm algo, CipherOperator op, const uint8_t *key, size_t keyLen, const uint8_t *iv, size_t ivLen)
Create a block cipher.