Skip to content

Commit

Permalink
Merge MD5State into MD5Context, and avoid unnecessary copying of MD5 …
Browse files Browse the repository at this point in the history
…blocks on little-endian platforms
  • Loading branch information
animetosho committed Mar 11, 2023
1 parent 5279777 commit 0898510
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 56 deletions.
83 changes: 43 additions & 40 deletions src/md5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,25 @@ string MD5Hash::print(void) const
return buffer;
}

MD5State::MD5State(void)
{
Reset();
}

// Initialise the 16 byte state
void MD5State::Reset(void)
{
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
}

// Update the state using 64 bytes of new data
void MD5State::UpdateState(const u32 (&block)[16])
inline void MD5Context::UpdateState(const unsigned char* current)
{
#if __BYTE_ORDER != __LITTLE_ENDIAN
u32 wordblock[16];
for (int i=0; i<16; i++)
{
// Convert source data from little endian format to internal format if different
wordblock[i] = ( ((u32)current[i*4+3]) << 24 ) |
( ((u32)current[i*4+2]) << 16 ) |
( ((u32)current[i*4+1]) << 8 ) |
( ((u32)current[i*4+0]) << 0 );
}
# define ROUND(f,w,x,y,z,k,s,ti) w = x + ROL(w + f(x,y,z) + wordblock[k] + ti, s)
#else
u32 input;
# define ROUND(f,w,x,y,z,k,s,ti) memcpy(&input, &current[(k)*4], 4); w = x + ROL(w + f(x,y,z) + input + ti, s)
#endif

// Primitive operations
#define F1(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) )
#define F2(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) )
Expand All @@ -85,7 +87,6 @@ void MD5State::UpdateState(const u32 (&block)[16])
//#define ROL(x,y) ( ((x) << (y)) | (((unsigned int)x) >> (32-y)) )
#define ROL(x,y) ( ((x) << (y)) | (((x) >> (32-y)) & ((1<<y)-1)))

#define ROUND(f,w,x,y,z,k,s,ti) w = x + ROL(w + f(x,y,z) + block[k] + ti, s)

u32 a = state[0];
u32 b = state[1];
Expand Down Expand Up @@ -179,16 +180,20 @@ void MD5State::UpdateState(const u32 (&block)[16])
}

MD5Context::MD5Context(void)
: MD5State()
, used(0)
: used(0)
, bytes(0)
{
memset(block, 0, buffersize);
Reset();
}

// Initialise the 16 byte state
void MD5Context::Reset(void)
{
MD5State::Reset();
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
used = 0;
bytes = 0;
}
Expand Down Expand Up @@ -231,8 +236,8 @@ void MD5Context::Update(const void *buffer, size_t length)
// Update the total amount of data processed.
bytes += length;

// Process any whole blocks
while (used + length >= buffersize)
// Process first whole block if we have something in the buffer
if (used && used + length >= buffersize)
{
size_t have = buffersize - used;

Expand All @@ -241,21 +246,19 @@ void MD5Context::Update(const void *buffer, size_t length)
current += have;
length -= have;

u32 wordblock[16];
for (int i=0; i<16; i++)
{
// Convert source data from little endian format to internal format if different
wordblock[i] = ( ((u32)block[i*4+3]) << 24 ) |
( ((u32)block[i*4+2]) << 16 ) |
( ((u32)block[i*4+1]) << 8 ) |
( ((u32)block[i*4+0]) << 0 );
}

MD5State::UpdateState(wordblock);
UpdateState(block);

used = 0;
}

// Process all subsequent whole blocks
while (length >= buffersize)
{
UpdateState(current);
current += buffersize;
length -= buffersize;
}

// Store any remainder
if (length > 0)
{
Expand Down Expand Up @@ -301,10 +304,10 @@ void MD5Context::Final(MD5Hash &output)
for (int i = 0; i < 4; i++)
{
// Read out the state and convert it from internal format to little endian format
output.hash[4*i+3] = (u8)((MD5State::state[i] >> 24) & 0xFF);
output.hash[4*i+2] = (u8)((MD5State::state[i] >> 16) & 0xFF);
output.hash[4*i+1] = (u8)((MD5State::state[i] >> 8) & 0xFF);
output.hash[4*i+0] = (u8)((MD5State::state[i] >> 0) & 0xFF);
output.hash[4*i+3] = (u8)((state[i] >> 24) & 0xFF);
output.hash[4*i+2] = (u8)((state[i] >> 16) & 0xFF);
output.hash[4*i+1] = (u8)((state[i] >> 8) & 0xFF);
output.hash[4*i+0] = (u8)((state[i] >> 0) & 0xFF);
}
}

Expand All @@ -316,10 +319,10 @@ MD5Hash MD5Context::Hash(void) const
for (unsigned int i = 0; i < 4; i++)
{
// Read out the state and convert it from internal format to little endian format
output.hash[4*i+3] = (unsigned char)((MD5State::state[i] >> 24) & 0xFF);
output.hash[4*i+2] = (unsigned char)((MD5State::state[i] >> 16) & 0xFF);
output.hash[4*i+1] = (unsigned char)((MD5State::state[i] >> 8) & 0xFF);
output.hash[4*i+0] = (unsigned char)((MD5State::state[i] >> 0) & 0xFF);
output.hash[4*i+3] = (unsigned char)((state[i] >> 24) & 0xFF);
output.hash[4*i+2] = (unsigned char)((state[i] >> 16) & 0xFF);
output.hash[4*i+1] = (unsigned char)((state[i] >> 8) & 0xFF);
output.hash[4*i+0] = (unsigned char)((state[i] >> 0) & 0xFF);
}

return output;
Expand Down
21 changes: 5 additions & 16 deletions src/md5.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,24 +64,9 @@ struct MD5Hash
u8 hash[16]; // 16 byte MD5 Hash value
} PACKED;

// Intermediate computation state

class MD5State
{
public:
MD5State(void);
void Reset(void);

public:
void UpdateState(const u32 (&block)[16]);

protected:
u32 state[4]; // 16 byte MD5 computation state
};

// MD5 computation context with 64 byte buffer

class MD5Context : public MD5State
class MD5Context
{
public:
MD5Context(void);
Expand All @@ -108,8 +93,12 @@ class MD5Context : public MD5State
enum {buffersize = 64};
unsigned char block[buffersize];
size_t used;
u32 state[4]; // 16 byte MD5 computation state

u64 bytes;

private:
void UpdateState(const unsigned char* current);
};

// Compare hash values
Expand Down

0 comments on commit 0898510

Please sign in to comment.