110 lines
3.6 KiB
C
110 lines
3.6 KiB
C
/*----------------------------------------------------------------------------
|
|
;
|
|
; MD5 hash generator -- Paul Houle (paulhoule.com) 11/13/2017
|
|
;
|
|
; Non-time critical C logic. All API entry points are here.
|
|
; See phmd5.h for documentation.
|
|
;
|
|
;---------------------------------------------------------------------------*/
|
|
|
|
#include <string.h>
|
|
#include "phmd5.h"
|
|
|
|
// First call -- initialize pmd5 structure for use.
|
|
void Phmd5Begin(PHMD5 *pmd5) {
|
|
unsigned __int32 *uhash = (unsigned __int32 *) pmd5->hash;
|
|
|
|
uhash[0] = 0x67452301; // init hash per rfc1321
|
|
uhash[1] = 0xEFCDAB89;
|
|
uhash[2] = 0x98BADCFE;
|
|
uhash[3] = 0x10325476;
|
|
|
|
pmd5->totbyt = 0; // init count of data bytes processed
|
|
}
|
|
|
|
// Last call -- after this, pmd5->hash holds final MD5 hash.
|
|
void Phmd5End(PHMD5 *pmd5) {
|
|
char pad[72]; // pad buffer (worst case is 72 bytes)
|
|
unsigned padc; // size of needed pad (9-72 bytes)
|
|
|
|
padc = 64 - ((unsigned) pmd5->totbyt & 63); // pad to 64-byte boundary
|
|
if (padc < 9) padc += 64; // add a block if we need more room
|
|
memset(pad, 0, padc); // clear entire pad area
|
|
pad[0] = (char) 0x80; // place input stream terminator
|
|
// place 64-bit input data bit count
|
|
*(unsigned __int64 *) &pad[padc - 8] = pmd5->totbyt << 3;
|
|
Phmd5Process(pmd5, pad, padc); // process the pad
|
|
}
|
|
|
|
// Work done here -- call for as many input blocks that need to be processed.
|
|
// pdata points to the input data, bytecnt is pdata size (0..n bytes).
|
|
// See phmd5.h regarding how to use this optimally.
|
|
void Phmd5Process(PHMD5 *pmd5, char *pdata, size_t bytecnt) {
|
|
unsigned resid = (unsigned) pmd5->totbyt;
|
|
|
|
pmd5->totbyt += bytecnt; // update total bytes processed
|
|
|
|
resid &= 63; // count of bytes now in pmd5->buf
|
|
|
|
// This block handles the case of residual data in pmd5->buf.
|
|
// After this block pmd5->buf is empty (except perhaps on exit).
|
|
|
|
if (resid) { // if residual exists,
|
|
unsigned cb = 64 - resid;
|
|
if (cb > bytecnt) cb = (unsigned) bytecnt;
|
|
memcpy(pmd5->buf + resid, pdata, cb);
|
|
pdata += cb;
|
|
bytecnt -= cb;
|
|
if (resid + cb < 64) return;
|
|
Phmd5DoBlocks(pmd5->hash, pmd5->buf, 64);
|
|
}
|
|
|
|
// This block processes input data in-place, if the data is dword
|
|
// aligned and in 64-byte chunks.
|
|
|
|
if ((unsigned) bytecnt & ~63 && ((size_t) pdata & 3) == 0) {
|
|
Phmd5DoBlocks(pmd5->hash, pdata, bytecnt & ~63);
|
|
pdata += bytecnt & ~63;
|
|
bytecnt &= 63;
|
|
}
|
|
|
|
while (bytecnt) { // handle residual/non-aligned data
|
|
unsigned cb = 64 > (unsigned) bytecnt ? (unsigned) bytecnt : 64;
|
|
memcpy(pmd5->buf, pdata, cb);
|
|
pdata += cb;
|
|
bytecnt -= cb;
|
|
if (cb < 64) return;
|
|
Phmd5DoBlocks(pmd5->hash, pmd5->buf, 64);
|
|
};
|
|
}
|
|
|
|
// Added by Yutaka Sawada for PAR2's padding null bytes at the last of each file.
|
|
void Phmd5ProcessZero(PHMD5 *pmd5, size_t bytecnt) {
|
|
unsigned resid = (unsigned) pmd5->totbyt;
|
|
|
|
pmd5->totbyt += bytecnt; // update total bytes processed
|
|
|
|
resid &= 63; // count of bytes now in pmd5->buf
|
|
|
|
// This block handles the case of residual data in pmd5->buf.
|
|
// After this block pmd5->buf is empty (except perhaps on exit).
|
|
|
|
if (resid) { // if residual exists,
|
|
unsigned cb = 64 - resid;
|
|
if (cb > bytecnt) cb = (unsigned) bytecnt;
|
|
memset(pmd5->buf + resid, 0, cb);
|
|
bytecnt -= cb;
|
|
if (resid + cb < 64) return;
|
|
Phmd5DoBlocks(pmd5->hash, pmd5->buf, 64);
|
|
}
|
|
|
|
// This block processes input data in-place, if the data is in 64-byte chunks.
|
|
|
|
if (bytecnt & ~63) {
|
|
Phmd5DoBlocksZero(pmd5->hash, bytecnt & ~63);
|
|
bytecnt &= 63;
|
|
}
|
|
|
|
if (bytecnt) memset(pmd5->buf, 0, 64); // handle residual data
|
|
}
|