Use C++ constexpr implementation of MD5

Removes dependency on openssl and libcrypto.
Upstream: https://github.com/Wodann/constexpr-md5-cpp
Modified to accept std::vector<uint8_t> as input
This commit is contained in:
queueRAM
2022-11-01 00:25:03 +00:00
parent 59e17f2fe9
commit c188b7ab80
5 changed files with 224 additions and 24 deletions
+7 -8
View File
@@ -1,10 +1,9 @@
CC := gcc
CXX := g++
CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -O2 -s
CXXFLAGS := --std=c++17 -lstdc++fs -lcrypto -lssl -lpthread
CXXFLAGS := --std=c++17
LDFLAGS := -lm
PROGRAMS := n64crc
CXX_PROGRAMS := dkr_assets_tool
PROGRAMS := n64crc dkr_assets_tool
BUILD_DIR := dkr_assets_tool_classes/_build
@@ -17,10 +16,10 @@ default: all
n64crc_SOURCES := n64crc.c
all: $(PROGRAMS) $(CXX_PROGRAMS)
all: $(PROGRAMS)
clean:
rm -Rf $(PROGRAMS) $(CXX_PROGRAMS) $(BUILD_DIR)
rm -Rf $(PROGRAMS) $(BUILD_DIR)
distclean: clean
@@ -31,16 +30,16 @@ dkr_assets_tool_CPP_FILES := dkr_assets_tool.cpp \
$(call rwildcard,dkr_assets_tool_classes,*.cpp)
dkr_assets_tool_C_FILES := $(call rwildcard,dkr_assets_tool_classes,*.c)
dkr_assets_tool_OBJ_FILES := $(foreach file,$(dkr_assets_tool_C_FILES),$(BUILD_DIR)/$(file:.c=.o)) \
$(foreach file,$(dkr_assets_tool_CPP_FILES),$(BUILD_DIR)/$(file:.cpp=.o))
DUMMY != mkdir -p $(sort $(dir $(dkr_assets_tool_OBJ_FILES)))
$(BUILD_DIR)/%.o: %.c
$(CXX) -c $^ -o $@ $(CXXFLAGS) $(LDFLAGS)
$(CC) -c $^ -o $@ $(CFLAGS)
$(BUILD_DIR)/%.o: %.cpp
$(CXX) -c $< -o $@ $(CXXFLAGS) $(LDFLAGS)
$(CXX) -c $< -o $@ $(CXXFLAGS)
dkr_assets_tool: $(dkr_assets_tool_OBJ_FILES)
$(CXX) $^ -o $@ $(CXXFLAGS) $(LDFLAGS)
@@ -1,4 +1,5 @@
#include "fileHelper.h"
#include "md5.h"
std::string assetsFolderPath = "";
std::string version = "";
@@ -216,25 +217,12 @@ void make_uppercase(std::string& input) {
}
std::string calculate_md5(std::vector<uint8_t> &bytes) {
uint8_t buffer[0x4000];
uint8_t digest[MD5_DIGEST_LENGTH];
md5::Digest digest = md5::compute(bytes);
std::stringstream ss;
MD5_CTX md5Context;
MD5_Init(&md5Context);
MD5_Update(&md5Context, &bytes[0], bytes.size());
int res = MD5_Final(digest, &md5Context);
if(res == 0) {
return "";
}
// set up stringstream format
ss << std::hex << std::setfill('0');
for(uint8_t uc: digest) {
ss << std::setw(2) << (int)uc;
}
@@ -8,10 +8,9 @@
#include <iterator>
#include <iostream>
#include <iomanip>
#include <openssl/md5.h>
// C++17
#include <filesystem>
#include <filesystem>
namespace fs = std::filesystem;
#include "errorHelper.h"
@@ -0,0 +1,206 @@
/*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef CONSTEXPR_MD5_H_
#define CONSTEXPR_MD5_H_
#include <array>
#include <climits>
#include <cstdint>
namespace md5 {
using Digest = std::array<unsigned char, 16>;
namespace details {
constexpr uint32_t CBLOCK = 64;
constexpr uint32_t LBLOCK = CBLOCK / 4;
constexpr Digest make_digest(const std::array<uint32_t, 4>& input) noexcept {
Digest digest{};
for (size_t i = 0; i < input.size(); ++i) {
digest[i * 4] = static_cast<unsigned char>((input[i]) & 0xff);
digest[i * 4 + 1] = static_cast<unsigned char>((input[i] >> 8) & 0xff);
digest[i * 4 + 2] = static_cast<unsigned char>((input[i] >> 16) & 0xff);
digest[i * 4 + 3] = static_cast<unsigned char>((input[i] >> 24) & 0xff);
}
return digest;
}
using Fn = uint32_t(*)(uint32_t, uint32_t, uint32_t);
constexpr uint32_t f(uint32_t b, uint32_t c, uint32_t d) noexcept {
return (b & c) | (~b & d);
}
constexpr uint32_t g(uint32_t b, uint32_t c, uint32_t d) noexcept {
return (b & d) | (c & ~d);
}
constexpr uint32_t h(uint32_t b, uint32_t c, uint32_t d) noexcept {
return b ^ c ^ d;
}
constexpr uint32_t i(uint32_t b, uint32_t c, uint32_t d) noexcept {
return c ^ (b | ~d);
}
constexpr Fn F[4] = { f, g, h, i };
constexpr uint32_t G[CBLOCK] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9
};
constexpr uint32_t K[CBLOCK] = {
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
};
constexpr uint32_t S[LBLOCK] = {
7, 12, 17, 22,
5, 9, 14, 20,
4, 11, 16, 23,
6, 10, 15, 21
};
constexpr uint8_t PADDING[CBLOCK] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
constexpr uint32_t rotate(uint32_t x, uint32_t n) noexcept {
return (x << n) | (x >> (32 - n));
}
constexpr uint32_t t(Fn f, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) noexcept {
return b + rotate(a + f(b, c, d) + x + ac, s);
}
constexpr uint32_t to_uint32(const unsigned char* data) noexcept {
return
(static_cast<uint32_t>(data[3]) << 24) |
(static_cast<uint32_t>(data[2]) << 16) |
(static_cast<uint32_t>(data[1]) << 8) |
(static_cast<uint32_t>(data[0]));
}
struct Context {
std::array<unsigned char, CBLOCK> buffer;
std::array<uint32_t, 4> state;
uint32_t nl, nh;
constexpr Context() noexcept
: buffer()
, state{ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }
, nl(0)
, nh(0)
{}
constexpr void append(const uint8_t* data, size_t len) noexcept {
std::array<uint32_t, LBLOCK> input{};
auto k = (nl >> 3) & 0x3f;
auto length = static_cast<uint32_t>(len);
nl += length << 3;
if (nl < length << 3) {
nh += 1;
}
nh += length >> 29;
for (auto ptr = data; ptr != data + len; ++ptr) {
buffer[k++] = static_cast<unsigned char>(static_cast<int16_t>(*ptr) + UCHAR_MAX + 1);
if (k == 0x40) {
auto j = 0;
for (auto i = 0; i < LBLOCK; ++i) {
input[i] = to_uint32(&buffer[j]);
j += 4;
}
transform(input);
k = 0;
}
}
}
constexpr void transform(const std::array<uint32_t, LBLOCK>& input) noexcept {
auto a = state[0], b = state[1], c = state[2], d = state[3];
for (uint32_t r = 0; r < 4; ++r) {
const auto g = G + r * LBLOCK;
const auto s = S + r * 4;
const auto k = K + r * LBLOCK;
for (auto i = 0; i < input.size(); ++i) {
const auto new_b = t(F[r], a, b, c, d, input[g[i]], s[i % 4], k[i]);
a = d;
d = c;
c = b;
b = new_b;
}
}
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
constexpr Digest final() noexcept {
std::array<uint32_t, LBLOCK> input{};
const auto k = ((nl >> 3) & 0x3f);
input[14] = nl;
input[15] = nh;
append(PADDING, k < 56 ? 56 - k : 120 - k);
auto j = 0;
for (auto i = 0; i < 14; ++i) {
input[i] = to_uint32(&buffer[j]);
j += 4;
}
transform(input);
return make_digest(state);
}
};
}
static Digest compute(std::vector<uint8_t> &bytes) {
details::Context c;
c.append(&bytes[0], bytes.size());
return c.final();
}
}
#endif
@@ -1,6 +1,10 @@
#ifndef N64GRAPHICS_H_
#define N64GRAPHICS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
// intermediate formats
@@ -97,4 +101,8 @@ const char *n64graphics_get_read_version(void);
// get version of underlying graphics writing library
const char *n64graphics_get_write_version(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // N64GRAPHICS_H_