rizin/librz/hash/algorithms/md4/md4.c
2021-11-25 15:44:28 +08:00

162 lines
5 KiB
C

// SPDX-FileCopyrightText: 2021 deroad <wargio@libero.it>
// SPDX-License-Identifier: LGPL-3.0-only
#include "md4.h"
#include <rz_types.h>
#include <rz_endian.h>
#include <rz_util.h>
#define XAX(x, y, z) (z ^ (x & (y ^ z)))
#define AAA(x, y, z) ((x & y) | (x & z) | (y & z))
#define XXX(x, y, z) (x ^ y ^ z)
#define md4_round(m, w, x, y, z, v, s) \
w += m(x, y, z) + v; \
w = rotate_left_32(w, s)
void rz_md4_init(RzMD4 *context) {
rz_return_if_fail(context);
context->digest[0] = 0x67452301;
context->digest[1] = 0xEFCDAB89;
context->digest[2] = 0x98BADCFE;
context->digest[3] = 0x10325476;
context->index = 0;
context->len_high = 0;
context->len_low = 0;
}
static inline ut32 rotate_left_32(ut32 value, ut32 rot) {
return ((((value) << (rot)) & 0xFFFFFFFF) | ((value) >> (32 - (rot))));
}
static void md4_digest_block(RzMD4 *context) {
// printb(context->block, 64);
ut32 W[16];
ut32 A = context->digest[0];
ut32 B = context->digest[1];
ut32 C = context->digest[2];
ut32 D = context->digest[3];
for (ut32 t = 0; t < 16; ++t) {
W[t] = rz_read_at_le32(context->block, t * 4);
}
md4_round(XAX, A, B, C, D, W[/* */ 0], 3);
md4_round(XAX, D, A, B, C, W[/* */ 1], 7);
md4_round(XAX, C, D, A, B, W[/* */ 2], 11);
md4_round(XAX, B, C, D, A, W[/* */ 3], 19);
md4_round(XAX, A, B, C, D, W[/* */ 4], 3);
md4_round(XAX, D, A, B, C, W[/* */ 5], 7);
md4_round(XAX, C, D, A, B, W[/* */ 6], 11);
md4_round(XAX, B, C, D, A, W[/* */ 7], 19);
md4_round(XAX, A, B, C, D, W[/* */ 8], 3);
md4_round(XAX, D, A, B, C, W[/* */ 9], 7);
md4_round(XAX, C, D, A, B, W[/**/ 10], 11);
md4_round(XAX, B, C, D, A, W[/**/ 11], 19);
md4_round(XAX, A, B, C, D, W[/**/ 12], 3);
md4_round(XAX, D, A, B, C, W[/**/ 13], 7);
md4_round(XAX, C, D, A, B, W[/**/ 14], 11);
md4_round(XAX, B, C, D, A, W[/**/ 15], 19);
md4_round(AAA, A, B, C, D, W[/* */ 0] + 0x5A827999, 3);
md4_round(AAA, D, A, B, C, W[/* */ 4] + 0x5A827999, 5);
md4_round(AAA, C, D, A, B, W[/* */ 8] + 0x5A827999, 9);
md4_round(AAA, B, C, D, A, W[/**/ 12] + 0x5A827999, 13);
md4_round(AAA, A, B, C, D, W[/* */ 1] + 0x5A827999, 3);
md4_round(AAA, D, A, B, C, W[/* */ 5] + 0x5A827999, 5);
md4_round(AAA, C, D, A, B, W[/* */ 9] + 0x5A827999, 9);
md4_round(AAA, B, C, D, A, W[/**/ 13] + 0x5A827999, 13);
md4_round(AAA, A, B, C, D, W[/* */ 2] + 0x5A827999, 3);
md4_round(AAA, D, A, B, C, W[/* */ 6] + 0x5A827999, 5);
md4_round(AAA, C, D, A, B, W[/**/ 10] + 0x5A827999, 9);
md4_round(AAA, B, C, D, A, W[/**/ 14] + 0x5A827999, 13);
md4_round(AAA, A, B, C, D, W[/* */ 3] + 0x5A827999, 3);
md4_round(AAA, D, A, B, C, W[/* */ 7] + 0x5A827999, 5);
md4_round(AAA, C, D, A, B, W[/**/ 11] + 0x5A827999, 9);
md4_round(AAA, B, C, D, A, W[/**/ 15] + 0x5A827999, 13);
md4_round(XXX, A, B, C, D, W[/* */ 0] + 0x6ED9EBA1, 3);
md4_round(XXX, D, A, B, C, W[/* */ 8] + 0x6ED9EBA1, 9);
md4_round(XXX, C, D, A, B, W[/* */ 4] + 0x6ED9EBA1, 11);
md4_round(XXX, B, C, D, A, W[/**/ 12] + 0x6ED9EBA1, 15);
md4_round(XXX, A, B, C, D, W[/* */ 2] + 0x6ED9EBA1, 3);
md4_round(XXX, D, A, B, C, W[/**/ 10] + 0x6ED9EBA1, 9);
md4_round(XXX, C, D, A, B, W[/* */ 6] + 0x6ED9EBA1, 11);
md4_round(XXX, B, C, D, A, W[/**/ 14] + 0x6ED9EBA1, 15);
md4_round(XXX, A, B, C, D, W[/* */ 1] + 0x6ED9EBA1, 3);
md4_round(XXX, D, A, B, C, W[/* */ 9] + 0x6ED9EBA1, 9);
md4_round(XXX, C, D, A, B, W[/* */ 5] + 0x6ED9EBA1, 11);
md4_round(XXX, B, C, D, A, W[/**/ 13] + 0x6ED9EBA1, 15);
md4_round(XXX, A, B, C, D, W[/* */ 3] + 0x6ED9EBA1, 3);
md4_round(XXX, D, A, B, C, W[/**/ 11] + 0x6ED9EBA1, 9);
md4_round(XXX, C, D, A, B, W[/* */ 7] + 0x6ED9EBA1, 11);
md4_round(XXX, B, C, D, A, W[/**/ 15] + 0x6ED9EBA1, 15);
context->digest[0] += A;
context->digest[1] += B;
context->digest[2] += C;
context->digest[3] += D;
context->index = 0;
}
bool rz_md4_update(RzMD4 *context, const ut8 *data, ut64 length) {
rz_return_val_if_fail(context && data, false);
for (ut64 i = 0; i < length; ++i) {
context->block[context->index++] = data[i];
context->len_low += 8;
if (context->len_low > 0xFFFFFFFFull) {
context->len_low &= 0xFFFFFFFFull;
context->len_high++;
// check if digested data overflows UT64
if (context->len_high > 0xFFFFFFFFull) {
return false;
}
}
// digest only 512 bit blocks
if (context->index == RZ_HASH_MD4_BLOCK_LENGTH) {
md4_digest_block(context);
}
}
return true;
}
void md4_padding(RzMD4 *context) {
if (context->index > 55) {
context->block[context->index++] = 0x80;
for (; context->index < RZ_HASH_MD4_BLOCK_LENGTH;) {
context->block[context->index++] = 0;
}
md4_digest_block(context);
for (; context->index < 56;) {
context->block[context->index++] = 0;
}
} else {
context->block[context->index++] = 0x80;
for (; context->index < 56;) {
context->block[context->index++] = 0;
}
}
rz_write_le32(&context->block[56], context->len_low);
rz_write_le32(&context->block[60], context->len_high);
md4_digest_block(context);
}
void rz_md4_fini(ut8 *hash, RzMD4 *context) {
rz_return_if_fail(context && hash);
md4_padding(context);
for (ut32 t = 0; t < 4; ++t) {
rz_write_at_le32(hash, context->digest[t], t * 4);
}
}