BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlde_md5.h
Go to the documentation of this file.
1/// @file bdlde_md5.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlde_md5.h -*-C++-*-
8#ifndef INCLUDED_BDLDE_MD5
9#define INCLUDED_BDLDE_MD5
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlde_md5 bdlde_md5
15/// @brief Provide a value-semantic type encoding a message in an MD5 digest.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlde
19/// @{
20/// @addtogroup bdlde_md5
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlde_md5-purpose"> Purpose</a>
25/// * <a href="#bdlde_md5-classes"> Classes </a>
26/// * <a href="#bdlde_md5-description"> Description </a>
27/// * <a href="#bdlde_md5-security"> Security </a>
28/// * <a href="#bdlde_md5-performance"> Performance </a>
29/// * <a href="#bdlde_md5-usage"> Usage </a>
30/// * <a href="#bdlde_md5-example-1-basic-usage"> Example 1: Basic Usage </a>
31/// * <a href="#bdlde_md5-additional-copyright-notice"> Additional Copyright Notice </a>
32///
33/// # Purpose {#bdlde_md5-purpose}
34/// Provide a value-semantic type encoding a message in an MD5 digest.
35///
36/// # Classes {#bdlde_md5-classes}
37///
38/// - bdlde::Md5: value-semantic type representing an MD5 digest
39///
40/// @see bdlde_crc32
41///
42/// # Description {#bdlde_md5-description}
43/// This component implements a mechanism for computing, updating,
44/// and streaming an MD5 digest (a hash comprising 128 bits). One possible
45/// application is determining whether or not a message was received without
46/// errors, although due to security vulnerabilities, it should no longer be
47/// used for this purpose (see the Security section below). This implementation
48/// is based on the RFC 1321 specification which can be found at:
49/// @code
50/// http://www.ietf.org/rfc/rfc1321.txt
51/// @endcode
52/// Note that an MD5 digest does not aid in error correction.
53///
54/// ## Security {#bdlde_md5-security}
55///
56///
57/// Practical collision and chosen-prefix collision attacks are known against
58/// MD5. Do not use MD5 to generate digital signatures under any circumstances,
59/// and do not use MD5 at all except when it is required for interoperation with
60/// legacy systems that use MD5. SHA-2 (available in the @ref bdlde_sha2
61/// component) and SHA-3 are more secure alternatives to MD5.
62///
63/// You might think that your application doesn't require collision resistance.
64/// However, (1) you might be mistaken, (2) once you start using MD5, you
65/// prevent future versions of your application from being able to rely on
66/// collision resistance unless they break backward compatibility, (3) a
67/// maintainer of your application might accidentally make a change that
68/// implicitly assumes collision resistance, and (4) if you expose MD5 hashes to
69/// your users, they might assume that they are secure digital signatures, which
70/// will make their applications insecure. In light of the foregoing
71/// considerations, and the availability of SHA-2 and SHA-3 as alternatives,
72/// there is no justification for using MD5 unless you absolutely have to.
73///
74/// ## Performance {#bdlde_md5-performance}
75///
76///
77/// The performance of this component is slightly slower than the native
78/// `openssl` implementation of MD5. It is typically within 7% of the speed of
79/// the native `openssl` implementation with an error margin of +/-2%, depending
80/// on machine load. A million iterations of the `update` method will typically
81/// take between 0.84s to 0.90s on Sun and 0.68s to 0.69s on IBM. A million
82/// iterations of the equivalent function in `openssl`, `MD5_Update`, will
83/// typically take between 0.80s to 0.85s on Sun and 0.65s to 0.67s on IBM.
84///
85/// ## Usage {#bdlde_md5-usage}
86///
87///
88/// This section illustrates intended use of this component.
89///
90/// ### Example 1: Basic Usage {#bdlde_md5-example-1-basic-usage}
91///
92///
93/// The following snippets of code illustrate a typical use of the `bdlde::Md5`
94/// class. Each function would typically execute in separate processes or
95/// potentially on separate machines. The `senderExample` function below
96/// demonstrates how a message sender can write a message and its MD5 digest
97/// to a `bdex` output stream. Note that `Out` may be a `typedef` of any class
98/// that implements the `bslx::OutStream` protocol:
99/// @code
100/// /// Write a message and its MD5 digest to the specified `output`
101/// /// stream.
102/// void senderExample(Out& output)
103/// {
104/// // Prepare a message.
105/// bsl::string message = "This is a test message.";
106///
107/// // Generate a digest for `message`.
108/// bdlde::Md5 digest(message.data(), static_cast<int>(message.length()));
109///
110/// // Write the message to `output`.
111/// output << message;
112///
113/// // Write the digest to `output`.
114/// const int VERSION = 1;
115/// digest.bdexStreamOut(output, VERSION);
116/// }
117/// @endcode
118/// The `receiverExample` function below illustrates how a message receiver can
119/// read a message and its MD5 digest from a `bdex` input stream, then perform a
120/// local MD5 computation to verify that the message was received intact. Note
121/// that `In` may be a `typedef` of any class that implements the
122/// `bslx::InStream` protocol:
123/// @code
124/// /// Read a message and its MD5 digest from the specified `input` stream,
125/// /// and verify the integrity of the message.
126/// void receiverExample(In& input)
127/// {
128/// // Read the message from `input`.
129/// bsl::string message;
130/// input >> message;
131///
132/// // Read the digest from `input`.
133/// bdlde::Md5 digest;
134/// const int VERSION = 1;
135/// digest.bdexStreamIn(input, VERSION);
136///
137/// // Locally compute the digest of the received `message`.
138/// bdlde::Md5 digestLocal;
139/// digestLocal.update(message.data(), static_cast<int>(message.length()));
140///
141/// // Verify that the received and locally-computed digests match.
142/// assert(digestLocal == digest);
143/// }
144/// @endcode
145/// Due to security vulnerabilities in the MD5 algorithm (see the Security
146/// section above), the use of MD5 contemplated above is insecure unless the
147/// transmission channel is *completely trusted*, which is often impossible to
148/// guarantee in practice. Therefore, MD5 should no longer be used in this way.
149///
150/// ## Additional Copyright Notice {#bdlde_md5-additional-copyright-notice}
151///
152///
153/// The implementation of this component is *substantially* derived from the RSA
154/// Data Security, Inc. MD5 Message-Digest Algorithm that was published in the
155/// aforementioned RFC 1321.
156/// @}
157/** @} */
158/** @} */
159
160/** @addtogroup bdl
161 * @{
162 */
163/** @addtogroup bdlde
164 * @{
165 */
166/** @addtogroup bdlde_md5
167 * @{
168 */
169
170#include <bdlscm_version.h>
171
172#include <bsls_alignedbuffer.h>
174#include <bsls_types.h>
175
176#include <bsl_cstring.h>
177#include <bsl_iosfwd.h>
178
179
180namespace bdlde {
181
182 // =========
183 // class Md5
184 // =========
185
186/// This `class` represents an MD5 digest that can be updated as additional
187/// data is provided.
188///
189/// More generally, this class supports a complete set of *value*
190/// *semantic* operations, including copy construction, assignment,
191/// equality comparison, `ostream` printing, and `bdex` serialization.
192/// (A precise operational definition of when two instances have the same
193/// value can be found in the description of `operator==` for the class.)
194/// This container is *exception* *neutral* with no guarantee of rollback:
195/// if an exception is thrown during the invocation of a method on a
196/// pre-existing instance, the class is left in a valid state, but its
197/// value is undefined. In no event is memory leaked. Finally, *aliasing*
198/// (e.g., using all or part of an object as both source and destination)
199/// is supported in all cases.
200///
201/// See @ref bdlde_md5
202class Md5 {
203
204 // DATA
205 unsigned int d_state[4]; // state array storing the digest
206
207 bsls::Types::Int64 d_length; // length of the message
208
209 unsigned char d_buffer[64]; // buffer for storing remaining part of
210 // message that is not yet incorporated
211 // into `d_state`
212
213 // FRIENDS
214 friend bool operator==(const Md5&, const Md5&);
215
216 public:
217 // TYPES
218
219 /// A maximally-aligned, 16-byte object type used to represent an MD5
220 /// digest.
222
223 // CLASS METHODS
224
225 /// Return the maximum valid BDEX format version, as indicated by the
226 /// specified `versionSelector`, to be passed to the `bdexStreamOut`
227 /// method. Note that the `versionSelector` is expected to be formatted
228 /// as `yyyymmdd`, a date representation. See the `bslx` package-level
229 /// documentation for more information on BDEX streaming of
230 /// value-semantic types and containers.
231 static int maxSupportedBdexVersion(int);
232
233 // CREATORS
234
235 /// Construct an MD5 digest having the value corresponding to no data
236 /// having been provided.
238
239 /// Construct an MD5 digest corresponding to the specified `data` having
240 /// the specified `length` (in bytes). The behavior is undefined unless
241 /// `0 <= length`. Note that if `data` is 0, then `length` also must
242 /// be 0.
243 Md5(const void *data, int length);
244
245 /// Construct an MD5 digest having the value of the specified `original`
246 /// digest.
247 Md5(const Md5& original);
248
249 /// Destroy this MD5 digest.
251
252 // MANIPULATORS
253
254#if defined(BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS)
255 /// Assign to this MD5 digest the value of the specified `rhs` MD5
256 /// digest and return a reference to this modifiable MD5 digest.
257 Md5& operator=(const Md5& rhs) = default;
258#endif
259
260 /// Assign to this object the value read from the specified input
261 /// `stream` using the specified `version` format and return a reference
262 /// to the modifiable `stream`. If `stream` is initially invalid, this
263 /// operation has no effect. If `stream` becomes invalid during this
264 /// operation, this object is valid, but its value is undefined. If the
265 /// specified `version` is not supported, `stream` is marked invalid,
266 /// but this object is unaltered. Note that no version is read from
267 /// `stream`. (See the package-group-level documentation for more
268 /// information on `bdex` streaming of container types.)
269 template <class STREAM>
270 STREAM& bdexStreamIn(STREAM& stream, int version);
271
272 /// Reset the value of this MD5 digest to the value provided by the
273 /// default constructor.
274 void reset();
275
276 /// Update the value of this MD5 digest to incorporate the specified
277 /// `data` having the specified `length` in bytes. If the current state
278 /// is the default state, the resultant value of this MD5 digest is the
279 /// application of the MD5 algorithm upon the currently given `data` of
280 /// the given `length`. If this digest has been previously provided
281 /// data and has not been subsequently reset, the current state is not
282 /// the default state and the resultant value is equivalent to applying
283 /// the MD5 algorithm upon the concatenation of all the provided data.
284 /// The behavior is undefined unless `0 <= length`. Note that if `data`
285 /// is 0, then `length` also must be 0.
286 void update(const void *data, int length);
287
288 /// Load the current value of this MD5 digest into the specified
289 /// `result` and set the value of this MD5 digest to the value provided
290 /// by the default constructor.
292
293 // ACCESSORS
294
295 /// Write this value to the specified output `stream` and return a
296 /// reference to the modifiable `stream`. Optionally specify an
297 /// explicit `version` format; by default, the maximum supported version
298 /// is written to `stream` and used as the format. If `version` is
299 /// specified, that format is used, but *not* written to `stream`. If
300 /// `version` is not supported, `stream` is left unmodified. (See the
301 /// package-group-level documentation for more information on `bdex`
302 /// streaming of container types).
303 template <class STREAM>
304 STREAM& bdexStreamOut(STREAM& stream, int version) const;
305
306 /// Format the current value of this MD5 digest to the specified output
307 /// `stream` and return a reference to the modifiable `stream`.
308 bsl::ostream& print(bsl::ostream& stream) const;
309
310 /// Load the current value of this MD5 digest into the specified
311 /// `result`.
312 void loadDigest(Md5Digest *result) const;
313
314#ifndef BDE_OMIT_DEPRECATED
315 // CLASS METHODS
316
317 /// Return the most current `bdex` streaming version number supported by
318 /// this class. (See the package-group-level documentation for more
319 /// information on `bdex` streaming of container types.)
320 static int maxSupportedBdexVersion();
321#endif
322};
323
324// FREE OPERATORS
325
326/// Return `true` if the specified `lhs` and `rhs` MD5 digests have the same
327/// value, and `false` otherwise. Two digests have the same value if the
328/// values obtained from their respective `loadDigest` methods are identical.
329bool operator==(const Md5& lhs, const Md5& rhs);
330
331/// Return `true` if the specified `lhs` and `rhs` MD5 digests do not have
332/// the same value, and `false` otherwise. Two digests do not have the same
333/// value if the values obtained from their respective `loadDigest` methods
334/// differ.
335inline
336bool operator!=(const Md5& lhs, const Md5& rhs);
337
338/// Write to the specified output `stream` the specified MD5 `digest` and
339/// return a reference to the modifiable `stream`.
340inline
341bsl::ostream& operator<<(bsl::ostream& stream, const Md5& digest);
342
343// ============================================================================
344// INLINE FUNCTION DEFINITIONS
345// ============================================================================
346
347 // ---------
348 // class Md5
349 // ---------
350
351// CLASS METHODS
352inline
354{
355 return 1;
356}
357
358// MANIPULATORS
359template <class STREAM>
360STREAM& Md5::bdexStreamIn(STREAM& stream, int version)
361{
362 switch (version) {
363 case 1: {
364 unsigned int state[4];
365 unsigned char buf[64];
366 bsls::Types::Int64 length;
367
368 // first the state
369
370 for (int i = 0; i < 4; i++) {
371 stream.getUint32(state[i]);
372 }
373
374 // then the length
375
376 stream.getInt64(length);
377
378 // finally the buffer
379
380 for (int i = 0; i < 64; i++) {
381 stream.getUint8(buf[i]);
382 }
383
384 if (!stream) {
385 return stream; // RETURN
386 }
387
388 d_length = length;
389 bsl::memcpy(d_state, state, sizeof state);
390 bsl::memcpy(d_buffer, buf, sizeof buf);
391
392 } break;
393 default: {
394 stream.invalidate();
395 } break;
396 }
397 return stream;
398}
399
400// ACCESSORS
401template <class STREAM>
402STREAM& Md5::bdexStreamOut(STREAM& stream, int version) const
403{
404 if (stream) {
405 switch (version) {
406 case 1: {
407 // first the state
408
409 for (int i = 0; i < 4; ++i) {
410 stream.putUint32(d_state[i]);
411 }
412
413 // then the length
414
415 stream.putInt64(d_length);
416
417 // finally the buffer
418
419 for (int i = 0; i < 64; ++i) {
420 stream.putUint8(d_buffer[i]);
421 }
422
423 } break;
424 default: {
425 stream.invalidate();
426 } break;
427 }
428 }
429 return stream;
430}
431
432#ifndef BDE_OMIT_DEPRECATED
433inline
438#endif
439
440} // close package namespace
441
442// FREE OPERATORS
443inline
444bool bdlde::operator!=(const Md5& lhs, const Md5& rhs)
445{
446 return !(lhs == rhs);
447}
448
449inline
450bsl::ostream& bdlde::operator<<(bsl::ostream& stream, const Md5& digest)
451{
452 return digest.print(stream);
453}
454
455
456
457#endif
458
459// ----------------------------------------------------------------------------
460// Copyright 2018 Bloomberg Finance L.P.
461//
462// Licensed under the Apache License, Version 2.0 (the "License");
463// you may not use this file except in compliance with the License.
464// You may obtain a copy of the License at
465//
466// http://www.apache.org/licenses/LICENSE-2.0
467//
468// Unless required by applicable law or agreed to in writing, software
469// distributed under the License is distributed on an "AS IS" BASIS,
470// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
471// See the License for the specific language governing permissions and
472// limitations under the License.
473// ----------------------------- END-OF-FILE ----------------------------------
474
475/** @} */
476/** @} */
477/** @} */
Definition bdlde_md5.h:202
void loadDigest(Md5Digest *result) const
Md5(const Md5 &original)
bsls::AlignedBuffer< 16 > Md5Digest
Definition bdlde_md5.h:221
STREAM & bdexStreamIn(STREAM &stream, int version)
Definition bdlde_md5.h:360
static int maxSupportedBdexVersion()
Definition bdlde_md5.h:434
friend bool operator==(const Md5 &, const Md5 &)
Md5(const void *data, int length)
void update(const void *data, int length)
void loadDigestAndReset(Md5Digest *result)
bsl::ostream & print(bsl::ostream &stream) const
STREAM & bdexStreamOut(STREAM &stream, int version) const
Definition bdlde_md5.h:402
~Md5()
Destroy this MD5 digest.
void reset()
Definition bsls_alignedbuffer.h:261
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlde_base64alphabet.h:118
bool operator!=(const Base64DecoderOptions &lhs, const Base64DecoderOptions &rhs)
bsl::ostream & operator<<(bsl::ostream &stream, Base64Alphabet::Enum value)
long long Int64
Definition bsls_types.h:132