2024-05-08 17:19:04 +00:00
|
|
|
/* Descent 3
|
|
|
|
* Copyright (C) 2024 Descent Developers
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2024-04-16 20:21:35 +00:00
|
|
|
|
|
|
|
#include "md5.h"
|
2024-04-18 00:18:11 +00:00
|
|
|
#include <byteswap.h>
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
#include <algorithm>
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
namespace {
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-24 02:51:16 +00:00
|
|
|
const uint32_t md5_round_shifts[] = {7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21};
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
const std::uint32_t md5_round_constants[] = {
|
|
|
|
0xD76AA478UL, 0xE8C7B756UL, 0x242070DBUL, 0xC1BDCEEEUL, 0xF57C0FAFUL, 0x4787C62AUL, 0xA8304613UL, 0xFD469501UL,
|
|
|
|
0x698098D8UL, 0x8B44F7AFUL, 0xFFFF5BB1UL, 0x895CD7BEUL, 0x6B901122UL, 0xFD987193UL, 0xA679438EUL, 0x49B40821UL,
|
|
|
|
0xF61E2562UL, 0xC040B340UL, 0x265E5A51UL, 0xE9B6C7AAUL, 0xD62F105DUL, 0x02441453UL, 0xD8A1E681UL, 0xE7D3FBC8UL,
|
|
|
|
0x21E1CDE6UL, 0xC33707D6UL, 0xF4D50D87UL, 0x455A14EDUL, 0xA9E3E905UL, 0xFCEFA3F8UL, 0x676F02D9UL, 0x8D2A4C8AUL,
|
|
|
|
0xFFFA3942UL, 0x8771F681UL, 0x6D9D6122UL, 0xFDE5380CUL, 0xA4BEEA44UL, 0x4BDECFA9UL, 0xF6BB4B60UL, 0xBEBFBC70UL,
|
|
|
|
0x289B7EC6UL, 0xEAA127FAUL, 0xD4EF3085UL, 0x04881D05UL, 0xD9D4D039UL, 0xE6DB99E5UL, 0x1FA27CF8UL, 0xC4AC5665UL,
|
|
|
|
0xF4292244UL, 0x432AFF97UL, 0xAB9423A7UL, 0xFC93A039UL, 0x655B59C3UL, 0x8F0CCC92UL, 0xFFEFF47DUL, 0x85845DD1UL,
|
|
|
|
0x6FA87E4FUL, 0xFE2CE6E0UL, 0xA3014314UL, 0x4E0811A1UL, 0xF7537E82UL, 0xBD3AF235UL, 0x2AD7D2BBUL, 0xEB86D391UL};
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
std::uint32_t rotl_uint32(std::uint32_t a, std::uint32_t b) noexcept { return b ? (a << b) | (a >> (32 - b)) : a; };
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
}; // namespace
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-24 02:58:46 +00:00
|
|
|
void MD5::round(std::array<std::uint32_t, 4> &sums, const uint8_t *block) const noexcept {
|
2024-05-08 17:19:04 +00:00
|
|
|
// break 64 bytes into 16 dwords
|
|
|
|
std::uint32_t m[16];
|
|
|
|
for (std::size_t i = 0; i < 16; ++i) {
|
|
|
|
m[i] = (static_cast<std::uint32_t>(block[(4 * i)])) | (static_cast<std::uint32_t>(block[(4 * i) + 1]) << 8) |
|
|
|
|
(static_cast<std::uint32_t>(block[(4 * i) + 2]) << 16) |
|
|
|
|
(static_cast<std::uint32_t>(block[(4 * i) + 3]) << 24);
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
std::uint32_t a = sums[0], b = sums[1], c = sums[2], d = sums[3];
|
|
|
|
|
|
|
|
// 64 rounds...
|
2024-05-24 02:51:16 +00:00
|
|
|
for (uint32_t r = 0; r < 64; ++r) {
|
2024-05-08 17:19:04 +00:00
|
|
|
std::uint32_t f, g;
|
2024-05-24 02:51:16 +00:00
|
|
|
uint32_t s = md5_round_shifts[((r >> 2) & ~3) | (r & 3)];
|
2024-05-08 17:19:04 +00:00
|
|
|
switch (r >> 4) {
|
|
|
|
case 0:
|
|
|
|
f = (b & c) | (~b & d), g = r;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
f = (b & d) | (c & ~d), g = (5 * r + 1) & 15;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
f = b ^ c ^ d, g = (3 * r + 5) & 15;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
f = c ^ (b | ~d), g = (7 * r) & 15;
|
|
|
|
break;
|
|
|
|
default:; // unreachable
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
2024-05-08 17:19:04 +00:00
|
|
|
f = rotl_uint32(f + a + m[g] + md5_round_constants[r], s) + b;
|
|
|
|
a = d;
|
|
|
|
d = c;
|
|
|
|
c = b;
|
|
|
|
b = f;
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
sums[0] += a, sums[1] += b, sums[2] += c, sums[3] += d;
|
|
|
|
}
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-24 02:58:46 +00:00
|
|
|
void MD5::round(const uint8_t *block) noexcept { round(sums_, block); }
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-24 02:58:46 +00:00
|
|
|
void MD5::update(const uint8_t *data, std::size_t n) noexcept {
|
2024-05-08 17:19:04 +00:00
|
|
|
message_len_ += n * 8;
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
// if there is already some data in tmpbuf, check if we would fill it
|
|
|
|
if (tmpbuf_n_) {
|
|
|
|
if ((n >= tmpbuf_.size() || tmpbuf_n_ + n >= tmpbuf_.size())) {
|
|
|
|
// we would fill tmpbuf at least once; handle partial block first.
|
|
|
|
std::size_t remaining = tmpbuf_.size() - tmpbuf_n_;
|
|
|
|
std::copy(data, data + remaining, tmpbuf_.begin() + tmpbuf_n_);
|
|
|
|
data += remaining;
|
|
|
|
n -= remaining;
|
|
|
|
round(tmpbuf_.data());
|
|
|
|
tmpbuf_n_ = 0;
|
|
|
|
} else {
|
|
|
|
// we will not fill the buffer - just copy and return
|
|
|
|
std::copy(data, data + n, tmpbuf_.begin() + tmpbuf_n_);
|
|
|
|
tmpbuf_n_ += n;
|
2024-04-16 20:21:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
// do rounds on full blocks for as long as we can
|
|
|
|
while (n >= tmpbuf_.size()) {
|
|
|
|
round(data);
|
|
|
|
data += tmpbuf_.size();
|
|
|
|
n -= tmpbuf_.size();
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
if (n) {
|
|
|
|
// copy partial block
|
|
|
|
std::copy(data, data + n, tmpbuf_.begin());
|
|
|
|
tmpbuf_n_ = n;
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-24 02:58:46 +00:00
|
|
|
void MD5::place_length(uint8_t *destination) const noexcept {
|
2024-05-08 17:19:04 +00:00
|
|
|
for (std::size_t i = 0; i < 8; ++i)
|
2024-05-24 02:58:46 +00:00
|
|
|
destination[i] = static_cast<uint8_t>(message_len_ >> (8 * i));
|
2024-05-08 17:19:04 +00:00
|
|
|
}
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-24 02:58:46 +00:00
|
|
|
std::array<uint8_t, 16> MD5::digest() const noexcept {
|
2024-05-08 17:19:04 +00:00
|
|
|
// copies of sums and buffers
|
|
|
|
auto sums = sums_;
|
|
|
|
auto buf = tmpbuf_;
|
|
|
|
std::size_t n = tmpbuf_n_;
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:58:59 +00:00
|
|
|
if (n >= 56) {
|
|
|
|
// must append current block, required padding bit and length won't fit.
|
|
|
|
// n is never buf.size() (= 64) yet
|
2024-05-08 17:19:04 +00:00
|
|
|
buf[n++] = 0x80U;
|
|
|
|
while (n < buf.size())
|
|
|
|
buf[n++] = 0;
|
|
|
|
round(sums, buf.data());
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
// all zeroes, except for length
|
|
|
|
std::fill(buf.begin(), buf.begin() + 56, 0);
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:58:59 +00:00
|
|
|
} else { // n < 56
|
2024-05-08 17:19:04 +00:00
|
|
|
// append padding to tmpbuf and then the length
|
|
|
|
buf[n++] = 0x80U;
|
|
|
|
while (n < 56)
|
|
|
|
buf[n++] = 0;
|
|
|
|
}
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
place_length(&buf[56]);
|
|
|
|
round(sums, buf.data());
|
2024-04-16 20:21:35 +00:00
|
|
|
|
2024-05-24 02:58:46 +00:00
|
|
|
return {static_cast<uint8_t>(sums[0]), static_cast<uint8_t>(sums[0] >> 8),
|
|
|
|
static_cast<uint8_t>(sums[0] >> 16), static_cast<uint8_t>(sums[0] >> 24),
|
|
|
|
static_cast<uint8_t>(sums[1]), static_cast<uint8_t>(sums[1] >> 8),
|
|
|
|
static_cast<uint8_t>(sums[1] >> 16), static_cast<uint8_t>(sums[1] >> 24),
|
|
|
|
static_cast<uint8_t>(sums[2]), static_cast<uint8_t>(sums[2] >> 8),
|
|
|
|
static_cast<uint8_t>(sums[2] >> 16), static_cast<uint8_t>(sums[2] >> 24),
|
|
|
|
static_cast<uint8_t>(sums[3]), static_cast<uint8_t>(sums[3] >> 8),
|
|
|
|
static_cast<uint8_t>(sums[3] >> 16), static_cast<uint8_t>(sums[3] >> 24)};
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
void MD5::update(float valin) noexcept {
|
|
|
|
float val = INTEL_FLOAT(valin);
|
2024-05-24 02:58:46 +00:00
|
|
|
uint8_t *p = (uint8_t *)&val;
|
2024-05-08 17:19:04 +00:00
|
|
|
update(p, sizeof(float));
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-08 17:19:04 +00:00
|
|
|
void MD5::update(int valin) noexcept {
|
|
|
|
int val = INTEL_INT(valin);
|
2024-05-24 02:58:46 +00:00
|
|
|
uint8_t *p = (uint8_t *)&val;
|
2024-05-08 17:19:04 +00:00
|
|
|
update(p, sizeof(int));
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-24 03:27:12 +00:00
|
|
|
void MD5::update(int16_t valin) noexcept {
|
|
|
|
int16_t val = INTEL_SHORT(valin);
|
2024-05-24 02:58:46 +00:00
|
|
|
uint8_t *p = (uint8_t *)&val;
|
2024-05-24 03:27:12 +00:00
|
|
|
update(p, sizeof(int16_t));
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-24 02:51:16 +00:00
|
|
|
void MD5::update(uint32_t valin) noexcept {
|
|
|
|
uint32_t val = INTEL_INT(valin);
|
2024-05-24 02:58:46 +00:00
|
|
|
uint8_t *p = (uint8_t *)&val;
|
2024-05-24 02:51:16 +00:00
|
|
|
update(p, sizeof(uint32_t));
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-24 02:58:46 +00:00
|
|
|
void MD5::update(uint8_t val) noexcept {
|
|
|
|
uint8_t *p = (uint8_t *)&val;
|
|
|
|
update(p, sizeof(uint8_t));
|
2024-04-16 20:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-05-24 02:58:46 +00:00
|
|
|
void MD5::digest(uint8_t *destination) const noexcept {
|
2024-05-08 17:19:04 +00:00
|
|
|
auto digest_data = digest();
|
|
|
|
std::copy(digest_data.begin(), digest_data.end(), destination);
|
2024-05-06 15:12:44 +00:00
|
|
|
}
|