001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:
033:
034:
035:
036:
037:
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
066:
067:
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
083:
084:
085:
086:
087:
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:

/*
* Copyright (c), Zeriph Enterprises
* All rights reserved.
*
* Contributor(s):
* Zechariah Perez, omni (at) zeriph (dot) com
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <omni/crypto/md5.hpp>
#include <omni/crypto/util.hpp>
#include <omni/defs/file_def.hpp>
#include <fstream>
#include <sstream>
#include <cstring>
#define OMNI_IO_FILE_EX_FW 1
#include <omni/xx/io/file_ex.hxx>
#if defined(OMNI_SAFE_MD5)
#define OMNI_SAFE_MD5DMTX_FW ,m_mtx()
#define OMNI_SAFE_MD5LOCK_FW this->m_mtx.lock();
#define OMNI_SAFE_MD5UNLOCK_FW this->m_mtx.unlock();
#define OMNI_SAFE_MD5ALOCK_FW omni::sync::scoped_basic_lock uuid12345(&this->m_mtx);
#define OMNI_SAFE_MD5OALOCK_FW(o) omni::sync::scoped_basic_lock uuid54321(&o.m_mtx);
#else
#define OMNI_SAFE_MD5DMTX_FW
#define OMNI_SAFE_MD5LOCK_FW
#define OMNI_SAFE_MD5UNLOCK_FW
#define OMNI_SAFE_MD5ALOCK_FW
#define OMNI_SAFE_MD5OALOCK_FW(o)
#endif
// standard MD5 bit-twiddling functions
#define OMNI_MD5_F_FW(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define OMNI_MD5_G_FW(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define OMNI_MD5_H_FW(x, y, z) ((x) ^ (y) ^ (z))
#define OMNI_MD5_I_FW(x, y, z) ((y) ^ ((x) | (~z)))
namespace omni { namespace crypto { namespace md5_internal {
void transform (const unsigned char* block, uint32_t* state)
{
const uint32_t transform_magic[64] = {
0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391
};
const int8_t s1[4] = { 7, 12, 17, 22 };
const int8_t s2[4] = { 5, 9, 14, 20 };
const int8_t s3[4] = { 4, 11, 16, 23 };
const int8_t s4[4] = { 6, 10, 15, 21 };
const uint32_t* x = reinterpret_cast<const uint32_t*>(block);
std::size_t i, j;
uint32_t a, b, c, d, tmp;
a = state[0];
b = state[1];
c = state[2];
d = state[3];
// Round 1
for (i = 0; i < 16; ++i) {
tmp = a + OMNI_MD5_F_FW(b, c, d) + (x[i]) + transform_magic[i];
tmp = omni::crypto::util::rotate_left(tmp, static_cast<uint8_t>(s1[i & 3]));
tmp += b;
a = d; d = c; c = b; b = tmp;
}
// Round 2
for (i = 0, j = 1; i < 16; ++i, j += 5) {
tmp = a + OMNI_MD5_G_FW(b, c, d) + (x[j & 15]) + transform_magic[i+16];
tmp = omni::crypto::util::rotate_left(tmp, static_cast<uint8_t>(s2[i & 3]));
tmp += b;
a = d; d = c; c = b; b = tmp;
}
// Round 3
for (i = 0, j = 5; i < 16; ++i, j += 3) {
tmp = a + OMNI_MD5_H_FW(b, c, d) + (x[j & 15]) + transform_magic[i+32];
tmp = omni::crypto::util::rotate_left(tmp, static_cast<uint8_t>(s3[i & 3]));
tmp += b;
a = d; d = c; c = b; b = tmp;
}
// Round 4
for (i = 0, j = 0; i < 16; ++i, j += 7) {
tmp = a + OMNI_MD5_I_FW(b, c, d) + (x[j & 15]) + transform_magic[i+48];
tmp = omni::crypto::util::rotate_left(tmp, static_cast<uint8_t>(s4[i & 3]));
tmp += b;
a = d; d = c; c = b; b = tmp;
}
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
std::string compute(const unsigned char* data, uint32_t data_len)
{
uint32_t state[4] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 };
unsigned char buffer[64] = {0};
uint32_t length = 0;
uint32_t buflen = length & 63;
length += data_len;
if (buflen + data_len < 64) {
std::memcpy(buffer + buflen, data, data_len);
buflen += data_len;
} else {
std::memcpy(buffer + buflen, data, 64 - buflen);
omni::crypto::md5_internal::transform(buffer, state);
data += 64 - buflen;
data_len -= 64 - buflen;
while (data_len >= 64) {
omni::crypto::md5_internal::transform(data, state);
data += 64;
data_len -= 64;
}
std::memcpy(buffer, data, data_len);
buflen = data_len;
}
buflen = length & 63;
buffer[buflen++] = 0x80;
std::memset(buffer+buflen, 0, 64 - buflen);
if (buflen > 56) {
omni::crypto::md5_internal::transform(buffer, state);
std::memset(buffer, 0, 64);
buflen = 0;
}
*(reinterpret_cast<uint32_t *>(buffer + 56)) = (8 * length);
*(reinterpret_cast<uint32_t *>(buffer + 60)) = 0;
omni::crypto::md5_internal::transform(buffer, state);
unsigned char* digest = reinterpret_cast<unsigned char *>(state);
return omni::crypto::util::buffer_to_hex_string(digest, 16);
}
inline std::string compute(const std::string& text)
{
return omni::crypto::md5_internal::compute(reinterpret_cast<const unsigned char*>(text.c_str()), static_cast<uint32_t>(text.length()));
}
} } }
omni::crypto::md5::md5() :
OMNI_CTOR_FW(omni::crypto::md5)
m_hash()
OMNI_SAFE_MD5DMTX_FW
{}
omni::crypto::md5::md5(const omni::crypto::md5& cp) :
OMNI_CPCTOR_FW(cp)
m_hash(cp.m_hash)
OMNI_SAFE_MD5DMTX_FW
{}
OMNI_EXPLICIT omni::crypto::md5::md5(const std::string& hash) :
OMNI_CTOR_FW(omni::crypto::md5)
m_hash(hash)
OMNI_SAFE_MD5DMTX_FW
{
}
omni::crypto::md5::md5(const std::string& text, const omni::crypto::hash_type& type) :
OMNI_CTOR_FW(omni::crypto::md5)
m_hash()
OMNI_SAFE_MD5DMTX_FW
{
if (type == omni::crypto::hash_type::STRING) {
this->m_hash = omni::crypto::md5_internal::compute(text);
} else {
if (!omni::io::file_internal::exists(text)) {
OMNI_ERRV_FW("File not found: ", text, omni::exceptions::file_not_found(text))
}
std::ifstream ifile;
if (type == omni::crypto::hash_type::BINARY_FILE) {
ifile.open(text.c_str(), std::ios::binary);
} else {
ifile.open(text.c_str());
}
ifile.seekg(0, ifile.end);
uint32_t length = static_cast<uint32_t>(ifile.tellg());
ifile.seekg(0, ifile.beg);
if (length > 0) {
char* data = new char[length];
ifile.read(data, length);
ifile.close();
this->m_hash = omni::crypto::md5_internal::compute(reinterpret_cast<const unsigned char*>(data), length);
delete[] data;
}
}
}
omni::crypto::md5::~md5()
{
OMNI_TRY_FW
OMNI_DTOR_FW
OMNI_CATCH_FW
}
std::string omni::crypto::md5::hash_code() const
{
return this->to_string();
}
void omni::crypto::md5::swap(omni::crypto::md5& o)
{
if (this != &o) {
OMNI_SAFE_MD5ALOCK_FW
OMNI_SAFE_MD5OALOCK_FW(o)
std::swap(this->m_hash, o.m_hash);
}
}
omni::string_t omni::crypto::md5::to_string_t() const
{
OMNI_SAFE_MD5ALOCK_FW
return omni::string::util::to_string_t(this->m_hash);
}
std::string omni::crypto::md5::to_string() const
{
OMNI_SAFE_MD5ALOCK_FW
return this->m_hash;
}
std::wstring omni::crypto::md5::to_wstring() const
{
OMNI_SAFE_MD5ALOCK_FW
return omni::string::util::to_wstring(this->m_hash);
}
omni::crypto::md5& omni::crypto::md5::operator=(const omni::crypto::md5& other)
{
if (this != &other) {
OMNI_SAFE_MD5ALOCK_FW
OMNI_SAFE_MD5OALOCK_FW(other)
this->m_hash = other.m_hash;
}
return *this;
}
bool omni::crypto::md5::operator==(const omni::crypto::md5& o) const
{
if (this != &o) {
OMNI_SAFE_MD5ALOCK_FW
OMNI_SAFE_MD5OALOCK_FW(o)
return this->m_hash == o.m_hash;
}
return true;
}
bool omni::crypto::md5::operator!=(const omni::crypto::md5& o) const
{
return !(*this == o);
}
std::string omni::crypto::md5::compute_hash(const std::string& text)
{
omni::crypto::md5 md5(text, omni::crypto::hash_type::STRING);
return md5.m_hash;
}
std::string omni::crypto::md5::compute_file_hash(const std::string& file)
{
omni::crypto::md5 md5(file, omni::crypto::hash_type::TEXT_FILE);
return md5.m_hash;
}
std::string omni::crypto::md5::compute_binary_file_hash(const std::string& file)
{
omni::crypto::md5 md5(file, omni::crypto::hash_type::BINARY_FILE);
return md5.m_hash;
}