1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
25 **************************************************************************/
28 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
29 * MD5 Message-Digest Algorithm (RFC 1321).
32 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
35 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
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:
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted.
47 * There's ABSOLUTELY NO WARRANTY, express or implied.
49 * See md5.c for more information.
55 #include "vogl_core.h"
56 #include "vogl_json.h"
57 #include "vogl_data_stream_serializer.h"
62 /* Any 32-bit or wider unsigned integer data type will do */
63 typedef unsigned int MD5_u32plus;
68 MD5_u32plus a, b, c, d;
69 unsigned char buffer[64];
70 MD5_u32plus block[16];
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);
78 // rg: Basic C++ helpers
79 class md5_hash : public utils::relative_ops<md5_hash>
85 inline md5_hash(uint32 a, uint32 b, uint32 c, uint32 d)
90 // pStr must be zero terminated, 32 hex chars, big endian order
91 inline md5_hash(const char *pStr)
93 bool success = init(pStr);
95 VOGL_NOTE_UNUSED(success);
98 // pStr must be zero terminated, 32 hex chars, big endian order
99 inline bool init(const char *pStr)
101 if (vogl_strlen(pStr) != 32)
104 for (uint i = 0; i < 16; ++i)
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))
111 uint v = v0 | (v1 << 4);
113 reinterpret_cast<uint8 *>(m_state)[i] = static_cast<uint8>(v);
119 inline dynamic_string &get_string(dynamic_string &str) const
121 const uint8 *pHash = reinterpret_cast<const uint8 *>(m_state);
123 for (uint i = 0; i < 16; i++)
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));
133 utils::zero_object(*this);
136 inline void init(uint32 a, uint32 b, uint32 c, uint32 d)
144 // size() is in uint32's, not bytes!
145 inline uint size() const
149 inline uint32 operator[](uint index) const
151 return m_state[vogl_assert_range<uint>(index, cStateSize)];
153 inline uint32 &operator[](uint index)
155 return m_state[vogl_assert_range<uint>(index, cStateSize)];
158 inline uint size_in_bytes() const
160 return cStateSize * sizeof(uint32);
162 inline const void *get_ptr() const
166 inline void set(const void *p)
168 memcpy(m_state, p, size_in_bytes());
171 inline bool operator==(const md5_hash &rhs) const
173 for (uint i = 0; i < cStateSize; i++)
174 if (m_state[i] != rhs.m_state[i])
179 inline bool operator<(const md5_hash &rhs) const
181 for (uint i = 0; i < cStateSize; i++)
182 if (m_state[i] < rhs.m_state[i])
184 else if (m_state[i] != rhs.m_state[i])
189 inline bool json_serialize(json_node &dst_node, const char *pKey) const
191 return json_serialize(dst_node.add(pKey));
194 inline bool json_serialize(json_value &dst_val) const
198 dst_val.set_value(str);
202 inline bool json_deserialize(const json_node &src_node, const char *pKey)
204 return json_deserialize(src_node.find_value(pKey));
207 inline bool json_deserialize(const json_value &src_val)
209 const char *pStr = src_val.as_string_ptr();
210 return pStr ? init(pStr) : false;
213 friend inline data_stream_serializer &operator<<(data_stream_serializer &serializer, const md5_hash &h)
215 serializer.write(&h.m_state, sizeof(h.m_state));
219 friend inline data_stream_serializer &operator>>(data_stream_serializer &serializer, md5_hash &h)
221 serializer.read(&h.m_state, sizeof(h.m_state));
225 inline operator size_t() const
227 return (size_t)fast_hash(this, sizeof(*this));
235 uint32 m_state[cStateSize];
241 inline md5_hash_gen()
246 inline md5_hash_gen(const void *p, uint n)
252 inline md5_hash_gen(const char *pStr)
258 inline md5_hash_gen(const dynamic_string &str)
264 inline md5_hash_gen(const md5_hash_gen &other)
269 inline md5_hash_gen &set(const md5_hash_gen &rhs)
271 memcpy(&m_ctx, &rhs.m_ctx, sizeof(m_ctx));
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
285 memcpy(&tmp_ctx, &m_ctx, sizeof(m_ctx));
287 return md5_hash(tmp_ctx.a, tmp_ctx.b, tmp_ctx.c, tmp_ctx.d);
290 inline md5_hash_gen &update(const char *pStr)
292 uint len = vogl_strlen(pStr);
298 inline md5_hash_gen &update(const dynamic_string &str)
301 update(str.get_ptr(), str.get_len());
305 // Hashes v as big endian
306 inline md5_hash_gen &update(uint64_t v)
309 for (uint i = 0; i < 8; i++)
311 octets[i] = static_cast<uint8>((v >> 56U) & 0xFF);
314 return update(octets, sizeof(octets));
317 // Hashes v as big endian
318 inline md5_hash_gen &update(uint32 v)
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));
328 // Hashes v as big endian
329 inline md5_hash_gen &update(uint16 v)
332 octets[0] = (v >> 16U) & 0xFF;
333 octets[1] = v & 0xFF;
334 return update(octets, sizeof(octets));
337 inline md5_hash_gen &update(const void *p, uint32 n)
339 MD5_Update(&m_ctx, p, n);
343 inline md5_hash_gen &update(const uint8_vec &buf)
345 return update(buf.get_ptr(), buf.size());
348 template <typename T>
349 inline md5_hash_gen &update_obj_bits(const T &obj)
351 return update(&obj, sizeof(obj));
354 inline md5_hash_gen &update_huge_buf(const void *p, uint64_t n)
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);
361 n -= bytes_to_process;
362 p = static_cast<const uint8 *>(p) + bytes_to_process;