security: Add transformation sink/source

Change-Id: I2698f79f639c2bd7c3ce2e00f48be634dc4c983d
Refs: #3009
diff --git a/src/security/transform.hpp b/src/security/transform.hpp
new file mode 100644
index 0000000..b29f5c6
--- /dev/null
+++ b/src/security/transform.hpp
@@ -0,0 +1,32 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_HPP
+
+#include "transform/buffer-source.hpp"
+#include "transform/stream-source.hpp"
+#include "transform/step-source.hpp"
+
+#include "transform/bool-sink.hpp"
+#include "transform/stream-sink.hpp"
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_HPP
diff --git a/src/security/transform/bool-sink.cpp b/src/security/transform/bool-sink.cpp
new file mode 100644
index 0000000..1c45c76
--- /dev/null
+++ b/src/security/transform/bool-sink.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "bool-sink.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+BoolSink::BoolSink(bool& value)
+  : m_hasValue(false)
+  , m_value(value)
+{
+}
+
+size_t
+BoolSink::doWrite(const uint8_t* buf, size_t size)
+{
+  if (!m_hasValue && size > 0) {
+    m_value = (buf[0] != 0);
+    m_hasValue = true;
+  }
+  return size;
+}
+
+void
+BoolSink::doEnd()
+{
+  // nothing to do.
+}
+
+unique_ptr<Sink>
+boolSink(bool& value)
+{
+  return make_unique<BoolSink>(value);
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/bool-sink.hpp b/src/security/transform/bool-sink.hpp
new file mode 100644
index 0000000..12e62c9
--- /dev/null
+++ b/src/security/transform/bool-sink.hpp
@@ -0,0 +1,73 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_BOOL_SINK_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_BOOL_SINK_HPP
+
+#include "transform-base.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A sink which outputs only one boolean value.
+ *
+ * It checks the first byte that is ever written into the sink,
+ * and set output true if the byte is non-zero, otherwise false.
+ */
+class BoolSink : public Sink
+{
+public:
+  /**
+   * @brief Create a bool sink whose output will be stored in @p value.
+   */
+  explicit
+  BoolSink(bool& value);
+
+private:
+  /**
+   * @brief Check the first byte that is ever received and set the boolean variable.
+   *
+   * @return the same value as @p size.
+   */
+  virtual size_t
+  doWrite(const uint8_t* buf, size_t size) final;
+
+  /**
+   * @brief Finalize sink processing
+   */
+  virtual void
+  doEnd() final;
+
+private:
+  bool m_hasValue;
+  bool& m_value;
+};
+
+unique_ptr<Sink>
+boolSink(bool& value);
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_BOOL_SINK_HPP
diff --git a/src/security/transform/buffer-source.cpp b/src/security/transform/buffer-source.cpp
new file mode 100644
index 0000000..b47e855
--- /dev/null
+++ b/src/security/transform/buffer-source.cpp
@@ -0,0 +1,65 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "buffer-source.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+BufferSource::BufferSource(const uint8_t* buf, size_t size)
+  : m_buf(buf)
+  , m_size(size)
+{
+}
+
+BufferSource::BufferSource(const std::string& string)
+  : m_buf(reinterpret_cast<const uint8_t*>(string.data()))
+  , m_size(string.size())
+{
+}
+
+BufferSource::BufferSource(const Buffer& buffer)
+  : m_buf(buffer.buf())
+  , m_size(buffer.size())
+{
+}
+
+void
+BufferSource::doPump()
+{
+  BOOST_ASSERT(m_next != nullptr);
+
+  const uint8_t* buf = m_buf;
+  size_t size = m_size;
+
+  while (0 < size) {
+    size_t nBytesWritten = m_next->write(buf, size);
+    buf += nBytesWritten;
+    size -= nBytesWritten;
+  }
+
+  m_next->end();
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/buffer-source.hpp b/src/security/transform/buffer-source.hpp
new file mode 100644
index 0000000..0833a0f
--- /dev/null
+++ b/src/security/transform/buffer-source.hpp
@@ -0,0 +1,79 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_BUFFER_SOURCE_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_BUFFER_SOURCE_HPP
+
+#include "transform-base.hpp"
+#include "../../encoding/buffer.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A source taking a memory buffer as input
+ */
+class BufferSource : public Source
+{
+public:
+  /**
+   * @brief Take a buffer @p buf with size of @p size as input.
+   *
+   * Caller must not destroy the buffer before transformation is done
+   */
+  BufferSource(const uint8_t* buf, size_t size);
+
+  /**
+   * @brief Take @p string as input.
+   *
+   * Caller must not destroy the string before transformation is done
+   */
+  explicit
+  BufferSource(const std::string& string);
+
+  /**
+   * @brief Take @p buffer as input.
+   *
+   * Caller must not destroy the buffer before transformation is done
+   */
+  explicit
+  BufferSource(const Buffer& buffer);
+
+private:
+  /**
+   * @brief Write the whole buffer into the next module.
+   */
+  virtual void
+  doPump() final;
+
+private:
+  const uint8_t* m_buf;
+  size_t m_size;
+};
+
+typedef BufferSource bufferSource;
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_BUFFER_SOURCE_HPP
diff --git a/src/security/transform/step-source.cpp b/src/security/transform/step-source.cpp
new file mode 100644
index 0000000..432ebd9
--- /dev/null
+++ b/src/security/transform/step-source.cpp
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "step-source.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+size_t
+StepSource::write(const uint8_t* buf, size_t size)
+{
+  return m_next->write(buf, size);
+}
+
+void
+StepSource::end()
+{
+  m_next->end();
+}
+
+
+void
+StepSource::doPump()
+{
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/step-source.hpp b/src/security/transform/step-source.hpp
new file mode 100644
index 0000000..76388f7
--- /dev/null
+++ b/src/security/transform/step-source.hpp
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_STEP_SOURCE_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_STEP_SOURCE_HPP
+
+#include "transform-base.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A source that can accept input step by step, and can close input explicitly.
+ *
+ * This source will not send data into the transformation chain when the chain is constructed.
+ * Input will be explicitly sent into the chain using write(...) and will be closed explicitly
+ * using end().
+ *
+ *   StepSource ss;
+ *   ss >> transform1() >> transform2() >> sinkStream(...);
+ *   ss.write(...);
+ *   ...
+ *   ss.write(...);
+ *   ss.end();
+ */
+class StepSource : public Source
+{
+public:
+  /**
+   * @brief Accept input data and directly write input into next transformation module.
+   *
+   * One can keep calling this method to until end() is called, which
+   * indicates the end of input.  After that, calling this method will cause Error.
+   *
+   * @return number of bytes that has been written into next module
+   */
+  size_t
+  write(const uint8_t* buf, size_t size);
+
+  /**
+   * @brief Close the input interface and directly notify the next module the end of input
+   */
+  void
+  end();
+
+private:
+  /**
+   * @brief This method intentionally does nothing
+   *
+   * use write() and end() method explicitly to input data.
+   */
+  virtual void
+  doPump() final;
+
+};
+
+typedef StepSource stepSource;
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_STEP_SOURCE_HPP
diff --git a/src/security/transform/stream-sink.cpp b/src/security/transform/stream-sink.cpp
new file mode 100644
index 0000000..58208c0
--- /dev/null
+++ b/src/security/transform/stream-sink.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "stream-sink.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+StreamSink::StreamSink(std::ostream& os)
+  : m_os(os)
+{
+}
+
+size_t
+StreamSink::doWrite(const uint8_t* buf, size_t size)
+{
+  m_os.write(reinterpret_cast<const char*>(buf), size);
+
+  if (m_os.bad())
+    BOOST_THROW_EXCEPTION(Error(getIndex(), "Fail to write data into output stream"));
+
+  return size;
+}
+
+void
+StreamSink::doEnd()
+{
+  m_os.flush();
+}
+
+unique_ptr<Sink>
+streamSink(std::ostream& os)
+{
+  return make_unique<StreamSink>(os);
+}
+
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/stream-sink.hpp b/src/security/transform/stream-sink.hpp
new file mode 100644
index 0000000..ed41cbd
--- /dev/null
+++ b/src/security/transform/stream-sink.hpp
@@ -0,0 +1,70 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_STREAM_SINK_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_STREAM_SINK_HPP
+
+#include "transform-base.hpp"
+#include <iostream>
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A sink which directs output to an std::ostream.
+ */
+class StreamSink : public Sink
+{
+public:
+  /**
+   * @brief Create a stream sink which outputs to @p os
+   */
+  explicit
+  StreamSink(std::ostream& os);
+
+private:
+  /**
+   * @brief Write data into the stream
+   *
+   * @return number of bytes that have been written into the stream
+   */
+  virtual size_t
+  doWrite(const uint8_t* buf, size_t size) final;
+
+  /**
+   * @brief Finalize sink processing
+   */
+  virtual void
+  doEnd() final;
+
+private:
+  std::ostream& m_os;
+};
+
+unique_ptr<Sink>
+streamSink(std::ostream& os);
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_STREAM_SINK_HPP
diff --git a/src/security/transform/stream-source.cpp b/src/security/transform/stream-source.cpp
new file mode 100644
index 0000000..5248646
--- /dev/null
+++ b/src/security/transform/stream-source.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "stream-source.hpp"
+#include <vector>
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+const std::size_t StreamSource::DEFAULT_BUFFER_LEN = 1024;
+
+StreamSource::StreamSource(std::istream& is, size_t bufferSize)
+  : Source()
+  , m_is(is)
+  , m_bufferSize(bufferSize)
+{
+  BOOST_ASSERT(bufferSize > 0);
+}
+
+void
+StreamSource::doPump()
+{
+  BOOST_ASSERT(m_next != nullptr);
+
+  std::vector<uint8_t> buffer(m_bufferSize);
+  size_t dataOffset = 0;
+  size_t dataLen = 0;
+
+  while (dataLen > 0 || !m_is.eof()) {
+    if (dataLen > 0) {
+      // we have some leftover, handle them first
+      size_t nBytesWritten = m_next->write(&buffer[dataOffset], dataLen);
+
+      dataOffset += nBytesWritten;
+      dataLen -= nBytesWritten;
+    }
+    else if (m_is.bad()) {
+      BOOST_THROW_EXCEPTION(Error(getIndex(), "Input stream in bad state"));
+    }
+    else if (m_is.good()) {
+      m_is.read(reinterpret_cast<char*>(&buffer.front()), buffer.size());
+      dataOffset = 0;
+      dataLen = m_is.gcount();
+    }
+  }
+  m_next->end();
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/stream-source.hpp b/src/security/transform/stream-source.hpp
new file mode 100644
index 0000000..b818fe7
--- /dev/null
+++ b/src/security/transform/stream-source.hpp
@@ -0,0 +1,69 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_STREAM_SOURCE_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_STREAM_SOURCE_HPP
+
+#include "transform-base.hpp"
+#include <iostream>
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A source taking an std::istream as input
+ */
+class StreamSource : public Source
+{
+public:
+  /**
+   * @brief Construst a source using @p is as input.
+   *
+   * @param is The input stream
+   * @param bufLen The internal buffer size. The default size is 1024.
+   * @pre bufLen must be larger than 0.
+   */
+  explicit
+  StreamSource(std::istream& is, size_t bufLen = DEFAULT_BUFFER_LEN);
+
+private:
+  /**
+   * @brief Read bytes from the input stream until EOF is reached and write them into the next module.
+   */
+  virtual void
+  doPump() final;
+
+public:
+  static const std::size_t DEFAULT_BUFFER_LEN;
+
+private:
+  std::istream& m_is;
+  size_t m_bufferSize;
+};
+
+typedef StreamSource streamSource;
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_STREAM_SOURCE_HPP
diff --git a/src/security/transform/transform-base.cpp b/src/security/transform/transform-base.cpp
new file mode 100644
index 0000000..85df6b9
--- /dev/null
+++ b/src/security/transform/transform-base.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "transform-base.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+Error::Error(size_t index, const std::string& what)
+  : std::runtime_error("Error in module " + std::to_string(index) + ": " + what)
+  , m_index(index)
+{
+}
+
+Downstream::Downstream()
+  : m_isEnd(false)
+{
+}
+
+size_t
+Downstream::write(const uint8_t* buf, size_t size)
+{
+  if (m_isEnd)
+    BOOST_THROW_EXCEPTION(Error(getIndex(), "Module is closed, no more input"));
+
+  size_t nBytesWritten = doWrite(buf, size);
+  BOOST_ASSERT(nBytesWritten <= size);
+  return nBytesWritten;
+}
+
+void
+Downstream::end()
+{
+  if (m_isEnd)
+    return;
+
+  m_isEnd = true;
+  return doEnd();
+}
+
+Upstream::Upstream()
+  : m_next(nullptr)
+{
+}
+
+void
+Upstream::appendChain(unique_ptr<Downstream> tail)
+{
+  if (m_next == nullptr) {
+    m_next = std::move(tail);
+  }
+  else {
+    BOOST_ASSERT(dynamic_cast<Transform*>(m_next.get()) != nullptr);
+    static_cast<Transform*>(m_next.get())->appendChain(std::move(tail));
+  }
+}
+
+Source::Source()
+  : m_nModules(1) // source per se is counted as one module
+{
+}
+
+void
+Source::pump()
+{
+  doPump();
+}
+
+Source&
+Source::operator>>(unique_ptr<Transform> transform)
+{
+  transform->setIndex(m_nModules);
+  m_nModules++;
+  this->appendChain(std::move(transform));
+
+  return *this;
+}
+
+void
+Source::operator>>(unique_ptr<Sink> sink)
+{
+  sink->setIndex(m_nModules);
+  m_nModules++;
+  this->appendChain(std::move(sink));
+
+  this->pump();
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/transform-base.hpp b/src/security/transform/transform-base.hpp
new file mode 100644
index 0000000..7f64145
--- /dev/null
+++ b/src/security/transform/transform-base.hpp
@@ -0,0 +1,249 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
+
+#include "../../common.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @file transform-base.hpp
+ *
+ * There are three types of module in a transformation chain: Source, Transform, and Sink.
+ * The ideal usage of the transformation would be:
+ *
+ *   source(...) >> transform1(...) >> transform2(...) >> sink(...);
+ *
+ * When error happens in a module, the module will throw out a transform::Error, one
+ * can get the location of the module through the getIndex() method of transform::Error.
+ */
+
+/**
+ * @brief Base class of transformation error
+ */
+class Error : public std::runtime_error
+{
+public:
+  Error(size_t index, const std::string& what);
+
+  size_t
+  getIndex() const
+  {
+    return m_index;
+  }
+
+private:
+  size_t m_index;
+};
+
+/**
+ * @brief The downstream interface of a transformation module
+ *
+ * A module can accept input through this interface
+ */
+class Downstream
+{
+public:
+  /**
+   * @brief Accept input data and perform transformation.
+   *
+   * An upstream module should call this method to write data into this module.
+   * The written data will be transformed and the result will be written into the next
+   * downstream module.
+   *
+   * An upstream module can keep calling this method to until end() is called, which
+   * indicates the end of input.  After that, calling this method will cause Error.
+   *
+   * If a Downstream implementation expects structured input (e.g., hex decoding requires byte-pair),
+   * it should not return less than size if final portion of input is not a complete record.
+   *
+   * @return number of bytes that has been written into this module
+   * @throws Error if this module is closed or transformation error happens.
+   */
+  size_t
+  write(const uint8_t* buf, size_t size);
+
+  /**
+   * @brief Close the input interface of a module.
+   *
+   * This method will notify this module that there is no more input and that the module
+   * should finalize transformation.
+   *
+   * Although end() can be invoked multiple times, only the first invocation takes effect.
+   */
+  void
+  end();
+
+  /**
+   * @brief Check if the input interface of a module is closed.
+   */
+  bool
+  isEnd() const
+  {
+    return m_isEnd;
+  }
+
+  /**
+   * @brief Set the module index.
+   */
+  void
+  setIndex(size_t index)
+  {
+    m_index = index;
+  }
+
+  /**
+   * @brief Get the module index.
+   */
+  size_t
+  getIndex() const
+  {
+    return m_index;
+  }
+
+protected:
+  Downstream();
+
+private:
+  /**
+   * @brief Internal implementation of write method
+   */
+  virtual size_t
+  doWrite(const uint8_t* buf, size_t size) = 0;
+
+  /**
+   * @brief Internal implementation of end method
+   */
+  virtual void
+  doEnd() = 0;
+
+private:
+  bool m_isEnd;
+  size_t m_index;
+};
+
+/**
+ * @brief The upstream interface of a transformation module
+ *
+ * A module can construct subsequent transformation chain through this interface.
+ */
+class Upstream
+{
+protected:
+  Upstream();
+
+protected:
+  /**
+   * @brief connect to next transformation module
+   */
+  void
+  appendChain(unique_ptr<Downstream> tail);
+
+  Downstream*
+  getNext()
+  {
+    return m_next.get();
+  }
+
+protected:
+  unique_ptr<Downstream> m_next;
+};
+
+/**
+ * @brief Abstraction of an intermediate transformation module
+ */
+class Transform : public Upstream,
+                  public Downstream,
+                  noncopyable
+{
+};
+
+/**
+ * @brief Abstraction of the transformation sink module
+ *
+ * This module does not have next module and can only accept input data
+ */
+class Sink : public Downstream,
+             noncopyable
+{
+};
+
+/**
+ * @brief Abstraction of the transformation source module
+ *
+ * This module can only accept input data from constructor
+ */
+class Source : public Upstream,
+               noncopyable
+{
+public:
+  /**
+   * @brief Connect to an intermediate transformation module.
+   */
+  Source&
+  operator>>(unique_ptr<Transform> transform);
+
+  /**
+   * @brief Connect to the last transformation module.
+   *
+   * This method will trigger the source to pump data into the transformation pipeline.
+   */
+  void
+  operator>>(unique_ptr<Sink> sink);
+
+protected:
+  Source();
+
+  /**
+   * @brief Pump all data into next transformation module.
+   */
+  void
+  pump();
+
+  /**
+   * @brief Get the source module index (should always be 0).
+   */
+  size_t
+  getIndex() const
+  {
+    return 0;
+  }
+
+private:
+  /**
+   * @brief Internal implementation of pump().
+   */
+  virtual void
+  doPump() = 0;
+
+private:
+  size_t m_nModules; // count of modules in the chain starting from this Source
+};
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
diff --git a/tests/unit-tests/security/transform.t.cpp b/tests/unit-tests/security/transform.t.cpp
new file mode 100644
index 0000000..6999df4
--- /dev/null
+++ b/tests/unit-tests/security/transform.t.cpp
@@ -0,0 +1,56 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/transform.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace security {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(TestTransform)
+
+BOOST_AUTO_TEST_CASE(SymbolVisibility)
+{
+  transform::BufferSource* bufferSource = nullptr;
+  BOOST_CHECK(bufferSource == nullptr);
+
+  transform::StreamSource* streamSource = nullptr;
+  BOOST_CHECK(streamSource == nullptr);
+
+  transform::StepSource* stepSource = nullptr;
+  BOOST_CHECK(stepSource == nullptr);
+
+  transform::BoolSink* boolSink = nullptr;
+  BOOST_CHECK(boolSink == nullptr);
+
+  transform::StreamSink* streamSink = nullptr;
+  BOOST_CHECK(streamSink == nullptr);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestTransform
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/transform/bool-sink.t.cpp b/tests/unit-tests/security/transform/bool-sink.t.cpp
new file mode 100644
index 0000000..4683219
--- /dev/null
+++ b/tests/unit-tests/security/transform/bool-sink.t.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/transform/bool-sink.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(Transform)
+BOOST_AUTO_TEST_SUITE(TestBoolSink)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  uint8_t in1[] = {0x00, 0x01};
+  bool value1 = true;
+  BoolSink sink1(value1);
+  BOOST_CHECK_EQUAL(sink1.write(in1, 1), 1);
+  BOOST_CHECK_EQUAL(sink1.write(in1 + 1, 1), 1);
+  sink1.end();
+  BOOST_CHECK_EQUAL(value1, false);
+  BOOST_CHECK_THROW(sink1.write(in1 + 1, 1), transform::Error);
+
+  uint8_t in2[] = {0x01, 0x00};
+  bool value2 = false;
+  BoolSink sink2(value2);
+  BOOST_CHECK_EQUAL(sink2.write(in2, 1), 1);
+  BOOST_CHECK_EQUAL(sink2.write(in2 + 1, 1), 1);
+  sink2.end();
+  BOOST_CHECK_EQUAL(value2, true);
+  BOOST_CHECK_THROW(sink2.write(in2 + 1, 1), transform::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestBoolSink
+BOOST_AUTO_TEST_SUITE_END() // Transform
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/transform/buffer-source.t.cpp b/tests/unit-tests/security/transform/buffer-source.t.cpp
new file mode 100644
index 0000000..151fd96
--- /dev/null
+++ b/tests/unit-tests/security/transform/buffer-source.t.cpp
@@ -0,0 +1,89 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/transform/buffer-source.hpp"
+#include "security/transform/stream-sink.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(Transform)
+BOOST_AUTO_TEST_SUITE(TestBufferSource)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  uint8_t in[16] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+  };
+
+  std::ostringstream os1;
+  bufferSource(in, sizeof(in)) >> streamSink(os1);
+  std::string out1 = os1.str();
+  BOOST_CHECK_EQUAL_COLLECTIONS(in, in + sizeof(in), out1.begin(), out1.end());
+
+  std::string in2 =
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567";
+
+  std::ostringstream os2;
+  bufferSource(in2) >> streamSink(os2);
+  std::string out2 = os2.str();
+  BOOST_CHECK_EQUAL_COLLECTIONS(in2.begin(), in2.end(), out2.begin(), out2.end());
+
+  Buffer in3(in, sizeof(in));
+  std::ostringstream os3;
+  bufferSource(in3) >> streamSink(os3);
+  std::string out3 = os3.str();
+  BOOST_CHECK_EQUAL_COLLECTIONS(in3.begin(), in3.end(), out3.begin(), out3.end());
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestBufferSource
+BOOST_AUTO_TEST_SUITE_END() // Transform
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/transform/step-source.t.cpp b/tests/unit-tests/security/transform/step-source.t.cpp
new file mode 100644
index 0000000..321a3dc
--- /dev/null
+++ b/tests/unit-tests/security/transform/step-source.t.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/transform/step-source.hpp"
+#include "security/transform/stream-sink.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(Transform)
+BOOST_AUTO_TEST_SUITE(TestStepSource)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  std::string input =
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567";
+  const uint8_t* buf = reinterpret_cast<const uint8_t*>(input.data());
+
+  std::stringstream os;
+  StepSource ss;
+  ss >> streamSink(os);
+  BOOST_CHECK_EQUAL(ss.write(buf, 320), 320);
+  BOOST_CHECK_EQUAL(ss.write(buf + 320, 320), 320);
+  BOOST_CHECK_EQUAL(ss.write(buf + 640, 320), 320);
+  BOOST_CHECK_EQUAL(ss.write(buf + 960, 320), 320);
+  ss.end();
+  BOOST_REQUIRE_THROW(ss.write(buf + 960, 320), transform::Error);
+  std::string output = os.str();
+  BOOST_CHECK_EQUAL(input, output);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestStepSource
+BOOST_AUTO_TEST_SUITE_END() // Transform
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/transform/stream-sink.t.cpp b/tests/unit-tests/security/transform/stream-sink.t.cpp
new file mode 100644
index 0000000..e9185d3
--- /dev/null
+++ b/tests/unit-tests/security/transform/stream-sink.t.cpp
@@ -0,0 +1,60 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/transform/stream-sink.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(Transform)
+BOOST_AUTO_TEST_SUITE(TestStreamSink)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  uint8_t in[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x20, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+  };
+  std::ostringstream os;
+  StreamSink sink(os);
+  BOOST_CHECK_EQUAL(sink.write(in, 4), 4);
+  BOOST_CHECK_EQUAL(sink.write(in + 4, 4), 4);
+  BOOST_CHECK_EQUAL(sink.write(in + 8, 4), 4);
+  BOOST_CHECK_EQUAL(sink.write(in + 12, 4), 4);
+  sink.end();
+  std::string out = os.str();
+  BOOST_CHECK_EQUAL_COLLECTIONS(in, in + sizeof(in), out.begin(), out.end());
+  BOOST_CHECK_THROW(sink.write(in + 8, 8), transform::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestStreamSink
+BOOST_AUTO_TEST_SUITE_END() // Transform
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/tests/unit-tests/security/transform/stream-source.t.cpp b/tests/unit-tests/security/transform/stream-source.t.cpp
new file mode 100644
index 0000000..a2f7be3
--- /dev/null
+++ b/tests/unit-tests/security/transform/stream-source.t.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "security/transform/stream-source.hpp"
+#include "security/transform/stream-sink.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Security)
+BOOST_AUTO_TEST_SUITE(Transform)
+BOOST_AUTO_TEST_SUITE(TestStreamSource)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  std::string input =
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "01234567012345670123456701234567 1234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567"
+    "0123456701234567012345670123456701234567012345670123456701234567";
+
+  std::stringstream is(input);
+  std::stringstream os;
+  streamSource(is) >> streamSink(os);
+  std::string output = os.str();
+
+  BOOST_CHECK_EQUAL(input, output);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestStreamSource
+BOOST_AUTO_TEST_SUITE_END() // Transform
+BOOST_AUTO_TEST_SUITE_END() // Security
+
+} // namespace tests
+} // namespace transform
+} // namespace security
+} // namespace ndn