/**********************************************************************\ VALIDATE - Portable "C" version of a CRC validation program which uses the same mechanisms as McAfee's VALIDATE program. Arguments: Filename(s) - The name(s) of the file(s) to be checked. (See complete documentation following code in this file) Author: Gary P. Mussar (gmussar on BIX) This code is released to the public domain. There are no restrictions, however, acknowledging the author by keeping this comment around would be appreciated. Compile command: cc validate -fop \**********************************************************************/ #include #include char version[] = {"Portable VALIDATE (Public Domain) V1.0 1991-01-05"}; /**********************************************************************\ The following is used to define the types of variable used to hold or manipulate CRCs. The 16 bit CRCs require a data type which is at least 16 bits. In addition, the data bits reserved for the CRC must be manipulated in an unsigned fashion. It is possible to define a data type which is larger than required to hold the CRC, however, this is an inefficient use of memory and usually results in less efficient code. \**********************************************************************/ #define CRC16 unsigned /**********************************************************************\ The coefficient of each term of the generator polynomial is represented by a bit in the polynomial array (except for the highest order term which is always assumed to be 1). The coefficient for the second highest term in the LSB of the first byte of the polynomial array. CRC Check 1 Polynomial x^16 + x^15 + x^2 + 1 (16 bit BCS polynomial) Generator is pre-initialized to 0x0000 CRC Check 2 Polynomial x^16 + x^15 + x^10 + x^3 Generator is pre-initialized to 0x0000 \**********************************************************************/ CRC16 crcchk1[256]; /* Fast lookup table */ CRC16 poly_crcchk1 = {0xA001}; /* Generator polynomial */ CRC16 init_crcchk1 = {0x0000}; /* Pre-init value */ CRC16 crc_crcchk1; /* CRC accumulator */ CRC16 crcchk2[256]; /* Fast lookup table */ CRC16 poly_crcchk2 = {0x1021}; /* Generator polynomial */ CRC16 init_crcchk2 = {0x0000}; /* Pre-init value */ CRC16 crc_crcchk2; /* CRC accumulator */ /* File stuff. The file is read (and CRCs calculated) in chunks. The size of a chunk is determined by the size of buff[] */ FILE *fp; char buff[8192]; /**********************************************************************\ Utilities for fast CRC using table lookup CRC calculations are performed one byte at a time using a table lookup mechanism. Two routines are provided: one to initialize the CRC lookup table; and one to perform the CRC calculation over an array of bytes. A CRC is the remainder produced by dividing a generator polynomial into a data polynomial using binary arthimetic (XORs). The data polynomial is formed by using each bit of the data as a coefficient of a term in the polynomial. These utilities assume the data communications ordering of bits for the data polynomial, ie. the LSB of the first byte of data is the coefficient of the highest term of the polynomial, etc.. I_CRC16 - Initialize the 256 entry CRC lookup table based on the specified generator polynomial. Input: Table[256] - Lookup table GenPolynomial - Generator polynomial F_CRC16 - Calculate CRC over an array of characters using fast table lookup. Input: Table[256] - Lookup table *CRC - Pointer to the variable containing the result of CRC calculations of previous characters. The CRC variable must be initialized to a known value before the first call to this routine. *dataptr - Pointer to array of characters to be included in the CRC calculation. count - Number of characters in the array. \**********************************************************************/ I_CRC16(Table, GenPolynomial) CRC16 Table[256]; CRC16 GenPolynomial; { int i; CRC16 crc; for (i = 0; i < 256; ++i) { crc = (CRC16) i; crc = (crc >> 1) ^ ((crc & 1) ? GenPolynomial : 0); crc = (crc >> 1) ^ ((crc & 1) ? GenPolynomial : 0); crc = (crc >> 1) ^ ((crc & 1) ? GenPolynomial : 0); crc = (crc >> 1) ^ ((crc & 1) ? GenPolynomial : 0); crc = (crc >> 1) ^ ((crc & 1) ? GenPolynomial : 0); crc = (crc >> 1) ^ ((crc & 1) ? GenPolynomial : 0); crc = (crc >> 1) ^ ((crc & 1) ? GenPolynomial : 0); crc = (crc >> 1) ^ ((crc & 1) ? GenPolynomial : 0); Table[i] = crc; } } F_CRC16(Table, CRC, dataptr, count) CRC16 Table[256]; CRC16 *CRC; unsigned char *dataptr; unsigned int count; { CRC16 temp_crc; for (temp_crc = *CRC; count; --count) { temp_crc = (temp_crc >> 8) ^ Table[(temp_crc & 0xff) ^ *dataptr++]; } *CRC = temp_crc; } /**********************************************************************\ Mainline Each file specified on the input line is opened (in binary mode) and two CRCs are calculated over the data. The CRC generators are initialized to 0 which means that null bytes (00) added to the front of a file will not affect the CRC (sigh, when will people ever learn). Hopefully the file length will catch these kinds of problems. \**********************************************************************/ main(argc, argv) int argc; char *argv[]; { unsigned len, files, bcount_h, bcount_l; fprintf(stderr, "%s\n", version); /* We expect 1 or more arguments */ if (argc < 2) { fprintf(stderr, "This program prints the validation information for a file.\n"); fprintf(stderr, "Examples:\n"); fprintf(stderr, " VALIDATE SCAN.EXE\n"); fprintf(stderr, " VALIDATE SCANRES.EXE\n"); exit(1); } /* Set up CRC tables */ I_CRC16(crcchk1, poly_crcchk1); I_CRC16(crcchk2, poly_crcchk2); /* Loop through each filename on the invocation line */ for (files = 1; files < argc; ++files) { printf("\n File Name: %s\n", argv[files]); fp=open(argv[files],F_READ); if (!fp) { fprintf(stderr, "\n Sorry, I cannot open the input file.\n"); continue; } /* Byte count and CRC generators to initial values */ bcount_h = bcount_l = 0; crc_crcchk1 = init_crcchk1; crc_crcchk2 = init_crcchk2; /* Read the file in chunks until done */ while ((len = read(buff, sizeof(buff), fp)) != 0) { /* Calculate CRC over this part of file */ F_CRC16(crcchk1, &crc_crcchk1, buff, len); F_CRC16(crcchk2, &crc_crcchk2, buff, len); /* Byte count of file */ if((bcount_l += len) > 10000) ++bcount_h, bcount_l -= 10000; } /* Give the user the results */ printf(" Size: %u%04u\n", bcount_h, bcount_l); printf("File Authentication:\n"); printf(" Check Method 1 - %04x\n", crc_crcchk1); printf(" Check Method 2 - %04x\n", crc_crcchk2); close(fp); } } /* Portable VALIDATE is a file authentication program which can be used to check software for signs of tampering. The program calculates two check codes over the data in a file by using two different CRC algorithms. The results can be checked against values provided by the author of the tested file or a list of values provided by a reliable source. One such reliable source is the Computer Virus Industry Association which maintains validation data for various shareware programs on-line. The CVIA bulletin board can be reached at (408) 988-4004. The user needs to perform the following steps when validating a program: - obtain the authentication numbers from a reliable source. - run Portable VALIDATE against the desired file. - compare the check codes produced by Portable VALIDATE against the reliable authentication numbers. If the numbers match, the user can be reasonably assured that the file or program has not been corrupted. The original VALIDATE program was provided by McAfee Associates as an executable module. This works great for IBM PCs and compatibles, however, sysops of non IBM PC BBSs cannot use this module. The Portable VALIDATE program was written so that sysops of these non-compatible BBSs could do quick validations of files. The Portable VALIDATE uses the same CRC algorithms as McAfee's VALIDATE and has been successfully run on a number of platforms including: IBM PC (Turbo C++) Sun 3 Sun SPARC Apollo McAfee Associates can be reached at (408) 988-3832. To run Portable VALIDATE, type: VALIDATE \path\filename.ext [\path\filename.ext] The program will display the following validation information: File Name: (\path\filename.ext) Size: (Number of Bytes) File Authentication: Check Method 1 - (4 digit CRC) Check Method 2 - (4 digit CRC) Portable VALIDATE has been released to the public domain in source code form. Please redistribute Portable VALIDATE in source code form with this document. Please report virus infection and verified instances of tampering to: Computer Virus Industry Association 4423 Cheeney Street Santa Clara, CA 95054 (408) 727-4559 */