VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
md5.h
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // md5.h
19 //
20 // An implementation of the RFC-1321 message digest algorithm.
21 //
22 // This code was developed from main body of RFC 1321 without reference to the
23 // RSA reference implementation in the appendix.
24 //
25 // A minor portability advantage over the RSA implementation is that there is no
26 // need to define a datatype that is exactly 32 bits: the requirement is that
27 // 'big_t' is at least 32 bits, but it can be more.
28 //
29 // Stylistic advantages are that it is written in C++ with an enclosing namespace,
30 // it does not use preprocessor macros, and there is an element of layering with
31 // digest_stream built on top of the low-level digest class.
32 //
33 
34 #ifndef MD5_GHW_H
35 #define MD5_GHW_H
36 
37 #include <string> // std::string
38 #include <cstdlib> // std::size_t
39 
40 namespace md5
41 {
42  typedef std::string string_type ; ///< A string type.
43  typedef std::string::size_type size_type ; ///< A std::size_t type.
44  typedef size_type big_t ; ///< To hold at least 32 bits, maybe more. Try unsigned long on small systems.
45  typedef size_type small_t ; ///< To hold at least a size_t. Must fit in a big_t.
46  typedef char assert_big_t_is_big_enough[sizeof(big_t)>=4U?1:-1] ; ///< A static assertion check.
47  typedef char assert_small_t_is_big_enough[sizeof(small_t)>=sizeof(size_type)?1:-1]; ///< A static assertion check.
48  class digest ;
49  class digest_stream ;
50  class format ;
51  class block ;
52 }
53 
54 /// \class md5::digest
55 /// A class that calculates an md5 digest from one or more 64-byte blocks of
56 /// data using the algorithm described by RFC 1321.
57 ///
58 /// Digests are made up of four integers which can be formatted into more
59 /// usable forms using the md5::format class.
60 ///
61 /// A digest can be calculated in one go from an arbitrarily-sized block of
62 /// data, or incrementally from a series of 64-byte blocks. The 64-byte
63 /// blocks must be passed as md5::block objects.
64 ///
65 /// In practice the requirement for 64-byte blocks of input data may be
66 /// inconvenient, so the md5::digest_stream class is provided to allow
67 /// calculation of digests from a stream of arbitrarily-sized data blocks.
68 ///
69 /// \code
70 /// std::string hash( const std::string & in )
71 /// {
72 /// md5::digest d( in ) ;
73 /// return md5::format::rfc( d ) ;
74 /// }
75 /// \endcode
76 ///
78 {
79 public:
80  struct state_type /// Holds the md5 algorithm state. Used by md5::digest.
81  { big_t a ; big_t b ; big_t c ; big_t d ; } ;
82 
83  digest() ;
84  ///< Default constructor. The message to
85  ///< be digested should be add()ed
86  ///< in 64-byte blocks.
87 
88  explicit digest( const string_type & s ) ;
89  ///< Constuctor. Calculates a digest for the
90  ///< given message string. Do not use add()
91  ///< with this constructor.
92 
93  explicit digest( state_type ) ;
94  ///< Constructor taking the result of an
95  ///< earlier call to state(). This allows
96  ///< calculation of a digest from a stream
97  ///< of 64-byte blocks to be suspended
98  ///< mid-stream and then resumed using a
99  ///< new digest object.
100 
101  state_type state() const ;
102  ///< Returns the internal state. Typically
103  ///< passed to the md5::format class.
104 
105  void add( const block & ) ;
106  ///< Adds a 64-byte block of the message.
107 
108 private:
109  typedef big_t (*aux_fn_t)( big_t , big_t , big_t ) ;
110  enum Permutation { ABCD , DABC , CDAB , BCDA } ;
111  big_t a ;
112  big_t b ;
113  big_t c ;
114  big_t d ;
115 
116 private:
117  explicit digest( const block & ) ;
118  void add( const digest & ) ;
119  void init() ;
120  void calculate( const block & ) ;
121  static big_t T( small_t i ) ;
122  static big_t rot32( small_t places , big_t n ) ;
123  void operator()( const block & , aux_fn_t , Permutation , small_t , small_t , small_t ) ;
124  static big_t op( const block & , aux_fn_t , big_t , big_t , big_t , big_t , small_t , small_t , small_t ) ;
125  void round1( const block & ) ;
126  void round2( const block & ) ;
127  void round3( const block & ) ;
128  void round4( const block & ) ;
129  static big_t F( big_t x , big_t y , big_t z ) ;
130  static big_t G( big_t x , big_t y , big_t z ) ;
131  static big_t H( big_t x , big_t y , big_t z ) ;
132  static big_t I( big_t x , big_t y , big_t z ) ;
133 } ;
134 
135 /// \class md5::format
136 /// A static string-formatting class for the output of md5::digest.
137 /// Various static methods are provided to convert the
138 /// md5::digest::state_type structure into more useful formats,
139 /// including the printable format defined by RFC 1321.
140 ///
142 {
143 public:
144  static string_type rfc( const digest & ) ;
145  ///< Returns the digest string in the RFC format.
146 
147  static string_type rfc( const digest::state_type & ) ;
148  ///< Returns the digest string in the RFC format.
149 
150  static string_type raw( const digest::state_type & ) ;
151  ///< Returns the raw digest data as a std::string.
152  ///< The returned std::string buffer will typically
153  ///< contain non-printing characters, including NULs.
154 
155 private:
156  static string_type raw( big_t n ) ;
157  static string_type str( big_t n ) ;
158  static string_type str2( small_t n ) ;
159  static string_type str1( small_t n ) ;
160  format() ; // not implemented
161 } ;
162 
163 /// \class md5::block
164 /// A helper class used by the md5::digest implementation to represent a
165 /// 64-character data block.
166 ///
168 {
169 public:
170  block( const string_type & s , small_t block_offset , big_t end_value ) ;
171  ///< Constructor. Unusually, the string reference is
172  ///< kept, so beware of binding temporaries.
173  ///<
174  ///< The 'block-offset' indicates, in units of 64-character
175  ///< blocks, how far down 's' the current block's data is.
176  ///<
177  ///< The string must hold at least 64 bytes beyond the
178  ///< 'block-offset' point, except for the last block in
179  ///< a message sequence. Note that this is the number
180  ///< of blocks, not the number of bytes.
181  ///<
182  ///< The 'end-value' is derived from the length of the
183  ///< full message (not just the current block). It is only
184  ///< used for the last block. See end().
185 
186  static big_t end( small_t data_length ) ;
187  ///< Takes the total number of bytes in the input message and
188  ///< returns a value which can be passed to the constructor's
189  ///< third parameter. This is used for the last block in
190  ///< the sequence of blocks that make up a complete message.
191 
192  static small_t blocks( small_t data_length ) ;
193  ///< Takes the total number of bytes in the input message and
194  ///< returns the number of 64-byte blocks, allowing for
195  ///< padding. In practice 0..55 maps to 1, 56..119 maps to
196  ///< 2, etc.
197 
198  big_t X( small_t ) const ;
199  ///< Returns a value from within the block. See RFC 1321.
200 
201 private:
202  block( const block & ) ; // not implemented
203  void operator=( const block & ) ; // not implemented
204  small_t x( small_t ) const ;
205  static small_t rounded( small_t n ) ;
206 
207 private:
208  const string_type & m_s ;
209  small_t m_block ;
210  big_t m_end_value ;
211 } ;
212 
213 /// \class md5::digest_stream
214 /// A class that calculates an md5 digest from a data stream
215 /// using the algorithm described by RFC 1321.
216 ///
217 /// The implementation is layered on top of the block-oriented
218 /// md5::digest by adding an element of buffering. The buffering
219 /// allows incremental calculation of an md5 digest without
220 /// requiring either the complete input string or precise
221 /// 64-byte blocks.
222 ///
223 /// \code
224 /// std::string hash( std::istream & in )
225 /// {
226 /// md5::digest_stream d ;
227 /// while( in.good() )
228 /// {
229 /// std::string line ;
230 /// std::getline( in , line ) ;
231 /// d.add( line ) ;
232 /// }
233 /// d.close() ;
234 /// return md5::format::rfc( d ) ;
235 /// }
236 /// \endcode
237 ///
239 {
240 public:
241  struct state_type /// Holds the state of an md5 digest stream. Used by md5::digest_stream.
242  { digest::state_type d ; small_t n ; string_type s ; } ;
243 
244  digest_stream() ;
245  ///< Default constructor.
246 
248  ///< Constructor taking state() allowing digest
249  ///< calculation to be suspended and resumed. The
250  ///< 'n' parameter must be a multiple of sixty-four
251  ///< (since "state_type::s" string is implicitly
252  ///< empty).
253 
254  void add( const string_type & ) ;
255  ///< Adds more message data.
256 
257  void close() ;
258  ///< Called after the last add().
259 
260  small_t size() const ;
261  ///< Returns how many data bytes have been
262  ///< accumulated so far.
263 
264  state_type state() const ;
265  ///< Returns the current state. Only useful after
266  ///< close().
267 
268 private:
269  digest m_digest ;
270  string_type m_buffer ;
271  small_t m_length ;
272 } ;
273 
274 #endif
275 
void add(const string_type &)
Adds more message data.
Definition: md5.cpp:392
A class that calculates an md5 digest from a data stream using the algorithm described by RFC 1321...
Definition: md5.h:238
size_type big_t
To hold at least 32 bits, maybe more. Try unsigned long on small systems.
Definition: md5.h:44
void close()
Called after the last add().
Definition: md5.cpp:405
size_type small_t
To hold at least a size_t. Must fit in a big_t.
Definition: md5.h:45
std::string::size_type size_type
A std::size_t type.
Definition: md5.h:43
big_t X(small_t) const
Returns a value from within the block. See RFC 1321.
Definition: md5.cpp:341
block(const string_type &s, small_t block_offset, big_t end_value)
Constructor.
Definition: md5.cpp:315
digest()
Default constructor.
Definition: md5.cpp:35
Holds the md5 algorithm state. Used by md5::digest.
Definition: md5.h:80
A helper class used by the md5::digest implementation to represent a 64-character data block...
Definition: md5.h:167
A static string-formatting class for the output of md5::digest.
Definition: md5.h:141
std::string string_type
A string type.
Definition: md5.h:42
static small_t blocks(small_t data_length)
Takes the total number of bytes in the input message and returns the number of 64-byte blocks...
Definition: md5.cpp:335
char assert_small_t_is_big_enough[sizeof(small_t)>=sizeof(size_type)?1:-1]
A static assertion check.
Definition: md5.h:47
A class that calculates an md5 digest from one or more 64-byte blocks of data using the algorithm des...
Definition: md5.h:77
small_t size() const
Returns how many data bytes have been accumulated so far.
Definition: md5.cpp:421
state_type state() const
Returns the internal state.
Definition: md5.cpp:48
state_type state() const
Returns the current state.
Definition: md5.cpp:412
static big_t end(small_t data_length)
Takes the total number of bytes in the input message and returns a value which can be passed to the c...
Definition: md5.cpp:322
digest_stream()
Default constructor.
Definition: md5.cpp:381
static string_type rfc(const digest &)
Returns the digest string in the RFC format.
Definition: md5.cpp:274
char assert_big_t_is_big_enough[sizeof(big_t)>=4U?1:-1]
A static assertion check.
Definition: md5.h:46
void add(const block &)
Adds a 64-byte block of the message.
Definition: md5.cpp:73
Holds the state of an md5 digest stream. Used by md5::digest_stream.
Definition: md5.h:241
static string_type raw(const digest::state_type &)
Returns the raw digest data as a std::string.
Definition: md5.cpp:252