Last active
September 19, 2022 19:57
-
-
Save Loki-Astari/264f47bdc2685bf8e220a24607c5f0e8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "md5.h" | |
#include <iostream> | |
#include <cmath> | |
#include <bit> | |
const std::array<std::uint32_t, 64> pstl::cryptography::hashing::md5::s_array = { | |
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, | |
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, | |
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, | |
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 | |
}; | |
constexpr std::array<std::uint32_t, 64> pstl::cryptography::hashing::md5::make_k_array() | |
{ | |
std::array<std::uint32_t, 64> output; | |
for (int i = 0; i < output.max_size(); i++) | |
output[i] = std::floor(0x100000000 * std::abs(std::sin(i + 1))); | |
return output; | |
} | |
const std::array<std::uint32_t, 64> pstl::cryptography::hashing::md5::k_array = pstl::cryptography::hashing::md5::make_k_array(); | |
// Based on RFC 1321 | |
// https://www.ietf.org/rfc/rfc1321.txt | |
// 1992 | |
pstl::cryptography::hashing::Hash const& pstl::cryptography::hashing::md5::digest(std::string str) | |
{ | |
add(str); | |
return hash(); | |
} | |
pstl::cryptography::hashing::Hash const& pstl::cryptography::hashing::md5::hash() | |
{ | |
if (complete) { | |
return result; | |
} | |
complete = true; | |
buffer.emplace_back(0x80); | |
if (buffer.size() >= 56) { | |
buffer.resize(64, 0x0); | |
addBuffer(); | |
buffer.clear(); | |
} | |
buffer.resize(64, 0x0); | |
std::uint32_t* placeForMsgSize = reinterpret_cast<std::uint32_t*>(&buffer[56]); | |
(*placeForMsgSize) = msgSize; | |
addBuffer(); | |
for (auto& var : result) | |
{ | |
var = (((var) >> 24) | (((var) & 0x00FF0000) >> 8) | (((var) & 0x0000FF00) << 8) | ((var) << 24)); | |
} | |
return result; | |
} | |
void pstl::cryptography::hashing::md5::add(std::string const& str) | |
{ | |
std::uint8_t const* begin = reinterpret_cast<std::uint8_t const*>(str.data()); | |
std::uint8_t const* end = begin + str.size(); | |
add(begin, end); | |
} | |
void pstl::cryptography::hashing::md5::add(std::uint8_t const* begin, std::uint8_t const* end) | |
{ | |
if (complete) { | |
throw std::runtime_error("Can not add Data to a completed Hash"); | |
} | |
std::uint32_t size = std::distance(begin, end); | |
msgSize += (size * 8); | |
if (buffer.size() != 0) { | |
std::uint32_t needed = 64 - buffer.size(); | |
std::uint32_t add = std::min(needed, size); | |
buffer.insert(std::end(buffer), begin, begin + add); | |
if (buffer.size() != 64) { | |
return; | |
} | |
addBuffer(); | |
buffer.clear(); | |
begin += add; | |
} | |
for (std::uint8_t const* endChunk = begin + 64; endChunk < end; begin = endChunk, endChunk += 64) { | |
addChunk(reinterpret_cast<std::uint32_t const*>(&(*begin))); | |
} | |
buffer.insert(std::end(buffer), begin, end); | |
} | |
void pstl::cryptography::hashing::md5::addBuffer() | |
{ | |
addChunk(reinterpret_cast<std::uint32_t*>(buffer.data())); | |
} | |
void pstl::cryptography::hashing::md5::addChunk(std::uint32_t const* data) | |
{ | |
std::uint32_t A = result[0]; | |
std::uint32_t B = result[1]; | |
std::uint32_t C = result[2]; | |
std::uint32_t D = result[3]; | |
for (int j = 0; j < 64; j++) | |
{ | |
std::uint32_t F, g; | |
if (j < 16) | |
{ | |
F = (B & C) | ((~B) & D); | |
g = j; | |
} | |
else if (j < 32) | |
{ | |
F = (B & D) | (C & (~D)); | |
g = (5 * j + 1) % 16; | |
} | |
else if (j < 48) | |
{ | |
F = B ^ C ^ D; | |
g = (3 * j + 5) % 16; | |
} | |
else if (j < 64) | |
{ | |
F = C ^ (B | (~D)); | |
g = (7 * j) % 16; | |
} | |
std::uint32_t token = data[g]; | |
F = F + A + token + k_array[j]; | |
A = D; | |
D = C; | |
C = B; | |
B = B + std::rotl(F, s_array[j]); | |
} | |
result[0] += A; | |
result[1] += B; | |
result[2] += C; | |
result[3] += D; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#include <array> | |
#include <vector> | |
#include <ostream> | |
#include <cstdlib> | |
#include <iomanip> | |
namespace pstl::cryptography::hashing | |
{ | |
struct Hash: std::array<std::uint32_t,4> | |
{ | |
Hash(std::uint32_t a1, std::uint32_t a2, std::uint32_t a3, std::uint32_t a4) | |
: array{a1, a2, a3, a4} | |
{} | |
Hash(char const* str) | |
{ | |
std::string chunk; | |
for (int loop = 0; loop < 4; ++loop) { | |
chunk = std::string_view(str + loop * 8, 8); | |
(*this)[loop] = std::stoul(chunk.data(), nullptr, 16); | |
} | |
} | |
friend std::ostream& operator<<(std::ostream& str, Hash const& data) | |
{ | |
for (auto var : data) { | |
str << std::setw(8) << std::setfill('0') << std::hex << var; | |
} | |
return str; | |
} | |
}; | |
class md5 | |
{ | |
public: | |
md5() | |
: result{0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476} | |
, complete(false) | |
, msgSize(0) | |
{ | |
buffer.reserve(64); | |
} | |
md5(md5 const&) = delete; | |
md5& operator=(md5 const&) = delete; | |
void reset() | |
{ | |
result = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476}; | |
complete = false; | |
msgSize = 0; | |
buffer.clear(); | |
} | |
// Original Interface. | |
Hash const& digest(std::string str); | |
// New Interface | |
Hash const& hash(); | |
void add(std::string const& str); | |
void add(std::uint8_t const* begin, std::uint8_t const* end); | |
private: | |
constexpr static std::array<std::uint32_t, 64> make_k_array(); | |
static const std::array<std::uint32_t, 64> k_array; | |
static const std::array<std::uint32_t, 64> s_array; | |
void addChunk(std::uint32_t const* data); | |
void addBuffer(); | |
Hash result; | |
bool complete; | |
std::vector<uint8_t> buffer; | |
std::uint32_t msgSize = 0; | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "md5.h" | |
#include <iostream> | |
using pstl::cryptography::hashing::md5; | |
using pstl::cryptography::hashing::Hash; | |
void test2(std::string const& input1, std::string const& input2, Hash const& expected) | |
{ | |
md5 hash; | |
hash.add(input1); | |
hash.add(input2); | |
Hash actual = hash.hash(); | |
std::cout << actual; | |
if (actual != expected) { | |
std::cout << " FAIL: (" << expected << ")"; | |
} | |
std::cout << "\n"; | |
} | |
void test(std::string const& input1, Hash const& expected) | |
{ | |
md5 hash; | |
Hash actual = hash.digest(input1); | |
std::cout << actual; | |
if (actual != expected) { | |
std::cout << " FAIL: (" << expected << ")"; | |
} | |
std::cout << "\n"; | |
} | |
int main() | |
{ | |
test("", "d41d8cd98f00b204e9800998ecf8427e"); | |
test("a", "0cc175b9c0f1b6a831c399e269772661"); | |
test("abc", "900150983cd24fb0d6963f7d28e17f72"); | |
test("message digest", "f96b697d7cb7938d525a2f31aaf161d0"); | |
test("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"); | |
test("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f"); | |
test("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"); | |
test2("", "", "d41d8cd98f00b204e9800998ecf8427e"); | |
test2("a", "", "0cc175b9c0f1b6a831c399e269772661"); | |
test2("ab", "c", "900150983cd24fb0d6963f7d28e17f72"); | |
test2("message di", "gest", "f96b697d7cb7938d525a2f31aaf161d0"); | |
test2("abcdefghijklmnopqrstuvwx", "yz", "c3fcd3d76192e4007dfb496cca67e13b"); | |
test2("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "", "d174ab98d277d9f5a5611c2c9f419d9f"); | |
test2("12", "345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment