/* * Ok, this is the stable release, after a long code overhaul. We can now read * as many files as the user throws at us, generate as many random pads to mix * in as the user asks for, and do it all much cleaner. * Future needs: * - have it check input filenames in the pad-md5-xxxxx.dat format to see if * their md5 sum really matches what their name claims it does. * - have an option to generate pads alone. * - make file pointer arrays expand to use whatever memory is needed. * * If you can improve upon this in any way, or have some kind of program that * uses it, please let me know. I'm interested. * * Everything contained in this file is subject to the terms of the GPL lisence * which is available in the COPYING file in this directory. * * --xercist@mindless.com * */ #include #include #include #include #include #include #include #include #include #include "pad.h" #include "md5.h" int main (int argc, char *argv[]) { char *ifname[256]; /* array of input file names */ char *ofname[256][FILENAME_MAX]; /* array of temp. output file names */ FILE *ifp[256]; int ofp[256]; struct md5_ctx context[256]; /* md5 contexts */ unsigned char digest[256][16]; /* md5 digests */ unsigned char currentbyte, readbyte; /* just a place to put new bytes */ char *outputname=NULL; /* output file name */ char buf[FILENAME_MAX]; /* temporary string space */ int defined_output=0, lastout, rands=-1, i, j; /* misc ints */ unsigned long bytecount=0, bytelimit=0; /* to limit/expand the filesize */ /* Let's parse some command params, eh? */ j=0; ifname[0]=NULL; for (i=1; (i < argc); i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'h': printversion(); printhelp(); exit(0); break; case 'v': printversion(); exit(0); break; case 'r': i++; if (argc == i) { fprintf(stderr, "-r must be used with a number.\n\n"); printhelp(); exit(1); } if ((!(rands = atoi(argv[i]))) || (rands < 0)) { fprintf(stderr, "-r must be used with a positive integer.\n\n"); printhelp(); exit(1); } break; case 's': i++; if (argc == i) { fprintf(stderr, "-s must be used with a filesize\n\n"); printhelp(); exit(1); } if (!(bytelimit = bytes_in(argv[i]))) { fprintf(stderr, "Error parsing output size\n\n"); printhelp(); exit(1); } break; case 'o': i++; if (argc == i) { fprintf(stderr, "-o must be used with an output filename.\n\n"); printhelp(); exit(1); } outputname=argv[i]; defined_output=1; break; default: fprintf(stderr, "Unknown option %s\n\n", argv[i]); printhelp(); exit(1); } } else { if ((j+rands) > 254) { /* This limitation will be removed as soon as I get around to making * the file pointer arrays self-expanding */ fprintf(stderr, "Random pads + Input files cannot exceed 255.\n"); exit(1); } else { ifname[j] = argv[i]; ifname[j+1] = NULL; j++; } } } if (j == 0) { printversion(); printhelp(); exit(1); } /* Let's open all our input files, and figure out how many * random pads should be mixed in, that is, if the user didn't tell us */ ifp[0]=NULL; for (i=0; (ifname[i] != NULL); i++) { if ((ifp[i]=fopen(ifname[i], "r"))==NULL) { fprintf(stderr,"Error opening %s: %s\n", ifname[i], strerror(errno)); exit(1); } ifp[i+1] = NULL; if ((rands == -1) && (i > 0)) rands=0; } if (rands == -1) rands=1; for (i=0; ifp[i] != NULL; i++) { if ((j != filesize(ifp[i])) && (i != 0)) { fprintf(stderr, "Warning: sizes of input files differ. Unless -s option was given,\noutput will match the size of the smallest input.\n"); break; } j=filesize(ifp[i]); } /* And now to figure out the names of our output files... */ ofname[0][0] = (char)0; for (i=0; i1)?"s":""); while (bytecount < bytelimit) { for (j=0; (j %s)\n", strerror(errno), ofname[i], buf ); } else { fprintf(stderr, "Wrote %s\n", buf); } } // for i exit(0); } // main() /* Return size of fp passed */ long filesize(FILE *fp) { struct stat buf; if (fstat(fileno(fp), &buf)) { return -1; } else { return buf.st_size; } } /* print out the help message */ void printhelp() { fprintf(stderr, "Usage: pad [options] [input files]\n\ \n\ options:\n\ \n\ -r [num] - Pad will XOR in [num] pads generated from random data. if this\n\ is omitted, pad will use either 1 or 0 random pads, depending on\n\ if there is only one input file or more than one, respectively.\n\ \n\ -o [output] - The result of all the XOR operations will be stored in this\n\ file. If [output] is omitted, pad will name the file according\n\ to its MD5-sum, along with the rest of the random pads.\n\ \n\ -s [size] - The output data will be [size] bytes. If this is less than the\n\ smallest input file, the output will be clipped to match, if it\n\ is larger, random data will be appended to the end.\n\ \n\ -h - Show usage.\n\ \n\ "); } void printversion() { fprintf(stderr, "Pad v%s by xercist\n", VERSION); } /* return 1 if one of the input files has hit eof */ int file_end(FILE *ifp[256]) { int i; for (i=0; ifp[i] != NULL; i++) { if (feof(ifp[i])) return 1; } return 0; } /* convert digest to readable string */ char *hexize(unsigned char digest[16]) { const char hexdigits[17] = "0123456789abcdef"; char buf[32]; int j; buf[0] = '\0'; for ( j=0 ; j<16 ; j++ ) { snprintf(buf, sizeof(buf), "%s%c", buf, (hexdigits[digest[j]>>4])); snprintf(buf, sizeof(buf), "%s%c", buf, (hexdigits[digest[j]&0xf])); } return((char *)strdup(buf)); } /* take a string like "5k" and return a number like 5120 */ unsigned long bytes_in(char *string) { int h, i, length=0; unsigned long total=0, multiplier=1; for (h=0;h<2;h++) { for (i=0;i 4294967294u) return 0; total += ((string[i]-'0')*pow(10,(length-(i+1)))); } } else { if (!h) { switch (string[i]) { case 'b': case 'B': multiplier=1; break; case 'k': case 'K': multiplier=1024; break; case 'm': case 'M': multiplier=pow(1024,2); break; default: return 0; break; } break; } else break; } } } total = total*multiplier; return total; }