|
/*
|
|
Copyright (c) 2003, Dominik Reichl <dominik.reichl@t-online.de>
|
|
All rights reserved.
|
|
|
|
LICENSE TERMS
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
* Neither the name of ReichlSoft nor the names of its contributors may be used
|
|
to endorse or promote products derived from this software without specific
|
|
prior written permission.
|
|
|
|
DISCLAIMER
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
// This free implementation is based on the free original implementation of
|
|
// RSA Data Security. The source has been heavily modified to integrate
|
|
// to ReHash.
|
|
|
|
// Here's the original header:
|
|
|
|
/*
|
|
Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
|
|
|
|
License to copy and use this software is granted provided that it
|
|
is identified as the "RSA Data Security, Inc. MD4 Message-Digest
|
|
Algorithm" in all material mentioning or referencing this software
|
|
or this function.
|
|
|
|
License is also granted to make and use derivative works provided
|
|
that such works are identified as "derived from the RSA Data
|
|
Security, Inc. MD4 Message-Digest Algorithm" in all material
|
|
mentioning or referencing the derived work.
|
|
|
|
RSA Data Security, Inc. makes no representations concerning either
|
|
the merchantability of this software or the suitability of this
|
|
software for any particular purpose. It is provided "as is"
|
|
without express or implied warranty of any kind.
|
|
|
|
These notices must be retained in any copies of any part of this
|
|
documentation and/or software.
|
|
*/
|
|
|
|
#include "md4.h"
|
|
|
|
// Constants for MD4_Transform routine
|
|
#define MD4_S11 3
|
|
#define MD4_S12 7
|
|
#define MD4_S13 11
|
|
#define MD4_S14 19
|
|
#define MD4_S21 3
|
|
#define MD4_S22 5
|
|
#define MD4_S23 9
|
|
#define MD4_S24 13
|
|
#define MD4_S31 3
|
|
#define MD4_S32 9
|
|
#define MD4_S33 11
|
|
#define MD4_S34 15
|
|
|
|
static const UWORD8 MD4_PADDING[64] = {
|
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
|
|
// MD4F, MD4G and MD4H are basic MD4 functions
|
|
#define MD4F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
|
#define MD4G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
|
|
#define MD4H(x, y, z) ((x) ^ (y) ^ (z))
|
|
|
|
// MD4FF, MD4GG and MD4HH are transformations for rounds 1, 2 and 3
|
|
// Rotation is separate from addition to prevent recomputation
|
|
#define MD4FF(a, b, c, d, x, s) { \
|
|
(a) += MD4F((b), (c), (d)) + (x); \
|
|
(a) = ROL32((a), (s)); }
|
|
#define MD4GG(a, b, c, d, x, s) { \
|
|
(a) += MD4G((b), (c), (d)) + (x) + 0x5a827999; \
|
|
(a) = ROL32((a), (s)); }
|
|
#define MD4HH(a, b, c, d, x, s) { \
|
|
(a) += MD4H((b), (c), (d)) + (x) + 0x6ed9eba1; \
|
|
(a) = ROL32((a), (s)); }
|
|
|
|
CMD4Hash::CMD4Hash()
|
|
{
|
|
}
|
|
|
|
CMD4Hash::~CMD4Hash()
|
|
{
|
|
}
|
|
|
|
// MD4 initialization. Begins an MD4 operation, writing a new context
|
|
void CMD4Hash::Init(RH_DATA_INFO *pInfo)
|
|
{
|
|
m_count[0] = m_count[1] = 0;
|
|
|
|
// Load magic initialization constants
|
|
m_state[0] = 0x67452301;
|
|
m_state[1] = 0xefcdab89;
|
|
m_state[2] = 0x98badcfe;
|
|
m_state[3] = 0x10325476;
|
|
}
|
|
|
|
// MD4 block update operation. Continues an MD4 message-digest
|
|
// operation, processing another message block, and updating the
|
|
// context
|
|
void CMD4Hash::Update(const UWORD8 *pBuf, UINTPREF uLen)
|
|
{
|
|
UINTPREF i = 0, ix, partLen;
|
|
|
|
// Compute number of bytes mod 64
|
|
ix = (UINTPREF)((m_count[0] >> 3) & 0x3F);
|
|
|
|
// Update number of bits
|
|
if((m_count[0] += ((UWORD32)uLen << 3)) < ((UWORD32)uLen << 3))
|
|
m_count[1]++;
|
|
m_count[1] += ((UWORD32)uLen >> 29);
|
|
|
|
partLen = 64 - ix;
|
|
|
|
// Transform as many times as possible
|
|
if(uLen >= partLen)
|
|
{
|
|
memcpy(&m_buffer[ix], pBuf, partLen);
|
|
_Transform(m_state, m_buffer);
|
|
|
|
for(i = partLen; i + 63 < uLen; i += 64)
|
|
_Transform(m_state, &pBuf[i]);
|
|
|
|
ix = 0;
|
|
}
|
|
else i = 0;
|
|
|
|
// Buffer remaining input
|
|
memcpy(&m_buffer[ix], &pBuf[i], uLen - i);
|
|
}
|
|
|
|
// MD4 finalization. Ends an MD4 message-digest operation, writing the
|
|
// the message digest and zeroizing the context
|
|
void CMD4Hash::Final()
|
|
{
|
|
UWORD8 pBits[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
UINTPREF ix, padLen;
|
|
|
|
// Save number of bits
|
|
_Encode(pBits, m_count, 8);
|
|
|
|
// Pad out to 56 mod 64.
|
|
ix = (UINTPREF)((m_count[0] >> 3) & 0x3f);
|
|
padLen = (ix < 56) ? (56 - ix) : (120 - ix);
|
|
Update(MD4_PADDING, padLen);
|
|
|
|
// Append length (before padding)
|
|
Update(pBits, 8);
|
|
|
|
// Store state in digest
|
|
_Encode(m_digest, m_state, 16);
|
|
}
|
|
|
|
// MD4 basic transformation. Transforms state based on block.
|
|
void CMD4Hash::_Transform(UWORD32 *pState, const UWORD8 *pBlock)
|
|
{
|
|
UWORD32 a = pState[0], b = pState[1], c = pState[2], d = pState[3];
|
|
UWORD32 x[16];
|
|
|
|
_Decode(x, pBlock, 64);
|
|
|
|
// Round 1
|
|
MD4FF(a, b, c, d, x[ 0], MD4_S11);
|
|
MD4FF(d, a, b, c, x[ 1], MD4_S12);
|
|
MD4FF(c, d, a, b, x[ 2], MD4_S13);
|
|
MD4FF(b, c, d, a, x[ 3], MD4_S14);
|
|
MD4FF(a, b, c, d, x[ 4], MD4_S11);
|
|
MD4FF(d, a, b, c, x[ 5], MD4_S12);
|
|
MD4FF(c, d, a, b, x[ 6], MD4_S13);
|
|
MD4FF(b, c, d, a, x[ 7], MD4_S14);
|
|
MD4FF(a, b, c, d, x[ 8], MD4_S11);
|
|
MD4FF(d, a, b, c, x[ 9], MD4_S12);
|
|
MD4FF(c, d, a, b, x[10], MD4_S13);
|
|
MD4FF(b, c, d, a, x[11], MD4_S14);
|
|
MD4FF(a, b, c, d, x[12], MD4_S11);
|
|
MD4FF(d, a, b, c, x[13], MD4_S12);
|
|
MD4FF(c, d, a, b, x[14], MD4_S13);
|
|
MD4FF(b, c, d, a, x[15], MD4_S14);
|
|
|
|
// Round 2
|
|
MD4GG(a, b, c, d, x[ 0], MD4_S21);
|
|
MD4GG(d, a, b, c, x[ 4], MD4_S22);
|
|
MD4GG(c, d, a, b, x[ 8], MD4_S23);
|
|
MD4GG(b, c, d, a, x[12], MD4_S24);
|
|
MD4GG(a, b, c, d, x[ 1], MD4_S21);
|
|
MD4GG(d, a, b, c, x[ 5], MD4_S22);
|
|
MD4GG(c, d, a, b, x[ 9], MD4_S23);
|
|
MD4GG(b, c, d, a, x[13], MD4_S24);
|
|
MD4GG(a, b, c, d, x[ 2], MD4_S21);
|
|
MD4GG(d, a, b, c, x[ 6], MD4_S22);
|
|
MD4GG(c, d, a, b, x[10], MD4_S23);
|
|
MD4GG(b, c, d, a, x[14], MD4_S24);
|
|
MD4GG(a, b, c, d, x[ 3], MD4_S21);
|
|
MD4GG(d, a, b, c, x[ 7], MD4_S22);
|
|
MD4GG(c, d, a, b, x[11], MD4_S23);
|
|
MD4GG(b, c, d, a, x[15], MD4_S24);
|
|
|
|
// Round 3
|
|
MD4HH(a, b, c, d, x[ 0], MD4_S31);
|
|
MD4HH(d, a, b, c, x[ 8], MD4_S32);
|
|
MD4HH(c, d, a, b, x[ 4], MD4_S33);
|
|
MD4HH(b, c, d, a, x[12], MD4_S34);
|
|
MD4HH(a, b, c, d, x[ 2], MD4_S31);
|
|
MD4HH(d, a, b, c, x[10], MD4_S32);
|
|
MD4HH(c, d, a, b, x[ 6], MD4_S33);
|
|
MD4HH(b, c, d, a, x[14], MD4_S34);
|
|
MD4HH(a, b, c, d, x[ 1], MD4_S31);
|
|
MD4HH(d, a, b, c, x[ 9], MD4_S32);
|
|
MD4HH(c, d, a, b, x[ 5], MD4_S33);
|
|
MD4HH(b, c, d, a, x[13], MD4_S34);
|
|
MD4HH(a, b, c, d, x[ 3], MD4_S31);
|
|
MD4HH(d, a, b, c, x[11], MD4_S32);
|
|
MD4HH(c, d, a, b, x[ 7], MD4_S33);
|
|
MD4HH(b, c, d, a, x[15], MD4_S34);
|
|
|
|
pState[0] += a;
|
|
pState[1] += b;
|
|
pState[2] += c;
|
|
pState[3] += d;
|
|
}
|
|
|
|
void CMD4Hash::_Encode(UWORD8 *pOutput, const UWORD32 *pInput, UINTPREF uLen)
|
|
{
|
|
UINTPREF i, j;
|
|
|
|
for(i = 0, j = 0; j < uLen; i++, j += 4)
|
|
{
|
|
pOutput[j] = (UWORD8)(pInput[i] & 0xFF);
|
|
pOutput[j+1] = (UWORD8)((pInput[i] >> 8) & 0xFF);
|
|
pOutput[j+2] = (UWORD8)((pInput[i] >> 16) & 0xFF);
|
|
pOutput[j+3] = (UWORD8)((pInput[i] >> 24) & 0xFF);
|
|
}
|
|
}
|
|
|
|
void CMD4Hash::_Decode(UWORD32 *pOutput, const UWORD8 *pInput, UINTPREF uLen)
|
|
{
|
|
UINTPREF i, j;
|
|
|
|
for(i = 0, j = 0; j < uLen; i++, j += 4)
|
|
pOutput[i] = ((UWORD32)pInput[j]) | (((UWORD32)pInput[j+1]) << 8) |
|
|
(((UWORD32)pInput[j+2]) << 16) | (((UWORD32)pInput[j+3]) << 24);
|
|
}
|