digestpp
0.01
Experimental C++11 header-only message digest library.
hasher.hpp
1
/*
2
This code is written by kerukuro and released into public domain.
3
*/
4
5
#
ifndef
DIGESTPP_HASHER_HPP
6
#
define
DIGESTPP_HASHER_HPP
7
8
#
include
<
string
>
9
#
include
<
array
>
10
#
include
<
algorithm
>
11
#
include
<
vector
>
12
#
include
<
iterator
>
13
#
include
<
sstream
>
14
#
include
<
cstring
>
15
#
include
<
iomanip
>
16
17
#
include
"detail/traits.hpp"
18
#
include
"detail/stream_width_fixer.hpp"
19
#
include
"algorithm/mixin/null_mixin.hpp"
20
21
namespace
digestpp
22
{
23
24
/**
25
* \brief Main class template implementing the public API for hashing
26
*
27
* Individual hash functions are defined by typedefs.
28
* See \ref digestpp namespace description for description of supported hash functions with usage examples.
29
*
30
* \param HashProvider A class implementing the algorithm via traditional init/update/final interface.
31
* \param Mixin A class template which can be used to inject additional functions to the public API of the hasher.
32
*
33
* \sa digestpp
34
*/
35
template
<
class
HashProvider,
template
<
class
>
class
Mixin = mixin::
null_mixin
>
36
class
hasher
:
public
Mixin<HashProvider>
37
{
38
public
:
39
40
/**
41
* \brief Default constructor
42
*
43
* \available_if * HashProvider is a hash function with fixed output size, OR
44
* * HashProvider is a hash function with sensible default output size, OR
45
* * HashProvider is an extendable output function (XOF)
46
*/
47
template
<
typename
H
=
HashProvider
,
typename
std
::
enable_if
<
std
::
is_default_constructible
<
H
>::
value
>::
type
* =
nullptr
>
48
hasher
()
49
{
50
provider
.
init
();
51
}
52
53
/**
54
* \brief Constructor with hash size parameter
55
*
56
* Supported output sizes for each algorithm are listed in the description of corresponding typedef.
57
*
58
* \available_if * HashProvider supports multiple output sizes, AND
59
* * HashProvider is not an extendable output function (XOF)
60
*
61
* \param[in] hashsize Desired output digest size (in bits).
62
* \throw std::runtime_error if the requested output size is not supported by the algorithm.
63
*/
64
template
<
typename
H
=
HashProvider
,
typename
std
::
enable_if
<!
detail
::
is_xof
<
H
>::
value
>::
type
* =
nullptr
>
65
hasher
(
size_t
hashsize
) :
provider
(
hashsize
)
66
{
67
provider
.
init
();
68
}
69
70
/**
71
* \brief Absorbs bytes from a C-style pointer to character buffer
72
* \param[in] data Pointer to data to absorb
73
* \param[in] len Size of data to absorb (in bytes)
74
* \return Reference to *this
75
*
76
* @par Example:\n
77
* @code // Calculate SHA-512/256 digest of a C array and output it in hex format
78
* unsigned char c[32];
79
* std::iota(c, c + sizeof(c), 0);
80
* cout << digestpp::sha512(256).absorb(c, sizeof(c)).hexdigest() << std::endl;
81
* @endcode
82
*/
83
template
<
typename
T
,
typename
std
::
enable_if
<
detail
::
is_byte
<
T
>::
value
>::
type
* =
nullptr
>
84
inline
hasher
&
absorb
(
const
T
*
data
,
size_t
len
)
85
{
86
provider
.
update
(
reinterpret_cast
<
const
unsigned
char
*>(
data
),
len
);
87
return
*
this
;
88
}
89
90
/**
91
* \brief Absorbs bytes from std::basic_string
92
* \param[in] str String to absorb
93
* \return Reference to *this
94
*/
95
template
<
typename
T
,
96
typename
std
::
enable_if
<
detail
::
is_byte
<
T
>::
value
&& !
std
::
is_same
<
T
,
std
::
string
::
value_type
>::
value
>::
type
* =
nullptr
>
97
inline
hasher
&
absorb
(
const
std
::
basic_string
<
T
>&
str
)
98
{
99
if
(!
str
.
empty
())
100
provider
.
update
(
reinterpret_cast
<
const
unsigned
char
*>(&
str
[0]),
str
.
size
());
101
return
*
this
;
102
}
103
104
/**
105
* \brief Absorbs bytes from std::string
106
* \param[in] str String to absorb
107
* \return Reference to *this
108
* @par Example:\n
109
* @code // Calculate BLAKE2b-256 digest from an std::string and output it in hex format
110
* std::string str = "The quick brown fox jumps over the lazy dog";
111
* std::cout << digestpp::blake2b(256).absorb(str).hexdigest() << std::endl;
112
* @endcode
113
*/
114
inline
hasher
&
absorb
(
const
std
::
string
&
str
)
115
{
116
if
(!
str
.
empty
())
117
provider
.
update
(
reinterpret_cast
<
const
unsigned
char
*>(&
str
[0]),
str
.
size
());
118
return
*
this
;
119
}
120
121
/**
122
* \brief Absorbs bytes from std::istream
123
* \param[in] istr Stream to absorb
124
* \return Reference to *this
125
* @par Example:\n
126
* @code // Calculate SHA-256 digest of a file and output it in hex format
127
* std::ifstream file("filename", std::ios_base::in|std::ios_base::binary);
128
* std::cout << digestpp::sha256().absorb(file).hexdigest() << std::endl;
129
* @endcode
130
*/
131
template
<
typename
T
,
typename
std
::
enable_if
<
detail
::
is_byte
<
T
>::
value
>::
type
* =
nullptr
>
132
inline
hasher
&
absorb
(
std
::
basic_istream
<
T
>&
istr
)
133
{
134
const
int
tmp_buffer_size
= 10000;
135
unsigned
char
buffer
[
tmp_buffer_size
];
136
size_t
len
= 0;
137
while
(
istr
.
read
(
reinterpret_cast
<
T
*>(
buffer
),
sizeof
(
buffer
)))
138
{
139
provider
.
update
(
buffer
,
sizeof
(
buffer
));
140
len
+=
sizeof
(
buffer
);
141
}
142
size_t
gcount
=
istr
.
gcount
();
143
if
(
gcount
)
144
{
145
provider
.
update
(
buffer
,
gcount
);
146
len
+=
gcount
;
147
}
148
return
*
this
;
149
}
150
151
/**
152
* \brief Absorbs bytes from an iterator sequence
153
* \param[in] begin Begin iterator
154
* \param[in] end End iterator
155
* \return Reference to *this
156
*
157
* @par Example:\n
158
* @code // Calculate SHA-512 digest of a vector and output it in hex format
159
* std::vector<unsigned char> v(100);
160
* std::iota(v.begin(), v.end(), 0);
161
* std::cout << digestpp::sha512().absorb(v.begin(), v.end()).hexdigest() << std::endl;
162
* @endcode
163
*/
164
template
<
typename
IT
>
165
inline
hasher
&
absorb
(
IT
begin
,
IT
end
)
166
{
167
while
(
begin
!=
end
)
168
{
169
unsigned
char
byte
= *
begin
++;
170
provider
.
update
(&
byte
, 1);
171
}
172
return
*
this
;
173
}
174
175
/**
176
* \brief Squeeze bytes into user-provided preallocated buffer.
177
*
178
* After each invocation of this function the internal state of the hasher changes
179
* so that the next call will generate different (additional) output bytes.
180
* To reset the state and start new digest calculation, use \ref reset function.
181
*
182
* \available_if HashProvider is an extendable output function (XOF)
183
*
184
* \param[out] buf Buffer to squeeze data to; must be of byte type (char, unsigned char or signed char)
185
* \param[in] len Size of data to squeeze (in bytes)
186
*/
187
template
<
typename
T
,
typename
H
=
HashProvider
,
188
typename
std
::
enable_if
<
detail
::
is_byte
<
T
>::
value
&&
detail
::
is_xof
<
H
>::
value
>::
type
* =
nullptr
>
189
inline
void
squeeze
(
T
*
buf
,
size_t
len
)
190
{
191
provider
.
squeeze
(
reinterpret_cast
<
unsigned
char
*>(
buf
),
len
);
192
}
193
194
/**
195
* \brief Squeeze bytes into an output iterator.
196
*
197
* After each invocation of this function the internal state of the hasher changes
198
* so that the next call will generate different (additional) output bytes.
199
* To reset the state and start new digest calculation, use \ref reset function.
200
*
201
* \available_if HashProvider is an extendable output function (XOF)
202
*
203
* \param[in] len Size of data to squeeze (in bytes)
204
* \param[out] it output iterator to a byte container
205
* @par Example:\n
206
* @code // Generate long output using SHAKE-256 extendable output function using multiple calls to squeeze()
207
* std::vector<unsigned char> v;
208
* digestpp::shake256 xof;
209
* xof.absorb("The quick brown fox jumps over the lazy dog");
210
* xof.squeeze(1000, back_inserter(v));
211
* xof.squeeze(1000, back_inserter(v));
212
* xof.squeeze(1000, back_inserter(v));
213
* std::cout << "Squeezed " << v.size() << " bytes." << std::endl;
214
* @endcode
215
*/
216
template
<
typename
OI
,
typename
H
=
HashProvider
,
typename
std
::
enable_if
<
detail
::
is_xof
<
H
>::
value
>::
type
* =
nullptr
>
217
inline
void
squeeze
(
size_t
len
,
OI
it
)
218
{
219
std
::
vector
<
unsigned
char
>
hash
(
len
);
220
provider
.
squeeze
(&
hash
[0],
len
);
221
std
::
copy
(
hash
.
begin
(),
hash
.
end
(),
it
);
222
}
223
224
/**
225
* \brief Squeeze bytes and return them as a hex string.
226
*
227
* After each invocation of this function the internal state of the hasher changes
228
* so that the next call will generate different (additional) output bytes.
229
* To reset the state and start new digest calculation, use \ref reset function.
230
*
231
* \available_if HashProvider is an extendable output function (XOF)
232
*
233
* \param[in] len Size of data to squeeze (in bytes)
234
* \return Calculated digest as a hexademical string
235
* @par Example:\n
236
* @code // Generate 64-byte digest using customizable cSHAKE-256 algorithm and print it in hex format
237
* digestpp::cshake256 xof;
238
* xof.set_customization("My Customization");
239
* std::cout << xof.absorb("The quick brown fox jumps over the lazy dog").hexsqueeze(64) << std::endl;
240
* @endcode
241
*/
242
template
<
typename
H
=
HashProvider
,
typename
std
::
enable_if
<
detail
::
is_xof
<
H
>::
value
>::
type
* =
nullptr
>
243
inline
std
::
string
hexsqueeze
(
size_t
len
)
244
{
245
std
::
ostringstream
res
;
246
res
<<
std
::
setfill
(
'0'
) <<
std
::
hex
;
247
squeeze
(
len
,
std
::
ostream_iterator
<
detail
::
stream_width_fixer
<
unsigned
int
, 2>>(
res
,
""
));
248
return
res
.
str
();
249
}
250
251
/**
252
* \brief Output binary digest into user-provided preallocated buffer.
253
*
254
* This function does not change the state of the hasher and can be called multiple times, producing the same result.
255
* To reset the state and start new digest calculation, use \ref reset function.
256
*
257
* \available_if HashProvider is a hash function (not XOF)
258
*
259
* \param[out] buf Buffer to squeeze data to; must be of byte type (char, unsigned char or signed char)
260
* \param[in] len Size of the buffer
261
* \throw std::runtime_error if the buffer size is not enough to fit the calculated digest
262
* (fixed by the algorithm or specified in the hasher constructor).
263
* @par Example:\n
264
* @code // Output binary digest to a raw C array
265
* unsigned char buf[32];
266
* digestpp::sha3(256).absorb("The quick brown fox jumps over the lazy dog").digest(buf, sizeof(buf));
267
* @endcode
268
*/
269
template
<
typename
T
,
typename
H
=
HashProvider
,
270
typename
std
::
enable_if
<
detail
::
is_byte
<
T
>::
value
&& !
detail
::
is_xof
<
H
>::
value
>::
type
* =
nullptr
>
271
inline
void
digest
(
T
*
buf
,
size_t
len
)
const
272
{
273
if
(
len
<
provider
.
hash_size
() / 8)
274
throw
std
::
runtime_error
(
"Invalid buffer size"
);
275
276
HashProvider
copy
(
provider
);
277
copy
.
final
(
buf
);
278
}
279
280
/**
281
* \brief Write binary digest into an output iterator.
282
*
283
* This function does not change the state of the hasher and can be called multiple times, producing the same result.
284
* To reset the state and start new digest calculation, use \ref reset function.
285
*
286
* \available_if HashProvider is a hash function (not XOF)
287
*
288
* \param[out] it Output iterator to a byte container.
289
* @par Example:\n
290
* @code // Output binary SHA3-256 digest to a vector
291
* vector<unsigned char> v;
292
* digestpp::sha3(256).absorb("The quick brown fox jumps over the lazy dog").digest(back_inserter(v));
293
* @endcode
294
*/
295
template
<
typename
OI
,
typename
H
=
HashProvider
,
typename
std
::
enable_if
<!
detail
::
is_xof
<
H
>::
value
>::
type
* =
nullptr
>
296
inline
void
digest
(
OI
it
)
const
297
{
298
HashProvider
copy
(
provider
);
299
std
::
vector
<
unsigned
char
>
hash
(
provider
.
hash_size
() / 8);
300
copy
.
final
(&
hash
[0]);
301
std
::
copy
(
hash
.
begin
(),
hash
.
end
(),
it
);
302
}
303
304
/**
305
* \brief Return hex digest of absorbed data.
306
*
307
* This function does not change the state of the hasher and can be called multiple times, producing the same result.
308
* To reset the state and start new digest calculation, use \ref reset function.
309
*
310
* \available_if HashProvider is a hash function (not XOF)
311
*
312
* \return Calculated digest as a hexademical string
313
* @par Example:\n
314
* @code // Calculate BLAKE2b digest from a double quoted string and output it in hex format
315
* std::cout << digestpp::blake2b().absorb("The quick brown fox jumps over the lazy dog").hexdigest() << std::endl;
316
* @endcode
317
*/
318
template
<
typename
H
=
HashProvider
,
typename
std
::
enable_if
<!
detail
::
is_xof
<
H
>::
value
>::
type
* =
nullptr
>
319
inline
std
::
string
hexdigest
()
const
320
{
321
std
::
ostringstream
res
;
322
res
<<
std
::
setfill
(
'0'
) <<
std
::
hex
;
323
digest
(
std
::
ostream_iterator
<
detail
::
stream_width_fixer
<
unsigned
int
, 2>>(
res
,
""
));
324
return
res
.
str
();
325
}
326
327
/**
328
* \brief Reset the hasher state to start new digest computation.
329
*
330
* \param[in] resetParameters if true, also clear optional parameters (personalization, salt, etc)
331
*/
332
inline
void
reset
(
bool
resetParameters
=
false
)
333
{
334
if
(
resetParameters
)
335
provider
.
clear
();
336
provider
.
init
();
337
}
338
339
private
:
340
friend
Mixin
<
HashProvider
>;
341
HashProvider provider;
342
};
343
344
345
}
// namespace digestpp
346
347
#
endif
// DIGESTPP_HASHER_HPP
digestpp::shake256
hasher< detail::shake_provider< 256, 24 > > shake256
SHAKE256 function.
Definition:
shake.hpp:53
digestpp::mixin::null_mixin
Empty mixin that does not have any additional fuctions.
Definition:
null_mixin.hpp:18
digestpp::hasher::reset
void reset(bool resetParameters=false)
Reset the hasher state to start new digest computation.
Definition:
hasher.hpp:332
Generated by
1.8.13