Skip to content

Commit

Permalink
Add MD4
Browse files Browse the repository at this point in the history
  • Loading branch information
matlo607 committed Nov 16, 2016
1 parent b43480a commit bc8c713
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 1 deletion.
51 changes: 51 additions & 0 deletions include/MD4.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef _MD4_HASHING_
#define _MD4_HASHING_

#include "HashingStrategy.hpp"

namespace crypto {

#define MD4_HASH_SIZE 16 // (in bytes)
#define MD4_MSGBLOCK_SIZE 64 // (in bytes)

using MD4hash = CryptoHash<MD4_HASH_SIZE>;

class MD4hashing : public HashingStrategy<MD4_HASH_SIZE, MD4_MSGBLOCK_SIZE>
{
public:

MD4hashing(void);
~MD4hashing() = default;

MD4hashing(const MD4hashing& other) = delete;
MD4hashing& operator=(const MD4hashing& other) = delete;

MD4hashing(MD4hashing&& other) = default;
MD4hashing& operator=(MD4hashing&& other) = default;

private:

class MD4BlockCipherLike final : public StrategyBlockCipherLike
{
private:
virtual void process(void) final override;
virtual MD4hash getDigest(void) final override;
virtual void setMsgSize(size_t size) final override;

public:
MD4BlockCipherLike(void);
~MD4BlockCipherLike() = default;

MD4BlockCipherLike(const MD4BlockCipherLike& other) = delete;
MD4BlockCipherLike& operator=(const MD4BlockCipherLike& other) = delete;

MD4BlockCipherLike(MD4BlockCipherLike&& other) = default;
MD4BlockCipherLike& operator=(MD4BlockCipherLike&& other) = default;

void reset(void) final override;
};
};

} /* namespace crypto */

#endif
142 changes: 142 additions & 0 deletions src/MD4.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include "MD4.hpp"
#include "HashingStrategy.hpp"
#include "utils.hpp"

#include <cstring>
#include <endian.h>

namespace crypto {

using namespace utils;

using MD4hash_uint32 = CryptoHash_uint32<MD4_HASH_SIZE>;
using MD4MsgBlock_uint32 = MsgBlock_uint32<MD4_MSGBLOCK_SIZE>;
using MD4MsgBlock_uint64 = MsgBlock_uint64<MD4_MSGBLOCK_SIZE>;

MD4hashing::MD4hashing(void) :
HashingStrategy<MD4_HASH_SIZE, MD4_MSGBLOCK_SIZE>(std::make_unique<MD4hashing::MD4BlockCipherLike>())
{
}

MD4hashing::MD4BlockCipherLike::MD4BlockCipherLike(void)
: HashingStrategy<MD4_HASH_SIZE, MD4_MSGBLOCK_SIZE>::StrategyBlockCipherLike()
{
reset();
}

void MD4hashing::MD4BlockCipherLike::reset(void)
{
memset(m_msgBlock.data(), 0, sizeof(m_msgBlock));
m_msgBlockIndex = 0;
m_intermediateHash = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476
};
}

MD4hash MD4hashing::MD4BlockCipherLike::getDigest(void)
{
MD4hash digest;

#if __BYTE_ORDER == __BIG_ENDIAN
// write the hash in little endian
for (uint8_t i = 0; i < m_intermediateHash.size(); ++i) {
(*reinterpret_cast<MD4hash_uint32*>(digest.data()))[i] = htole32(m_intermediateHash[i]);
}
#else
memcpy(digest.data(), m_intermediateHash.data(), digest.size());
#endif

return std::move(digest);
}

void MD4hashing::MD4BlockCipherLike::setMsgSize(size_t size)
{
(*reinterpret_cast<MD4MsgBlock_uint64*>(m_msgBlock.data())).back() = htole64(size);
}

