]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_md5.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_md5.h
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 /*
28  * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
29  * MD5 Message-Digest Algorithm (RFC 1321).
30  *
31  * Homepage:
32  * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
33  *
34  * Author:
35  * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
36  *
37  * This software was written by Alexander Peslyak in 2001.  No copyright is
38  * claimed, and the software is hereby placed in the public domain.
39  * In case this attempt to disclaim copyright and place the software in the
40  * public domain is deemed null and void, then the software is
41  * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
42  * general public under the following terms:
43  *
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted.
46  *
47  * There's ABSOLUTELY NO WARRANTY, express or implied.
48  *
49  * See md5.c for more information.
50  */
51
52 #if !defined(_MD5_H)
53 #define _MD5_H
54
55 #include "vogl_core.h"
56 #include "vogl_json.h"
57 #include "vogl_data_stream_serializer.h"
58
59 namespace vogl
60 {
61
62     /* Any 32-bit or wider unsigned integer data type will do */
63     typedef unsigned int MD5_u32plus;
64
65     struct MD5_CTX
66     {
67         MD5_u32plus lo, hi;
68         MD5_u32plus a, b, c, d;
69         unsigned char buffer[64];
70         MD5_u32plus block[16];
71     };
72
73     void MD5_Init(MD5_CTX *ctx);
74     void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
75     void MD5_Final(unsigned char *result, MD5_CTX *ctx);
76     void MD5_Final(MD5_CTX *ctx);
77
78     // rg: Basic C++ helpers
79     class md5_hash : public utils::relative_ops<md5_hash>
80     {
81     public:
82         inline md5_hash()
83         {
84         }
85         inline md5_hash(uint32 a, uint32 b, uint32 c, uint32 d)
86         {
87             init(a, b, c, d);
88         }
89
90         // pStr must be zero terminated, 32 hex chars, big endian order
91         inline md5_hash(const char *pStr)
92         {
93             bool success = init(pStr);
94             VOGL_ASSERT(success);
95             VOGL_NOTE_UNUSED(success);
96         }
97
98         // pStr must be zero terminated, 32 hex chars, big endian order
99         inline bool init(const char *pStr)
100         {
101             if (vogl_strlen(pStr) != 32)
102                 return false;
103
104             for (uint i = 0; i < 16; ++i)
105             {
106                 const int v1 = utils::from_hex(pStr[i * 2]);
107                 const int v0 = utils::from_hex(pStr[i * 2 + 1]);
108                 if ((v0 < 0) || (v1 < 0))
109                     return false;
110
111                 uint v = v0 | (v1 << 4);
112
113                 reinterpret_cast<uint8 *>(m_state)[i] = static_cast<uint8>(v);
114             }
115
116             return true;
117         }
118
119         inline dynamic_string &get_string(dynamic_string &str) const
120         {
121             const uint8 *pHash = reinterpret_cast<const uint8 *>(m_state);
122             str.set_len(32);
123             for (uint i = 0; i < 16; i++)
124             {
125                 str.set_char(i * 2, utils::to_hex(pHash[i] >> 4));
126                 str.set_char(i * 2 + 1, utils::to_hex(pHash[i] & 0xF));
127             }
128             return str;
129         }
130
131         inline void clear()
132         {
133             utils::zero_object(*this);
134         }
135
136         inline void init(uint32 a, uint32 b, uint32 c, uint32 d)
137         {
138             m_state[0] = a;
139             m_state[1] = b;
140             m_state[2] = c;
141             m_state[3] = d;
142         }
143
144         // size() is in uint32's, not bytes!
145         inline uint size() const
146         {
147             return cStateSize;
148         }
149         inline uint32 operator[](uint index) const
150         {
151             return m_state[vogl_assert_range<uint>(index, cStateSize)];
152         }
153         inline uint32 &operator[](uint index)
154         {
155             return m_state[vogl_assert_range<uint>(index, cStateSize)];
156         }
157
158         inline uint size_in_bytes() const
159         {
160             return cStateSize * sizeof(uint32);
161         }
162         inline const void *get_ptr() const
163         {
164             return m_state;
165         }
166         inline void set(const void *p)
167         {
168             memcpy(m_state, p, size_in_bytes());
169         }
170
171         inline bool operator==(const md5_hash &rhs) const
172         {
173             for (uint i = 0; i < cStateSize; i++)
174                 if (m_state[i] != rhs.m_state[i])
175                     return false;
176             return true;
177         }
178
179         inline bool operator<(const md5_hash &rhs) const
180         {
181             for (uint i = 0; i < cStateSize; i++)
182                 if (m_state[i] < rhs.m_state[i])
183                     return true;
184                 else if (m_state[i] != rhs.m_state[i])
185                     return false;
186             return false;
187         }
188
189         inline bool json_serialize(json_node &dst_node, const char *pKey) const
190         {
191             return json_serialize(dst_node.add(pKey));
192         }
193
194         inline bool json_serialize(json_value &dst_val) const
195         {
196             dynamic_string str;
197             get_string(str);
198             dst_val.set_value(str);
199             return true;
200         }
201
202         inline bool json_deserialize(const json_node &src_node, const char *pKey)
203         {
204             return json_deserialize(src_node.find_value(pKey));
205         }
206
207         inline bool json_deserialize(const json_value &src_val)
208         {
209             const char *pStr = src_val.as_string_ptr();
210             return pStr ? init(pStr) : false;
211         }
212
213         friend inline data_stream_serializer &operator<<(data_stream_serializer &serializer, const md5_hash &h)
214         {
215             serializer.write(&h.m_state, sizeof(h.m_state));
216             return serializer;
217         }
218
219         friend inline data_stream_serializer &operator>>(data_stream_serializer &serializer, md5_hash &h)
220         {
221             serializer.read(&h.m_state, sizeof(h.m_state));
222             return serializer;
223         }
224
225         inline operator size_t() const
226         {
227             return (size_t)fast_hash(this, sizeof(*this));
228         }
229
230     private:
231         enum
232         {
233             cStateSize = 4
234         };
235         uint32 m_state[cStateSize];
236     };
237
238     class md5_hash_gen
239     {
240     public:
241         inline md5_hash_gen()
242         {
243             clear();
244         }
245
246         inline md5_hash_gen(const void *p, uint n)
247         {
248             clear();
249             update(p, n);
250         }
251
252         inline md5_hash_gen(const char *pStr)
253         {
254             clear();
255             update(pStr);
256         }
257
258         inline md5_hash_gen(const dynamic_string &str)
259         {
260             clear();
261             update(str);
262         }
263
264         inline md5_hash_gen(const md5_hash_gen &other)
265         {
266             set(other);
267         }
268
269         inline md5_hash_gen &set(const md5_hash_gen &rhs)
270         {
271             memcpy(&m_ctx, &rhs.m_ctx, sizeof(m_ctx));
272             return *this;
273         }
274
275         inline void clear()
276         {
277             MD5_Init(&m_ctx);
278         }
279
280         // finalize() doesn't invalidate the current hash, so it can be continued,
281         // and there's never any question that this object is in a valid state of not.
282         inline md5_hash finalize() const
283         {
284             MD5_CTX tmp_ctx;
285             memcpy(&tmp_ctx, &m_ctx, sizeof(m_ctx));
286             MD5_Final(&tmp_ctx);
287             return md5_hash(tmp_ctx.a, tmp_ctx.b, tmp_ctx.c, tmp_ctx.d);
288         }
289
290         inline md5_hash_gen &update(const char *pStr)
291         {
292             uint len = vogl_strlen(pStr);
293             if (len)
294                 update(pStr, len);
295             return *this;
296         }
297
298         inline md5_hash_gen &update(const dynamic_string &str)
299         {
300             if (str.get_len())
301                 update(str.get_ptr(), str.get_len());
302             return *this;
303         }
304
305         // Hashes v as big endian
306         inline md5_hash_gen &update(uint64_t v)
307         {
308             uint8 octets[8];
309             for (uint i = 0; i < 8; i++)
310             {
311                 octets[i] = static_cast<uint8>((v >> 56U) & 0xFF);
312                 v <<= 8U;
313             }
314             return update(octets, sizeof(octets));
315         }
316
317         // Hashes v as big endian
318         inline md5_hash_gen &update(uint32 v)
319         {
320             uint8 octets[4];
321             octets[0] = (v >> 24U) & 0xFF;
322             octets[1] = (v >> 16U) & 0xFF;
323             octets[2] = (v >> 8U) & 0xFF;
324             octets[3] = v & 0xFF;
325             return update(octets, sizeof(octets));
326         }
327
328         // Hashes v as big endian
329         inline md5_hash_gen &update(uint16 v)
330         {
331             uint8 octets[2];
332             octets[0] = (v >> 16U) & 0xFF;
333             octets[1] = v & 0xFF;
334             return update(octets, sizeof(octets));
335         }
336
337         inline md5_hash_gen &update(const void *p, uint32 n)
338         {
339             MD5_Update(&m_ctx, p, n);
340             return *this;
341         }
342
343         inline md5_hash_gen &update(const uint8_vec &buf)
344         {
345             return update(buf.get_ptr(), buf.size());
346         }
347
348         template <typename T>
349         inline md5_hash_gen &update_obj_bits(const T &obj)
350         {
351             return update(&obj, sizeof(obj));
352         }
353
354         inline md5_hash_gen &update_huge_buf(const void *p, uint64_t n)
355         {
356             while (n)
357             {
358                 unsigned long bytes_to_process = static_cast<unsigned long>(math::minimum<uint64_t>(cUINT32_MAX, n));
359                 MD5_Update(&m_ctx, p, bytes_to_process);
360
361                 n -= bytes_to_process;
362                 p = static_cast<const uint8 *>(p) + bytes_to_process;
363             }
364             return *this;
365         }
366
367     private:
368         MD5_CTX m_ctx;
369     };
370
371     bool md5_test();
372
373 } // namespace vogl
374
375 #endif