blob: 40d0100be7f7ebeee1efe4f7c26095d26911aff5 [file] [log] [blame]
Yingdi Yude222c72014-08-15 16:06:52 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento94368312017-07-08 22:25:03 -04002/*
Alexander Afanasyev574aa862017-01-10 19:53:28 -08003 * Copyright (c) 2013-2017 Regents of the University of California.
Yingdi Yude222c72014-08-15 16:06:52 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#ifndef NDN_UTIL_DIGEST_HPP
23#define NDN_UTIL_DIGEST_HPP
24
Yingdi Yude222c72014-08-15 16:06:52 -070025#include "concepts.hpp"
Davide Pesavento94368312017-07-08 22:25:03 -040026#include "crypto.hpp"
27#include "../encoding/block.hpp"
28#include "../encoding/buffer-stream.hpp"
29#include "../security/transform/step-source.hpp"
Yingdi Yude222c72014-08-15 16:06:52 -070030
31namespace ndn {
32namespace util {
33
34/**
Alexander Afanasyev574aa862017-01-10 19:53:28 -080035 * @brief provides a stateful digest calculation
Yingdi Yude222c72014-08-15 16:06:52 -070036 *
Alexander Afanasyev574aa862017-01-10 19:53:28 -080037 * SHA256 example:
Yingdi Yude222c72014-08-15 16:06:52 -070038 *
39 * Digest<CryptoPP::SHA256> digest;
40 * digest.update(buf1, size1);
41 * digest.update(buf2, size2);
42 * ...
43 * ConstBufferPtr result = digest.computeDigest();
Yingdi Yude222c72014-08-15 16:06:52 -070044 */
45template<typename Hash>
46class Digest
47{
48public:
49 BOOST_CONCEPT_ASSERT((Hashable<Hash>));
50
51 typedef Hash HashFunction;
52
53 class Error : public std::runtime_error
54 {
55 public:
56 explicit
57 Error(const std::string& what)
58 : std::runtime_error(what)
59 {
60 }
61 };
62
63 Digest();
64
65 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -080066 * @brief Calculate digest of the input stream @p is
Alexander Afanasyevd27334f2015-07-01 21:44:36 -070067 * @param is input stream
68 */
69 explicit
70 Digest(std::istream& is);
71
72 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -080073 * @brief Discard the current state and start a new digest calculation.
Yingdi Yude222c72014-08-15 16:06:52 -070074 */
75 void
76 reset();
77
78 /**
79 * @brief Check if digest is empty.
80 *
81 * An empty digest means nothing has been taken into calculation.
82 */
83 bool
84 empty() const
85 {
86 return !m_isInProcess;
87 }
88
89 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -080090 * @brief Finalize and return the digest based on all previously supplied inputs.
Yingdi Yude222c72014-08-15 16:06:52 -070091 */
92 ConstBufferPtr
93 computeDigest();
94
95 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -080096 * @brief Check if the supplied digest equals to this digest
Yingdi Yude222c72014-08-15 16:06:52 -070097 *
Alexander Afanasyev574aa862017-01-10 19:53:28 -080098 * @note This method will invoke computeDigest(), finalizing the digest.
Yingdi Yude222c72014-08-15 16:06:52 -070099 */
100 bool
101 operator==(Digest<Hash>& digest);
102
103 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800104 * @brief Check if the supplied digest is not equal to this digest
Yingdi Yude222c72014-08-15 16:06:52 -0700105 *
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800106 * @note This method will invoke computeDigest(), finalizing the digest.
Yingdi Yude222c72014-08-15 16:06:52 -0700107 */
108 bool
109 operator!=(Digest<Hash>& digest)
110 {
111 return !(*this == digest);
112 }
113
114 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800115 * @brief Add existing digest to the digest calculation
Yingdi Yude222c72014-08-15 16:06:52 -0700116 * @param src digest to combine with
117 *
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800118 * The result of this combination is `digest(digest(...))`
119 *
120 * @note This method will invoke computeDigest(), finalizing the digest.
Yingdi Yude222c72014-08-15 16:06:52 -0700121 */
122 Digest<Hash>&
123 operator<<(Digest<Hash>& src);
124
125 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800126 * @brief Add string to the digest calculation
Yingdi Yude222c72014-08-15 16:06:52 -0700127 * @param str string to put into digest
128 */
129 Digest<Hash>&
130 operator<<(const std::string& str);
131
132 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800133 * @brief Add block to the digest calculation
134 * @param block data block to put into digest
135 * @throw Error the digest has been finalized.
Yingdi Yude222c72014-08-15 16:06:52 -0700136 */
137 Digest<Hash>&
138 operator<<(const Block& block);
139
140 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800141 * @brief Add uint64_t value to the digest calculation
142 * @param value the integer value to put into digest
143 * @throw Error the digest has been finalized.
Yingdi Yude222c72014-08-15 16:06:52 -0700144 */
145 Digest<Hash>&
146 operator<<(uint64_t value);
147
148 /**
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800149 * @brief Add a buffer to the digest calculation
Yingdi Yude222c72014-08-15 16:06:52 -0700150 *
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800151 * Update the state of the digest if it has not been finalized and mark the digest as
152 * InProcess.
Yingdi Yude222c72014-08-15 16:06:52 -0700153 *
154 * @param buffer the input buffer
155 * @param size the size of the input buffer.
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800156 * @throw Error the digest has been finalized.
Yingdi Yude222c72014-08-15 16:06:52 -0700157 */
158 void
159 update(const uint8_t* buffer, size_t size);
160
161 /**
162 * @brief Compute one-time digest
163 * @param buffer the input buffer
164 * @param size the size of the input buffer.
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800165 * @return digest computed according to the `Hash` algorithm
Yingdi Yude222c72014-08-15 16:06:52 -0700166 */
167 static ConstBufferPtr
168 computeDigest(const uint8_t* buffer, size_t size);
169
Yingdi Yu9ad2d722014-08-30 16:13:57 -0700170 /**
171 * @brief Convert digest to std::string
172 *
Alexander Afanasyev574aa862017-01-10 19:53:28 -0800173 * @note This method will invoke computeDigest(), finalizing the digest.
Yingdi Yu9ad2d722014-08-30 16:13:57 -0700174 */
175 std::string
176 toString();
Yingdi Yude222c72014-08-15 16:06:52 -0700177
178private:
179 /**
180 * @brief Finalize digest.
181 *
182 * All subsequent calls to "operator<<" will throw an exception
183 */
184 void
185 finalize();
186
187private:
188 Hash m_hash;
189 BufferPtr m_buffer;
190 bool m_isInProcess;
191 bool m_isFinalized;
192};
193
Yingdi Yu9ad2d722014-08-30 16:13:57 -0700194template<typename Hash>
195std::ostream&
196operator<<(std::ostream& os, Digest<Hash>& digest);
197
Davide Pesavento94368312017-07-08 22:25:03 -0400198
Yingdi Yude222c72014-08-15 16:06:52 -0700199/**
Davide Pesavento94368312017-07-08 22:25:03 -0400200 * @brief Provides stateful SHA-256 digest calculation.
201 *
202 * Example:
203 * @code
204 * Sha256 digest;
205 * digest.update(buf1, size1);
206 * digest.update(buf2, size2);
207 * ...
208 * ConstBufferPtr result = digest.computeDigest();
209 * @endcode
Yingdi Yude222c72014-08-15 16:06:52 -0700210 */
Davide Pesavento94368312017-07-08 22:25:03 -0400211class Sha256
212{
213public:
214 class Error : public std::runtime_error
215 {
216 public:
217 explicit
218 Error(const std::string& what)
219 : std::runtime_error(what)
220 {
221 }
222 };
223
224 /**
225 * @brief Create an empty SHA-256 digest.
226 */
227 Sha256();
228
229 /**
230 * @brief Calculate SHA-256 digest of the input stream @p is.
231 */
232 explicit
233 Sha256(std::istream& is);
234
235 /**
236 * @brief Check if digest is empty.
237 *
238 * An empty digest means nothing has been taken into calculation.
239 */
240 bool
241 empty() const
242 {
243 return m_isEmpty;
244 }
245
246 /**
247 * @brief Discard the current state and start a new digest calculation.
248 */
249 void
250 reset();
251
252 /**
253 * @brief Finalize and return the digest based on all previously supplied inputs.
254 */
255 ConstBufferPtr
256 computeDigest();
257
258 /**
259 * @brief Check if the supplied digest is equal to this digest.
260 * @note This method invokes computeDigest() on both operands, finalizing the digest.
261 */
262 bool
263 operator==(Sha256& digest);
264
265 /**
266 * @brief Check if the supplied digest is not equal to this digest.
267 * @note This method invokes computeDigest() on both operands, finalizing the digest.
268 */
269 bool
270 operator!=(Sha256& digest)
271 {
272 return !(*this == digest);
273 }
274
275 /**
276 * @brief Add existing digest to the digest calculation.
277 * @param src digest to combine with
278 *
279 * The result of this combination is `sha256(sha256(...))`
280 *
281 * @note This method invokes computeDigest() on @p src, finalizing the digest.
282 * @throw Error the digest has already been finalized
283 */
284 Sha256&
285 operator<<(Sha256& src);
286
287 /**
288 * @brief Add a string to the digest calculation.
289 * @throw Error the digest has already been finalized
290 */
291 Sha256&
292 operator<<(const std::string& str);
293
294 /**
295 * @brief Add a block to the digest calculation.
296 * @throw Error the digest has already been finalized
297 */
298 Sha256&
299 operator<<(const Block& block);
300
301 /**
302 * @brief Add a uint64_t value to the digest calculation.
303 * @throw Error the digest has already been finalized
304 */
305 Sha256&
306 operator<<(uint64_t value);
307
308 /**
309 * @brief Add a raw buffer to the digest calculation.
310 * @param buffer the input buffer
311 * @param size the size of the input buffer
312 * @throw Error the digest has already been finalized
313 */
314 void
315 update(const uint8_t* buffer, size_t size);
316
317 /**
318 * @brief Convert digest to std::string.
319 * @note This method invokes computeDigest(), finalizing the digest.
320 */
321 std::string
322 toString();
323
324 /**
325 * @brief Compute a one-time SHA-256 digest.
326 * @param buffer the input buffer
327 * @param size the size of the input buffer
328 * @return SHA-256 digest of the input buffer
329 */
330 static ConstBufferPtr
331 computeDigest(const uint8_t* buffer, size_t size)
332 {
333 return crypto::computeSha256Digest(buffer, size);
334 }
335
336private:
337 unique_ptr<security::transform::StepSource> m_input;
338 unique_ptr<OBufferStream> m_output;
339 bool m_isEmpty;
340 bool m_isFinalized;
341};
342
343std::ostream&
344operator<<(std::ostream& os, Sha256& digest);
Yingdi Yude222c72014-08-15 16:06:52 -0700345
346} // namespace util
347} // namespace ndn
348
349#endif // NDN_UTIL_DIGEST_HPP