void MD4hashing::MD4BlockCipherLike::process(void)
{
auto F = [](auto x, auto y, auto z) { return (x & y) | ((~x) & z); };
auto G = [](auto x, auto y, auto z) { return (x & (y | z)) | (y & z); };
auto H = [](auto x, auto y, auto z) { return x ^ y ^ z; };

#define mod16(x) ((x) % 16)
#define div4(x) (mod16(x) / 4)

auto f = [](auto x) { return mod16(x); };
auto g = [](auto x) { return div4(x) + (x % 4) * 4; };
auto h = [](auto x) {
auto h1 = [] (auto x) { return (x % 2) * 2 + (x % 4) / 2; };
return h1(x) * 4 + h1( div4(x) );
};

auto XX = [](auto X, auto &a, auto b, auto c, auto d, auto k, auto w, auto s)
{
a += X(b,c,d) + w + k;
a = rotate_left(a,s);
};

static std::array<const uint32_t, 3> K = { 0, 0x5a827999, 0x6ed9eba1 };

static std::array<const uint8_t, 12> ref_leftshift =
{
3, 7, 11, 19,
3, 5, 9, 13,
3, 9, 11, 15
};

auto shift = [](auto x) { return (x / 16) * 4 + (x % 4); };

std::array<uint32_t,16> W;
uint32_t A, B, C, D;

// initialize the first 16 words in the array W
for (uint8_t t = 0; t < 16; ++t) {
W[t] = htole32((*reinterpret_cast<MD4MsgBlock_uint32*>(m_msgBlock.data()))[t]);
}

A = m_intermediateHash[0];
B = m_intermediateHash[1];
C = m_intermediateHash[2];
D = m_intermediateHash[3];

for (uint8_t t = 0; t < 16; ++t) {
XX( F, A, B, C, D, K[t/16], W[ f(t) ], ref_leftshift[ shift(t) ] );
auto temp = D;
D = C;
C = B;
B = A;
A = temp;
}

for (uint8_t t = 16; t < 32; ++t) {
XX( G, A, B, C, D, K[t/16], W[ g(t) ], ref_leftshift[ shift(t) ] );
auto temp = D;
D = C;
C = B;
B = A;
A = temp;
}

for (uint8_t t = 32; t < 48; ++t) {
XX( H, A, B, C, D, K[t/16], W[ h(t) ], ref_leftshift[ shift(t) ] );
auto temp = D;
D = C;
C = B;
B = A;
A = temp;
}

m_intermediateHash[0] += A;
m_intermediateHash[1] += B;
m_intermediateHash[2] += C;
m_intermediateHash[3] += D;

m_msgBlockIndex = 0;
}

} /* namespace crypto */

3 changes: 2 additions & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ all: test_libcrypto

INCLUDE_FILES=../include/*.hpp ../include/*.ipp

MD4.o: ../src/MD4.cpp $(INCLUDE_FILES)
MD5.o: ../src/MD5.cpp $(INCLUDE_FILES)
SHA1.o: ../src/SHA1.cpp $(INCLUDE_FILES)
SHA256.o: ../src/SHA256.cpp $(INCLUDE_FILES)
Expand All @@ -19,7 +20,7 @@ test_libcrypto.o: test_libcrypto.cpp $(INCLUDE_FILES)
%.o: %.cpp
$(CC) $(CXXFLAGS) $(INCFLAGS) -c $< -o $@

test_libcrypto: test_libcrypto.o ../src/SHA256.o ../src/SHA1.o ../src/MD5.o
test_libcrypto: test_libcrypto.o ../src/SHA256.o ../src/SHA1.o ../src/MD5.o ../src/MD4.o
$(CC) -o $@ $^ $(LDFLAGS)

clean:
Expand Down
13 changes: 13 additions & 0 deletions test/test_libcrypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "HashingStrategy.hpp"
#include "SHA1.hpp"
#include "SHA256.hpp"
#include "MD4.hpp"
#include "MD5.hpp"

#include <string>
Expand Down Expand Up @@ -176,6 +177,18 @@ TEST(Hashing, SHA256_Test)
hashProve(challenges, crypto::SHA256hashing());
}

TEST(Hashing, MD4_Test)
{
HashChallenges<3> challenges =
{
std::make_pair(TestEnvironment::getTxt1(), "a448017aaf21d8525fc10ae87aa6729d"),
std::make_pair(TestEnvironment::getTxt2(), "2d85cb0dfc938572c5b3e8d41b724c55"),
std::make_pair(TestEnvironment::getTxt3(), "bdbba5cc002c432ac14368c4ac6a03eb")
};

hashProve(challenges, crypto::MD4hashing());
}

TEST(Hashing, MD5_Test)
{
HashChallenges<3> challenges =
Expand Down

0 comments on commit bc8c713

Please sign in to comment.