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) 2013-2016 Regents of the University of California.
Definition: common.hpp:74
BlockCipherAlgorithm
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.
bool isOutputBufferEmpty() const
Check if output buffer is empty.
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.
size_t getIndex() const
Get the module index.