BDE 4.39.x 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` method.
227 ///
228 /// \note Note that the `versionSelector` is expected to be formatted
229 /// as `yyyymmdd`, a date representation. See the `bslx` package-level
230 /// documentation for more information on BDEX streaming of
231 /// value-semantic types and containers.
232 static int maxSupportedBdexVersion(int);
233
234 // CREATORS
235
236 /// Construct an MD5 digest having the value corresponding to no data
237 /// having been provided.
239
240 /// Construct an MD5 digest corresponding to the specified `data` having the specified `length` (in bytes).
241 ///
242 /// \pre The behavior is undefined unless `0 <= length`.
243 ///
244 /// \note Note that if `data` is 0, then `length` also must
245 /// be 0.
246 Md5(const void *data, int length);
247
248 /// Construct an MD5 digest having the value of the specified `original`
249 /// digest.
250 Md5(const Md5& original);
251
252 /// Destroy this MD5 digest.
254
255 // MANIPULATORS
256
257#if defined(BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS)
258 /// Assign to this MD5 digest the value of the specified `rhs` MD5
259 /// digest and return a reference to this modifiable MD5 digest.
260 Md5& operator=(const Md5& rhs) = default;
261#endif
262
263 /// Assign to this object the value read from the specified input
264 /// `stream` using the specified `version` format and return a reference
265 /// to the modifiable `stream`. If `stream` is initially invalid, this
266 /// operation has no effect. If `stream` becomes invalid during this
267 /// operation, this object is valid, but its value is undefined. If the
268 /// specified `version` is not supported, `stream` is marked invalid, but this object is unaltered.
269 ///
270 /// \note Note that no version is read from
271 /// `stream`. (See the package-group-level documentation for more
272 /// information on `bdex` streaming of container types.)
273 template <class STREAM>
274 STREAM& bdexStreamIn(STREAM& stream, int version);
275
276 /// Reset the value of this MD5 digest to the value provided by the
277 /// default constructor.
278 void reset();
279
280 /// Update the value of this MD5 digest to incorporate the specified
281 /// `data` having the specified `length` in bytes. If the current state
282 /// is the default state, the resultant value of this MD5 digest is the
283 /// application of the MD5 algorithm upon the currently given `data` of
284 /// the given `length`. If this digest has been previously provided
285 /// data and has not been subsequently reset, the current state is not
286 /// the default state and the resultant value is equivalent to applying
287 /// the MD5 algorithm upon the concatenation of all the provided data.
288 ///
289 /// \pre The behavior is undefined unless `0 <= length`.
290 /// \note Note that if `data`
291 /// is 0, then `length` also must be 0.
292 void update(const void *data, int length);
293
294 /// Load the current value of this MD5 digest into the specified
295 /// `result` and set the value of this MD5 digest to the value provided
296 /// by the default constructor.
298
299 // ACCESSORS
300
301 /// Write this value to the specified output `stream` and return a
302 /// reference to the modifiable `stream`. Optionally specify an
303 /// explicit `version` format; by default, the maximum supported version
304 /// is written to `stream` and used as the format. If `version` is
305 /// specified, that format is used, but *not* written to `stream`. If
306 /// `version` is not supported, `stream` is left unmodified. (See the
307 /// package-group-level documentation for more information on `bdex`
308 /// streaming of container types).
309 template <class STREAM>
310 STREAM& bdexStreamOut(STREAM& stream, int version) const;
311
312 /// Format the current value of this MD5 digest to the specified output
313 /// `stream` and return a reference to the modifiable `stream`.
314 bsl::ostream& print(bsl::ostream& stream) const;
315
316 /// Load the current value of this MD5 digest into the specified
317 /// `result`.
318 void loadDigest(Md5Digest *result) const;
319
320#ifndef BDE_OMIT_DEPRECATED
321 // CLASS METHODS
322
323 /// Return the most current `bdex` streaming version number supported by
324 /// this class. (See the package-group-level documentation for more
325 /// information on `bdex` streaming of container types.)
326 static int maxSupportedBdexVersion();
327#endif
328};
329
330// FREE OPERATORS
331
332/// Return `true` if the specified `lhs` and `rhs` MD5 digests have the same
333/// value, and `false` otherwise. Two digests have the same value if the
334/// values obtained from their respective `loadDigest` methods are identical.
335bool operator==(const Md5& lhs, const Md5& rhs);
336
337/// Return `true` if the specified `lhs` and `rhs` MD5 digests do not have
338/// the same value, and `false` otherwise. Two digests do not have the same
339/// value if the values obtained from their respective `loadDigest` methods
340/// differ.
341inline
342bool operator!=(const Md5& lhs, const Md5& rhs);
343
344/// Write to the specified output `stream` the specified MD5 `digest` and
345/// return a reference to the modifiable `stream`.
346inline
347bsl::ostream& operator<<(bsl::ostream& stream, const Md5& digest);
348
349// ============================================================================
350// INLINE FUNCTION DEFINITIONS
351// ============================================================================
352
353 // ---------
354 // class Md5
355 // ---------
356
357// CLASS METHODS
358inline
360{
361 return 1;
362}
363
364// MANIPULATORS
365template <class STREAM>
366STREAM& Md5::bdexStreamIn(STREAM& stream, int version)
367{
368 switch (version) {
369 case 1: {
370 unsigned int state[4];
371 unsigned char buf[64];
372 bsls::Types::Int64 length;
373
374 // first the state
375
376 for (int i = 0; i < 4; i++) {
377 stream.getUint32(state[i]);
378 }
379
380 // then the length
381
382 stream.getInt64(length);
383
384 // finally the buffer
385
386 for (int i = 0; i < 64; i++) {
387 stream.getUint8(buf[i]);
388 }
389
390 if (!stream) {
391 return stream; // RETURN
392 }
393
394 d_length = length;
395 bsl::memcpy(d_state, state, sizeof state);
396 bsl::memcpy(d_buffer, buf, sizeof buf);
397
398 } break;
399 default: {
400 stream.invalidate();
401 } break;
402 }
403 return stream;
404}
405
406// ACCESSORS
407template <class STREAM>
408STREAM& Md5::bdexStreamOut(STREAM& stream, int version) const
409{
410 if (stream) {
411 switch (version) {
412 case 1: {
413 // first the state
414
415 for (int i = 0; i < 4; ++i) {
416 stream.putUint32(d_state[i]);
417 }
418
419 // then the length
420
421 stream.putInt64(d_length);
422
423 // finally the buffer
424
425 for (int i = 0; i < 64; ++i) {
426 stream.putUint8(d_buffer[i]);
427 }
428
429 } break;
430 default: {
431 stream.invalidate();
432 } break;
433 }
434 }
435 return stream;
436}
437
438#ifndef BDE_OMIT_DEPRECATED
439inline
444#endif
445
446} // close package namespace
447
448// FREE OPERATORS
449inline
450bool bdlde::operator!=(const Md5& lhs, const Md5& rhs)
451{
452 return !(lhs == rhs);
453}
454
455inline
456bsl::ostream& bdlde::operator<<(bsl::ostream& stream, const Md5& digest)
457{
458 return digest.print(stream);
459}
460
461
462
463#endif
464
465// ----------------------------------------------------------------------------
466// Copyright 2018 Bloomberg Finance L.P.
467//
468// Licensed under the Apache License, Version 2.0 (the "License");
469// you may not use this file except in compliance with the License.
470// You may obtain a copy of the License at
471//
472// http://www.apache.org/licenses/LICENSE-2.0
473//
474// Unless required by applicable law or agreed to in writing, software
475// distributed under the License is distributed on an "AS IS" BASIS,
476// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
477// See the License for the specific language governing permissions and
478// limitations under the License.
479// ----------------------------- END-OF-FILE ----------------------------------
480
481/** @} */
482/** @} */
483/** @} */
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:366
static int maxSupportedBdexVersion()
Definition bdlde_md5.h:440
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:408
~Md5()
Destroy this MD5 digest.
void reset()
Definition bsls_alignedbuffer.h:262
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
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:134