/* md5sum.c by Michael Thorpe 2020-11-20 */ /* Adapted from Colin Plumb' 1993 public domain version */ /* This is because glibc is a festering boil on the face of computerdom... */ #define _FILE_OFFSET_BITS 64 const char usage[]="usage: md5sum [-bchtv] [ [ [..]]\n"; #include #include #include #include #define BUF_SIZE 4096 static int verboseprogress=0,neednl=0; /* You can define ON_LITTLE_ENDIAN to speed things up somewhat on */ /* little-endian machines */ #ifdef __i386__ #define ON_LITTLE_ENDIAN 1 #endif /* We need a 32-bit unsigned int; you may need to change this */ typedef unsigned int u32; struct md5context { u32 buf[4]; u32 bits[2]; unsigned char in[64]; }; #if ON_LITTLE_ENDIAN #define byteReverse(buf,len) /* Nothing */ #else /* Note: this code is harmless on little-endian machines */ void byteReverse(unsigned char *buf,unsigned int longs) { u32 t; do { t=((u32)buf[3]<<24) | ((u32)buf[2]<<16) | ((u32)buf[1]<<8) | buf[0]; *(u32 *)buf=t; buf+=4; } while(--longs); } #endif /* The four core functions - F1 is optimized somewhat */ /* #define F1(x,y,z) ((x&y)|(~x&z)) */ #define F1(x,y,z) (z^(x&(y^z))) #define F2(x,y,z) F1(z,x,y) #define F3(x,y,z) (x^y^z) #define F4(x,y,z) (y^(x|~z)) /* This is the central step in the MD5 algorithm */ #define MD5STEP(f,w,x,y,z,data,s) \ (w+=f(x,y,z)+data, w=(w<>(32-s)), w+=x) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. md5update blocks * the data and converts bytes into longwords for this routine. */ void md5transform(u32 buf[4], u32 in[16]) { u32 a,b,c,d; a=buf[0]; b=buf[1]; c=buf[2]; d=buf[3]; MD5STEP(F1,a,b,c,d,in[0]+0xd76aa478,7); MD5STEP(F1,d,a,b,c,in[1]+0xe8c7b756,12); MD5STEP(F1,c,d,a,b,in[2]+0x242070db,17); MD5STEP(F1,b,c,d,a,in[3]+0xc1bdceee,22); MD5STEP(F1,a,b,c,d,in[4]+0xf57c0faf,7); MD5STEP(F1,d,a,b,c,in[5]+0x4787c62a,12); MD5STEP(F1,c,d,a,b,in[6]+0xa8304613,17); MD5STEP(F1,b,c,d,a,in[7]+0xfd469501,22); MD5STEP(F1,a,b,c,d,in[8]+0x698098d8,7); MD5STEP(F1,d,a,b,c,in[9]+0x8b44f7af,12); MD5STEP(F1,c,d,a,b,in[10]+0xffff5bb1,17); MD5STEP(F1,b,c,d,a,in[11]+0x895cd7be,22); MD5STEP(F1,a,b,c,d,in[12]+0x6b901122,7); MD5STEP(F1,d,a,b,c,in[13]+0xfd987193,12); MD5STEP(F1,c,d,a,b,in[14]+0xa679438e,17); MD5STEP(F1,b,c,d,a,in[15]+0x49b40821,22); MD5STEP(F2,a,b,c,d,in[1]+0xf61e2562,5); MD5STEP(F2,d,a,b,c,in[6]+0xc040b340,9); MD5STEP(F2,c,d,a,b,in[11]+0x265e5a51,14); MD5STEP(F2,b,c,d,a,in[0]+0xe9b6c7aa,20); MD5STEP(F2,a,b,c,d,in[5]+0xd62f105d,5); MD5STEP(F2,d,a,b,c,in[10]+0x02441453,9); MD5STEP(F2,c,d,a,b,in[15]+0xd8a1e681,14); MD5STEP(F2,b,c,d,a,in[4]+0xe7d3fbc8,20); MD5STEP(F2,a,b,c,d,in[9]+0x21e1cde6,5); MD5STEP(F2,d,a,b,c,in[14]+0xc33707d6,9); MD5STEP(F2,c,d,a,b,in[3]+0xf4d50d87,14); MD5STEP(F2,b,c,d,a,in[8]+0x455a14ed,20); MD5STEP(F2,a,b,c,d,in[13]+0xa9e3e905,5); MD5STEP(F2,d,a,b,c,in[2]+0xfcefa3f8,9); MD5STEP(F2,c,d,a,b,in[7]+0x676f02d9,14); MD5STEP(F2,b,c,d,a,in[12]+0x8d2a4c8a,20); MD5STEP(F3,a,b,c,d,in[5]+0xfffa3942,4); MD5STEP(F3,d,a,b,c,in[8]+0x8771f681,11); MD5STEP(F3,c,d,a,b,in[11]+0x6d9d6122,16); MD5STEP(F3,b,c,d,a,in[14]+0xfde5380c,23); MD5STEP(F3,a,b,c,d,in[1]+0xa4beea44,4); MD5STEP(F3,d,a,b,c,in[4]+0x4bdecfa9,11); MD5STEP(F3,c,d,a,b,in[7]+0xf6bb4b60,16); MD5STEP(F3,b,c,d,a,in[10]+0xbebfbc70,23); MD5STEP(F3,a,b,c,d,in[13]+0x289b7ec6,4); MD5STEP(F3,d,a,b,c,in[0]+0xeaa127fa,11); MD5STEP(F3,c,d,a,b,in[3]+0xd4ef3085,16); MD5STEP(F3,b,c,d,a,in[6]+0x04881d05,23); MD5STEP(F3,a,b,c,d,in[9]+0xd9d4d039,4); MD5STEP(F3,d,a,b,c,in[12]+0xe6db99e5,11); MD5STEP(F3,c,d,a,b,in[15]+0x1fa27cf8,16); MD5STEP(F3,b,c,d,a,in[2]+0xc4ac5665,23); MD5STEP(F4,a,b,c,d,in[0]+0xf4292244,6); MD5STEP(F4,d,a,b,c,in[7]+0x432aff97,10); MD5STEP(F4,c,d,a,b,in[14]+0xab9423a7,15); MD5STEP(F4,b,c,d,a,in[5]+0xfc93a039,21); MD5STEP(F4,a,b,c,d,in[12]+0x655b59c3,6); MD5STEP(F4,d,a,b,c,in[3]+0x8f0ccc92,10); MD5STEP(F4,c,d,a,b,in[10]+0xffeff47d,15); MD5STEP(F4,b,c,d,a,in[1]+0x85845dd1,21); MD5STEP(F4,a,b,c,d,in[8]+0x6fa87e4f,6); MD5STEP(F4,d,a,b,c,in[15]+0xfe2ce6e0,10); MD5STEP(F4,c,d,a,b,in[6]+0xa3014314,15); MD5STEP(F4,b,c,d,a,in[13]+0x4e0811a1,21); MD5STEP(F4,a,b,c,d,in[4]+0xf7537e82,6); MD5STEP(F4,d,a,b,c,in[11]+0xbd3af235,10); MD5STEP(F4,c,d,a,b,in[2]+0x2ad7d2bb,15); MD5STEP(F4,b,c,d,a,in[9]+0xeb86d391,21); buf[0]+=a; buf[1]+=b; buf[2]+=c; buf[3]+=d; } /* * Start MD5 accumulation. */ void md5init(struct md5context *ctx) { /* Set buffer to mysterious initialization constants */ ctx->buf[0]=0x67452301; ctx->buf[1]=0xefcdab89; ctx->buf[2]=0x98badcfe; ctx->buf[3]=0x10325476; /* Set bit count to 0 */ ctx->bits[0]=0; ctx->bits[1]=0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void md5update(struct md5context *ctx,unsigned char *buf,unsigned int len) { u32 t; unsigned char *p; /* Update bitcount */ t=ctx->bits[0]; if(t>(ctx->bits[0]=t+((u32)len<<3))) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1]+=len>>29; /* Bytes already in shsInfo->data */ t=(t>>3)&0x3f; /* Handle any leading odd-sized chunks */ if(t) { p=ctx->in+t; t=64-t; if(lenin,16); md5transform(ctx->buf,(u32 *)ctx->in); buf+=t; len-=t; } /* Process data in 64-byte chunks */ while(len>=64) { memcpy(ctx->in,buf,64); byteReverse(ctx->in,16); md5transform(ctx->buf,(u32 *)ctx->in); buf+=64; len-=64; } /* Handle any remaining bytes of data */ memcpy(ctx->in,buf,len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void md5final(struct md5context *ctx,unsigned char digest[16]) { unsigned int count; unsigned char *p; /* Compute number of bytes mod 64 */ count=(ctx->bits[0]>>3)&0x3F; /* Set the first char of padding to 0x80 */ /* This is safe since there is always at least one byte free */ p=ctx->in+count; *p++=0x80; /* Bytes of padding needed to make 64 bytes */ count=64-1-count; /* Pad out to 56 mod 64 */ if(count<8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p,0,count); byteReverse(ctx->in,16); md5transform(ctx->buf,(u32 *)ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in,0,56); } else { /* Pad block to 56 bytes */ memset(p,0,count-8); } byteReverse(ctx->in,14); /* Append length in bits and transform */ ((u32 *)ctx->in)[14]=ctx->bits[0]; ((u32 *)ctx->in)[15]=ctx->bits[1]; md5transform(ctx->buf,(u32 *)ctx->in); byteReverse((unsigned char *)ctx->buf,4); memcpy(digest,ctx->buf,16); memset(ctx,0,sizeof(*ctx)); /* In case it's sensitive */ } static void showresult(const char *fname,unsigned char result[16]) { int i; if(neednl) { fputc('\n',stderr); neednl=0; } for(i=0;i<16;i++) printf("%2.2x",result[i]); if(fname) printf(" %s",fname); putchar('\n'); } static int make(const char *fname,FILE *f,unsigned char result[16]) { struct md5context pms; size_t l; unsigned char buf[BUF_SIZE]; if(verboseprogress) { fprintf(stderr,"%s",fname); neednl=1; } md5init(&pms); while(1) { l=fread(buf,1,BUF_SIZE,f); if(0==l) break; if(-1==l) { if(neednl) { fputc('\n',stderr); neednl=0; } perror("read"); return(1); } md5update(&pms,buf,l); } md5final(&pms,result); if(verboseprogress && neednl) fputc('\r',stderr); return(0); } static int check(const char *fname,FILE *f,int textmode) { unsigned char old[16],new[16]; char buf[BUF_SIZE]; FILE *f2; int goterror=0; int i,l; while(fgets(buf,BUF_SIZE,f)) { l=strlen(buf); if('\n' != buf[l-1]) { if(neednl) { fputc('\n',stderr); neednl=0; } fprintf(stderr,"Line too long in %s: %s...\n",fname,buf); goterror=1; continue; } buf[--l]='\0'; if(l<32) { if(neednl) { fputc('\n',stderr); neednl=0; } fprintf(stderr,"Line too short in %s: %s\n",fname,buf); goterror=1; continue; } memset(old,0,16); for(i=0;i<32;i++) { if(isxdigit(buf[i])) { old[i>>1]<<=4; if(isdigit(buf[i])) old[i>>1]|=buf[i]-'0'; else if(isupper(buf[i])) old[i>>1]|=buf[i]-'A'+10; else old[i>>1]|=buf[i]-'a'+10; } else { if(neednl) { fputc('\n',stderr); neednl=0; } fprintf(stderr,"Invalid line in %s: %s\n",fname,buf); goterror=1; continue; } } if(l<34) { if(textmode) { if(neednl) { fputc('\n',stderr); neednl=0; } fputs("warning: text mode not supported for stdin\n",stderr); goterror=1; } f2=stdin; } else { f2=fopen(buf+34,textmode?"r":"rb"); if(!f2) { if(neednl) { fputc('\n',stderr); neednl=0; } perror(buf+34); goterror=1; continue; } } if(make(l<34?"-":buf+34,f2,new)) goterror=1; else { if(memcmp(old,new,16)) { if(neednl) { fputc('\n',stderr); neednl=0; } fprintf(stderr,"%s: FAILED\n",l<34?"-":buf+34); goterror=1; } } if(l>=34) { if(fclose(f2)) { if(neednl) { fputc('\n',stderr); neednl=0; } perror("close"); goterror=1; } } } if(neednl) { fputc('\n',stderr); neednl=0; } return(goterror); } int main(int argc,char **argv) { int docheck=0,goterror=0,textmode=0; unsigned char result[16]; FILE *f; int i; while(-1 != (i=getopt(argc,argv,"+bchtv"))) { switch(i) { case 'b': textmode=0; break; case 'c': docheck=1; break; case 'h': fputs(usage,stdout); fputs(" -b binary mode (default; ignored for compatibility)\n",stdout); fputs(" -c check the MD5s stored in the files\n",stdout); fputs(" -h show this help message\n",stdout); fputs(" -t text mode\n",stdout); fputs(" -v output filename+ to stderr as progress indicator\n",stdout); return(0); case 't': textmode=1; break; case 'v': verboseprogress=1; break; default: fputs(usage,stderr); return(1); } } if(optind==argc) { if(textmode) { fputs("warning: text mode not supported for stdin\n",stderr); goterror=1; } if(docheck) { if(check("-",stdin,textmode)) goterror=1; } else { if(make("-",stdin,result)) goterror=1; else showresult(0,result); } } for(i=optind;i