Created
March 16, 2016 03:11
-
-
Save sbeckeriv/0ff5100f464e88a9caa2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// _IMAGE AUTHENTICATION FOR A SLIPPERY NEW AGE_ | |
//by Steve Walton | |
//Listing One | |
// <sealimg.c> | |
// Copyright 1994 by Steve Walton | |
// | |
// This implementation measures checksums using all of the upper 7 bits of each | |
// pixel, without varying the number of bits by random sequence. It does, | |
// however, ensure order dependence by multiplying sum elements pairwise with | |
// a pseudo-random sequence and accumulating a sum. | |
// The overall structure of this program is intended to roughly mirror or | |
// simulate what could be used as a hardware design. | |
// A temporary file is used to store "images" of checksum bits and walk | |
// locations. Obviously, this could be done in extended memory, but this method | |
// will work on 286-class machines with little or no RAM running without a swap | |
// manager, and is independent of image size. Up to 255 using checksum lengths | |
// up to 256 bits long are possible within the limits of this structure. | |
// The temporary disk file is roughly twice the size of image being tested | |
// for seals. Named <temp> and placed in the launch path, it is deleted after | |
// use. When filling the image with seal checksum bits, the sealspace map is | |
// used to embed them in one pass through the image; the map tells us which | |
// bit for which seal is to be forced into the pixel LSB. | |
// To reduce (apparent) code complexity and improve readability, this program | |
// is written using static global variables for file pointers, control | |
// variables, and so forth. Code-crafting could improve the structure a great | |
// deal, but this form is probably better for illustrating the underlying | |
// algorithms. All user-written functions used in this program are contained | |
// in this listing. | |
// Targa image format is used for file I/O, primarily because it is as | |
// universal as TIFF and MUCH easier to use on a casual basis. Hopefully, the | |
// structure is semi-self-evident from the code. | |
// Written with and compiled by Microsoft QuickC for Windows v1.00 | |
// TARGA is a registered trademark of Truevision, Inc. | |
// TGA is a registered trademark of Truevision, Inc. | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <conio.h> | |
#include <process.h> | |
#include <malloc.h> | |
#include <math.h> | |
// Structures must be stored byte-aligned! Compile with switch /Zp1 (Microsoft) | |
// or the equivalent. | |
typedef unsigned long ULONG; | |
typedef unsigned short USHORT; | |
typedef unsigned short BOOL; | |
typedef unsigned char BYTE; | |
// Truevision TARGA file header format | |
typedef struct { | |
BYTE idLength; // Identifies number of bytes in optional Targa Field 6 | |
BYTE colorMapType; // Type of color map (0=no color map, 1=color map used) | |
BYTE imageType; // Type of image (1=uncompress color-mapped, | |
// 2=24-bit direct, 3= monochrome) | |
USHORT firstEntry; // Index of first color map entry (usually 0) | |
USHORT mapLength; // Length of color map (number of colors) | |
BYTE entrySize; // Size of color map entry (bits) | |
USHORT xOrigin; // Horiz coord of L-L image corner on display | |
USHORT yOrigin; // Vert coord of L-L image corner on display | |
USHORT width; // Width of the image in pixels | |
USHORT height; // Height of the image in pixels | |
BYTE pixDepth; // Number of bits in each pixel location | |
BYTE imageDesc; // Alpha Channel bits or overlay bits | |
} tgaHeader_t; | |
// Truevision TARGA RGB triplet format | |
typedef struct { | |
BYTE blu; // 8-bit Blue component | |
BYTE grn; // 8-bit Green component | |
BYTE red; // 8-bit Red component | |
} rgbTriplet_t; | |
typedef struct { // The per-pixel-address descriptor | |
BYTE sealNum; // ... Index number of seal | |
BYTE bitNum; // ... bit number (0=LSB) of the checksum | |
} sealSpace_t; | |
typedef union { // Mechanizes our VERY SIMPLE pseudo-random-number | |
// generator seeds | |
char asciiChar[4]; // The characters are kept for reference. | |
} seal_t; | |
#define TRUE 1 | |
#define FALSE 0 | |
#define MONO 3 | |
#define PALETTE 1 | |
#define NOSEAL 0xFF | |
// -------------- Global Variable List ------------------------------- | |
ULONG | |
checksum[256] | |
; | |
seal_t | |
sealArray[255]; // Contains the seeds for each seal | |
FILE | |
*fpIn, // Input file pointer | |
*fpOut // Output file pointer | |
; | |
char | |
inFileName[80], // Input file name string (allow 80 bytes) | |
outFileName[80] // Output file name string (allow 80 bytes) | |
; | |
//////////////////////////// | |
// F u n c t i o n s // | |
//////////////////////////// | |
//-----------------------u r a n d D o u b l e ()------------------------------ | |
// A pseudo-random number generator designed to return floating-point | |
// quantities as a percentage of a passed range argument. This is the standard | |
// linear congruential generator which uses the recurrence relation i(j+1) = | |
// mod(m)[a * i(j) + c], where m is the modulus, a is the muliplier, | |
// and c is the offset. The randomness of these sequences is very dependent | |
// upon a, m, and c. The value of i(0) is called the seed. | |
#define URANDDOUBLE_MULTIPLIER 2416L // Multiplier | |
#define URANDDOUBLE_OFFSET 374441L // Offset | |
#define URANDDOUBLE_MODULUS 1771875L | |
static unsigned long urandDoubleSeed = 3456L; // global static unsigned | |
double urandDouble( double range ){ // long seed | |
urandDoubleSeed = (urandDoubleSeed * URANDDOUBLE_MULTIPLIER + | |
URANDDOUBLE_OFFSET) % URANDDOUBLE_MODULUS; | |
return( ((double)urandDoubleSeed * (range)) / (double)URANDDOUBLE_MODULUS ); | |
} | |
//---------------------------u r a n d W A ()---------------------------------- | |
// A pseudo-random number generator designed to return 16-bit quantities. This | |
// is an arrayed function of up to 256 outputs. This is the standard linear | |
// congruential generator which uses the recurrence relation i(j+1) = mod(m)[a | |
// * i(j) + c], where m is the modulus, a is muliplier, and c is the offset. | |
// The randomness of these sequences is very dependent upon a, m, and c. | |
// The value of i(0) is called the seed. | |
#define URANDWA_MULTIPLIER 2416L // Multiplier | |
#define URANDWA_OFFSET 374441L // Offset | |
#define URANDWA_MODULUS 1771875L | |
static unsigned long | |
urandWASeed[256]; // global static unsigned long seed | |
USHORT urandWA( short index ){ | |
urandWASeed[index] = (urandWASeed[index] * URANDWA_MULTIPLIER + | |
URANDWA_OFFSET) % URANDWA_MODULUS; | |
return( (USHORT)( (double)urandWASeed[index] * 65536.0 / | |
(double)URANDWA_MODULUS ) ); | |
} | |
//==================== s o l i c i t S e a l s () ============================= | |
// Gets up to 255 4-character sealing strings from the user and fills the | |
// file pointed to by <sealSpace> with seal# and bit# information. We are using | |
// 32-bit checksums, and the walk space is driven by urandWord() | |
short solicitSeals( FILE *sealSpace, long sealSpaceLength ){ | |
BOOL | |
sealGood = TRUE, | |
done = FALSE | |
; | |
short | |
i, | |
numSeal=0 | |
; | |
long walkAddress; | |
char | |
temp | |
; | |
sealSpace_t | |
sealPix | |
; | |
seal_t | |
inSeal | |
; | |
printf( "\n----Seal entry----\n" ); | |
printf( "Each four characters will be taken as a seal. Each seal's | |
validity is\n" ); | |
printf( "checked as it is entered. Invalid (intersecting) seals are | |
not accepted.\n" ); | |
printf( "You may enter up to 255 seals (indices are 0..254)\n" ); | |
while( !done ){ | |
printf( "Enter seal %d (ESC to end): ", numSeal ); | |
i=0; | |
while( i < 4 ){ | |
temp = (char)getch(); | |
if( temp == 27 ){ | |
done = TRUE; | |
break; | |
} else { | |
inSeal.asciiChar[i] = temp; | |
printf( "-" ); | |
i++; | |
} | |
} | |
if( !done ){ | |
printf( "%c Checking %c%c%c%c...", 7, inSeal.asciiChar[0], | |
inSeal.asciiChar[1], inSeal.asciiChar[2], inSeal.asciiChar[3] ); | |
// First, check the sealspace for any of these locations... | |
sealGood = TRUE; | |
urandDoubleSeed = inSeal.bits32 % URANDDOUBLE_MODULUS; | |
for( i=0; i<32; i++ ){ | |
walkAddress = (long)urandDouble( sealSpaceLength ); | |
if( walkAddress == sealSpaceLength ) walkAddress = sealSpaceLength-1; | |
fseek( sealSpace, walkAddress*sizeof(sealSpace_t), SEEK_SET ); | |
fread( &sealPix, sizeof( sealSpace_t ), 1, sealSpace ); | |
if( sealPix.sealNum != NOSEAL ){ | |
sealGood = FALSE; | |
break; | |
} | |
} | |
if( sealGood ){ | |
printf( "ok -- embedding...\n" ); | |
sealArray[numSeal].bits32 = inSeal.bits32; // Copy into seal array | |
// embed this seal into the sealspace map | |
urandDoubleSeed = inSeal.bits32 % URANDDOUBLE_MODULUS; | |
for( i=0; i<32; i++ ){ | |
walkAddress = (long)urandDouble( sealSpaceLength ); | |
if( walkAddress == sealSpaceLength ) walkAddress=sealSpaceLength-1; | |
sealPix.sealNum = (BYTE)numSeal; // Keep sealArray index in the map | |
sealPix.bitNum = (BYTE)i; // Keep bit number in the map | |
fseek( sealSpace, walkAddress*sizeof(sealSpace_t), SEEK_SET ); | |
fwrite( &sealPix, sizeof( sealSpace_t ), 1, sealSpace ); | |
} | |
numSeal++; | |
if( numSeal == 255 ) done = TRUE; // Limit number of seals | |
} else { | |
printf( "no. Try another.\n" ); | |
} | |
} // End checking and embedding section | |
} | |
printf( "\nYou have embedded %d seals.\n", numSeal ); | |
return( numSeal ); | |
} | |
//======================= o p e n F i l e s () ================================ | |
// Open image files. Test each file for validity and return FALSE if something | |
// is wrong. There are all sorts of clever ways to avoid using a "goto" | |
// statement, and I support most of them. This is one of the places where its | |
// use is justified to generate short, quick code. | |
BOOL openFiles( void ){ | |
tgaHeader_t *hdr; | |
// Go get temporary storage for the header so we can test it for validity | |
hdr = (tgaHeader_t *)malloc( sizeof(tgaHeader_t) ); | |
if( hdr == NULL ){ | |
printf( "Your system's seriously ill! Can't allocate 18 bytes | |
of dynamic memory!" ); | |
goto bugout; | |
} | |
// OPEN THE INPUT FILE | |
printf( "Enter complete input image file name: " ); | |
scanf( "%s", &inFileName[0] ); | |
fpIn = fopen( &inFileName[0], "rb" ); // Attempt to open the input file | |
if( fpIn == NULL ){ | |
printf( "Problem opening file %s\n", inFileName ); | |
goto errorExitCloseFile; | |
} | |
fread( hdr, sizeof(tgaHeader_t), (size_t)1, fpIn ); // Read the input block | |
rewind( fpIn ); // Reset file pointer to zero | |
if( hdr->imageType != MONO && hdr->imageType != PALETTE ){ | |
printf( "Input image is not Targa monochrome or palette." ); | |
goto errorExitCleanAll; | |
} | |
if( hdr->imageType == MONO && | |
(hdr->mapLength != 0 || hdr->colorMapType != 0 || hdr->pixDepth != 8 || | |
hdr->entrySize != 0 )){ | |
printf( "Corrupted monochrome image file." ); | |
goto errorExitCleanAll; | |
} | |
if( hdr->imageType == PALETTE && | |
(hdr->mapLength != 256 || hdr->colorMapType == 0 || | |
hdr->pixDepth != 8 || hdr->entrySize != 24 ) ){ | |
printf( "Not an appropriate 8-bit palette image file." ); | |
goto errorExitCleanAll; | |
} | |
// OPEN THE OUTPUT FILE | |
printf( "Enter output image name: " ); | |
scanf( "%s", &outFileName[0] ); | |
fpOut = fopen( &outFileName[0], "wb" ); // Attempt to open the output file | |
if( fpOut == NULL ){ | |
printf( "Problem opening file %s\n", outFileName ); | |
goto errorExitCloseFile; | |
} | |
// If we've gotten this far, it's likely that everything is OK and we can | |
// get back to business... | |
return( TRUE ); | |
errorExitCleanAll: // Error exit point | |
free( hdr ); | |
errorExitCloseFile: // Another error exit point | |
fcloseall(); | |
bugout: // Get outta here! | |
return( FALSE ); | |
} | |
//=========================== m a i n () ===================================== | |
// This program opens an 8-bit grey or 8-bit color mapped Targa file, reads it | |
// in row-by-row, and applies a list of seals to it. | |
void main( void ){ | |
BYTE | |
*rowIn, // Pointer to row of input image pixels | |
*rowOut // Pointer to row of output image pixels | |
; | |
short | |
i,j,k, // Temporary index variables | |
numSeals // Total number of seals to check for in the image | |
; | |
long | |
sealSpaceLength // Total number of pixels in the input image. | |
; | |
FILE | |
*sealSpace // File pointer to temporary "seal space frame" image file | |
; | |
tgaHeader_t | |
inFileHeader // Will contain input file Targa header | |
; | |
sealSpace_t | |
*sealRow // Pointer to row of seal space elements | |
; | |
rgbTriplet_t | |
*palette // Pointer to a palette full of rgb triplets | |
; | |
// Print out the program identification and default values | |
printf( "<sealimg.c>\nCopyright 9/20/94 by Steve Walton\n" ); | |
if( !openFiles() ) exit(0); // Get the files from the user and open them | |
fread( &inFileHeader, sizeof(tgaHeader_t), (size_t)1, fpIn ); | |
sealSpaceLength = (long)inFileHeader.width * (long)inFileHeader.height; | |
sealSpace = fopen( "temp", "wb+" ); // Open sealspace file for random R/W | |
sealRow = (sealSpace_t *)malloc( sizeof( sealSpace_t ) * | |
inFileHeader.width ); | |
printf( "Clearing sealspace...\n" ); | |
// Clear temporary file with seal walkspace data, since it will be filled | |
for( i=0; i<(short)inFileHeader.width; i++ ){ | |
sealRow[i].sealNum = NOSEAL; | |
sealRow[i].bitNum = 0; | |
} | |
for( j=0; j<(short)inFileHeader.height; j++ ){ // Clear the sealspace file | |
fwrite( sealRow,sizeof(sealSpace_t),(size_t)inFileHeader.width,sealSpace ); | |
} | |
// Now that we have a place to put them, fill sealSpace with valid seals | |
// gotten from the user. Remember that the array containing the actual seal | |
// strings is the global static array <sealArray[255]> | |
numSeals = solicitSeals( sealSpace, sealSpaceLength ); | |
// Allocate some memory for all of our image manipulation to come... | |
rowIn = (BYTE *)malloc( inFileHeader.width ); | |
rowOut = (BYTE *)malloc( inFileHeader.width ); | |
// We will now go through the image and calculate the seal-warped checksums. | |
// Checksums are modulo-32, based on an iterative multiply-accumulate | |
// operation of the form cs32 <- (ran16 * (pixel>>1) ) % 0xFFFFFFFF + cs32 | |
// where cs32 is the check sum "summing" variable, pixel is the 8-bit image | |
// pixel data at address N, and ran16 is the upper 16 bits of the Nth | |
// iteration of a 32-bit linear congruential generator. The modulo 0xFFFFFFFF | |
// is obtained simply by using unsigned long integer arithmetic. | |
printf( "Measuring commuted checksums...\n" ); | |
for( j=0; j<numSeals; j++ ){ | |
checksum[j] = 0L; // Clear all of the checksums | |
urandWASeed[j] = sealArray[j].bits32 % URANDWA_MODULUS; | |
// Set seeds to values implied by seals | |
} | |
fseek( fpIn, sizeof(tgaHeader_t) + (inFileHeader.mapLength * | |
sizeof( rgbTriplet_t ) ), SEEK_SET ); | |
for( i=0; i<(short)inFileHeader.height; i++ ){ | |
fread( rowIn, (size_t)1, (size_t)inFileHeader.width, fpIn ); | |
for( j=0; j<(short)inFileHeader.width; j++ ){ | |
for( k=0; k<numSeals; k++ ){ | |
checksum[k] += (ULONG)urandWA(k) * (ULONG)(rowIn[j]>>1); | |
} | |
} | |
} | |
// Get the output image ready to go. Put a copy of the input file header at | |
// the beginning of the output file, and copy the color palette over if it | |
// is a palette-type image. | |
fseek( fpOut, 0, SEEK_SET ); // Reset output file pointer to zero | |
fwrite( &inFileHeader, sizeof( tgaHeader_t ), (size_t)1, fpOut ); | |
if( inFileHeader.imageType == PALETTE ){ | |
palette = (rgbTriplet_t *)malloc( (inFileHeader.mapLength * | |
sizeof( rgbTriplet_t ) ) ); | |
fseek( fpIn, sizeof(tgaHeader_t), SEEK_SET ); // Set input pointer | |
fread( palette, sizeof( rgbTriplet_t ), | |
(size_t)inFileHeader.mapLength, fpIn ); // Read palette | |
fseek( fpOut, sizeof(tgaHeader_t), SEEK_SET ); // Set output pointer | |
fwrite( palette, sizeof( rgbTriplet_t ), (size_t)inFileHeader.mapLength, | |
fpOut ); // Write palette | |
free( palette ); // Free this -- we don't use the palette | |
} | |
// Set the file pointers of all files to the beginning of the image data | |
fseek( fpIn, sizeof(tgaHeader_t) + (inFileHeader.mapLength * | |
sizeof( rgbTriplet_t ) ), SEEK_SET ); | |
fseek( fpOut, sizeof(tgaHeader_t) + (inFileHeader.mapLength * | |
sizeof( rgbTriplet_t ) ), SEEK_SET ); | |
fseek( sealSpace, 0, SEEK_SET ); | |
// Go through the image and embed checksums. Use the sealspace map to tell | |
// which bit of which checksum to place with each pixel... | |
printf( "Embedding checksums into image data...\n" ); | |
for( i=0; i<(short)inFileHeader.height; i++ ){ | |
fread( rowIn, (size_t)1, (size_t)inFileHeader.width, fpIn ); | |
fread( sealRow,sizeof(sealSpace_t), (size_t)inFileHeader.width,sealSpace ); | |
for( j=0; j<(short)inFileHeader.width; j++ ){ | |
if( sealRow[j].sealNum == NOSEAL ){ | |
rowOut[j] = rowIn[j]; | |
} else { | |
rowOut[j] = (BYTE)( | |
(ULONG)(rowIn[j] & 0xFE) | | |
(0x01L & (checksum[ sealRow[j].sealNum] >> sealRow[j].bitNum )) | |
); | |
} | |
} | |
fwrite( rowOut, (size_t)1, (size_t)inFileHeader.width, fpOut ); | |
} | |
free( rowIn ); | |
free( rowOut ); | |
free( sealRow ); | |
fcloseall(); | |
system( "del temp" ); | |
printf( "Execution complete.\n" ); | |
} | |
Listing Two | |
// <testseal.c> Copyright 1994 by Steve Walton | |
// This implementation measures checksums using all of the upper 7 bits of each | |
// pixel, without varying number of bits by random sequence. It does, however, | |
// ensure order dependence by multiplying sum elements pairwise with a | |
// pseudo-random sequence and accumulating a sum. The overall structure of this | |
// program is intended to roughly mirror or simulate what could be used as | |
// a hardware design. A temporary file is used to store "images" of checksum | |
// bits and walk locations. Obviously, this could be done in extended memory, | |
// but this method will work on 286-class machines with little or no RAM | |
// running without a swap manager, and is independent of image size. Up to 255 | |
// using checksum lengths up to 256 bits long are possible within the limits | |
// of this structure. The temporary disk file is roughly twice the size of the | |
// image being tested for seals. Named <temp> and placed in the launch path, it | |
// is deleted after use. When checking the image for seal checksum bits, the | |
// sealspace map is used to find them in one pass through the image; the map | |
// tells us which bit for which seal is to be forced into the pixel LSB. To | |
// reduce (apparent) code complexity and improve readability, this program is | |
// written using static global variables for file pointers, control variables, | |
// and so forth. Code-crafting could improve the structure a great deal, but | |
// this form is probably better for illustrating the underlying algorithms. | |
// All user-written functions used in this program are contained here. | |
// Targa image format is used for file I/O, primarily because it is as | |
// universal as TIFF and MUCH easier to use on a casual basis. Hopefully, the | |
// structure is semi-self-evident from the code. Written with and compiled by | |
// Microsoft QuickC for Windows v1.00. TARGA is a registered trademark of | |
// Truevision, Inc. TGA is a registered trademark of Truevision, Inc. | |
// | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <conio.h> | |
#include <process.h> | |
#include <malloc.h> | |
#include <math.h> | |
// Structures must be stored byte-aligned! Compile with switch /Zp1 (Microsoft) | |
// or equivalent. | |
typedef unsigned long ULONG; | |
typedef unsigned short USHORT; | |
typedef unsigned short BOOL; | |
typedef unsigned char BYTE; | |
// Truevision TARGA file header format | |
typedef struct { | |
BYTE idLength; // Identifies number of bytes in optional Targa Field 6 | |
BYTE colorMapType; // Type of color map (0=no color map, 1=color map used) | |
BYTE imageType; // Type of image (1=uncompress color-mapped, | |
// 2=24-bit direct, 3=monochrome) | |
USHORT firstEntry; // Index of first color map entry (usually 0) | |
USHORT mapLength; // Length of color map (number of colors) | |
BYTE entrySize; // Size of color map entry (bits) | |
USHORT xOrigin; // Horiz coord of lower-left image corner on a display | |
USHORT yOrigin; // Vert coord of lower-left image corner on a display | |
USHORT width; // Width of the image in pixels | |
USHORT height; // Height of the image in pixels | |
BYTE pixDepth; // Number of bits in each pixel location | |
BYTE imageDesc; // Alpha Channel bits or overlay bits | |
} tgaHeader_t; | |
// Truevision TARGA RGB triplet format | |
typedef struct { | |
BYTE blu; // 8-bit Blue component | |
BYTE grn; // 8-bit Green component | |
BYTE red; // 8-bit Red component | |
} rgbTriplet_t; | |
typedef struct { // per-pixel-address descriptor for keeping embedded checksum | |
bit locations | |
BYTE sealNum; // Index number of seal associated with the checksum partially | |
// embedded at this location | |
BYTE bitNum; // Bit number (0=LSB) of the checksum associated with this seal | |
} sealSpace_t; | |
typedef union { // Mechanizes pseudo-random-number generator seeds | |
ULONG bits32; | |
char asciiChar[4]; // The characters are kept for reference. | |
} seal_t; | |
#define TRUE 1 | |
#define FALSE 0 | |
#define MONO 3 | |
#define PALETTE 1 | |
#define NOSEAL 0xFF | |
// -------------- Global Variable List ------------------------------- | |
ULONG | |
checksum[256], // array of 32-bit image checksums, implied by seals | |
checksumEmbedded[256] // array of 32-bit image checksums stripped from | |
// embedded walk sequences | |
; | |
seal_t | |
sealArray[255]; // Contains the seeds for each seal | |
FILE | |
*fpIn, // Input file pointer | |
*fpOut // Output file pointer | |
; | |
char | |
inFileName[80], // Input file name string (allow 80 bytes) | |
outFileName[80] // Output file name string (allow 80 bytes) | |
; | |
//////////////////////////// | |
// F u n c t i o n s // | |
//////////////////////////// | |
//======================== u r a n d D o u b l e () =========================== | |
// Pseudo-random number generator designed to return floating-point quantities | |
// as a percentage of a passed range argument. This is the standard linear | |
// congruential generator which uses the recurrence relation i(j+1) = mod(m)[a | |
// * i(j) + c], where m is the modulus, a is the muliplier, and c is offset. | |
// The randomness of these sequences is very dependent upon a, m, and c. | |
// The value of i(0) is called the seed. | |
// | |
#define URANDDOUBLE_MULTIPLIER 2416L // Multiplier | |
#define URANDDOUBLE_OFFSET 374441L // Offset | |
#define URANDDOUBLE_MODULUS 1771875L | |
static unsigned long urandDoubleSeed = 3456L; | |
double urandDouble( double range ){ | |
urandDoubleSeed = (urandDoubleSeed * URANDDOUBLE_MULTIPLIER + | |
URANDDOUBLE_OFFSET) % URANDDOUBLE_MODULUS; | |
return( ((double)urandDoubleSeed * (range)) / (double)URANDDOUBLE_MODULUS ); | |
} | |
//========================= u r a n d W A () ================================= | |
// A pseudo-random number generator designed to return 16-bit quantities. This | |
// is an arrayed function of up to 256 outputs. This is the standard linear | |
// congruential generator which uses the recurrence relation i(j+1) = mod(m)[a | |
// * i(j) + c], where m is the modulus, a is the muliplier, and c is offset. | |
// The randomness of these sequences is very dependent upon a, m, and c. | |
// The value of i(0) is called the seed. | |
// | |
#define URANDWA_MULTIPLIER 2416L // Multiplier | |
#define URANDWA_OFFSET 374441L // Offset | |
#define URANDWA_MODULUS 1771875L | |
static unsigned long | |
urandWASeed[256]; // global static unsigned long seed | |
USHORT urandWA( short index ){ | |
urandWASeed[index] = (urandWASeed[index] * URANDWA_MULTIPLIER + | |
URANDWA_OFFSET) % URANDWA_MODULUS; | |
return( (USHORT)( (double)urandWASeed[index] * 65536.0 / | |
(double)URANDWA_MODULUS ) ); | |
} | |
//========================= s o l i c i t S e a l s () ===================== | |
// Gets up to 255 4-character sealing strings from the user and fills the file | |
// pointed to by <sealSpace> with seal# and bit# information. We are using | |
// 32-bit checksums, and the walk space is driven by urandWord() | |
short solicitSeals( FILE *sealSpace, long sealSpaceLength ){ | |
BOOL | |
sealGood = TRUE, | |
done = FALSE | |
; | |
short | |
i, // Temporary index variable | |
numSeal=0 | |
; | |
long | |
walkAddress; | |
char | |
temp | |
; | |
sealSpace_t | |
sealPix | |
; | |
seal_t | |
inSeal | |
; | |
printf( "\n---- Seal Test List Entry ----\n" ); | |
printf( "Each four characters entered will be taken as a seal. \n" ); | |
printf( "You may submit up to 255 seals for testing (indices are 0..254)\n" ); | |
printf( "If you get self-intersections, at least two seals in your list\n" ); | |
printf( "are mutually exclusive, one of which cannot be present.\n" ); | |
while( !done ){ | |
printf( "Enter seal %d (ESC to end): ", numSeal ); | |
i=0; | |
while( i < 4 ){ | |
temp = (char)getch(); | |
if( temp == 27 ){ | |
done = TRUE; | |
break; | |
} else { | |
inSeal.asciiChar[i] = temp; | |
printf( "-" ); | |
i++; | |
} | |
} | |
if( !done ){ | |
printf( "%c (checking for intersections...", 7 ); | |
// First, check the sealspace for any of these locations... | |
sealGood = TRUE; | |
urandDoubleSeed = inSeal.bits32 % URANDDOUBLE_MODULUS; | |
for( i=0; i<32; i++ ){ | |
walkAddress = (long)urandDouble( sealSpaceLength ); | |
if( walkAddress == sealSpaceLength ) walkAddress = sealSpaceLength-1; | |
fseek( sealSpace, walkAddress*sizeof(sealSpace_t), SEEK_SET ); | |
fread( &sealPix, sizeof( sealSpace_t ), 1, sealSpace ); | |
if( sealPix.sealNum != NOSEAL ){ | |
sealGood = FALSE; | |
break; | |
} | |
} | |
if( sealGood ){ | |
printf( "ok.)\n" ); | |
sealArray[numSeal].bits32 = inSeal.bits32; | |
// embed this seal into the sealspace map | |
urandDoubleSeed = inSeal.bits32 % URANDDOUBLE_MODULUS; | |
for( i=0; i<32; i++ ){ | |
walkAddress = (long)urandDouble( sealSpaceLength ); | |
if( walkAddress == sealSpaceLength ) walkAddress=sealSpaceLength-1; | |
sealPix.sealNum = (BYTE)numSeal; // Keep sealArray index in the map | |
sealPix.bitNum = (BYTE)i; // Keep bit number in the map | |
fseek( sealSpace, walkAddress*sizeof(sealSpace_t), SEEK_SET ); | |
fwrite( &sealPix, sizeof( sealSpace_t ), 1, sealSpace ); | |
} | |
numSeal++; | |
} else { | |
printf( "no. Try another.)\n" ); | |
} | |
} // End checking and embedding section | |
} | |
printf( "\nYou have submitted %d seals for testing.\n", numSeal ); | |
return( numSeal ); | |
} | |
//============================ o p e n F i l e s () ========================== | |
// Open image files. Test each file for validity and return FALSE if something | |
// is wrong. There are all sorts of clever ways to avoid using a "goto" | |
// statement, and I support most of them. This is one of the places where | |
// its use is justified to generate short, quick code. | |
BOOL openFiles( void ){ | |
tgaHeader_t *hdr; | |
// Get temporary storage for the header so we can test it for validity | |
hdr = (tgaHeader_t *)malloc( sizeof(tgaHeader_t) ); | |
if( hdr == NULL ){ | |
printf( "Your system's seriously ill! Can't allocate 18 bytes | |
of dynamic memory!" ); | |
goto bugout; | |
} | |
// OPEN THE INPUT FILE | |
printf( "Enter complete input image file name: " ); | |
scanf( "%s", &inFileName[0] ); | |
fpIn = fopen( &inFileName[0], "rb" ); | |
if( fpIn == NULL ){ | |
printf( "Problem opening file %s\n", inFileName ); | |
goto errorExitCloseFile; | |
} | |
fread( hdr, sizeof(tgaHeader_t), (size_t)1, fpIn ); | |
rewind( fpIn ); | |
if( hdr->imageType != MONO && hdr->imageType != PALETTE ){ | |
printf( "Input image is not Targa monochrome or palette." ); | |
goto errorExitCleanAll; | |
} | |
if( hdr->imageType == MONO && | |
(hdr->mapLength != 0 || hdr->colorMapType != 0 || hdr->pixDepth != 8 || | |
hdr->entrySize != 0 )){ | |
printf( "Corrupted monochrome image file." ); | |
goto errorExitCleanAll; | |
} | |
if( hdr->imageType == PALETTE && | |
(hdr->mapLength != 256 || hdr->colorMapType == 0 || | |
hdr->pixDepth != 8 || hdr->entrySize != 24 ) ){ | |
printf( "Not an appropriate 8-bit palette image file." ); | |
goto errorExitCleanAll; | |
} | |
// If we've gotten this far, it's likely that everything is OK and we can | |
// get back to business... | |
return( TRUE ); | |
errorExitCleanAll: // Error exit point | |
free( hdr ); | |
errorExitCloseFile: // Another error exit point | |
fcloseall(); | |
bugout: // Get outta here! | |
return( FALSE ); | |
} | |
//////////////////////////// | |
// m a i n () // | |
//////////////////////////// | |
//========================================================================== | |
// This program opens either an 8-bit grey or 8-bit color-mapped Targa image, | |
// reads it in row-by-row, and checks for presence of a list of embedded seals. | |
void main( void ){ | |
BYTE | |
*rowIn // Pointer to row of input image pixels | |
; | |
short | |
i,j,k, // Temporary index variables | |
numSeals // Total number of seals to check for in the image | |
; | |
long | |
sealSpaceLength // Total number of pixels in the input image. | |
; | |
FILE | |
*sealSpace // File pointer to temporary "seal space frame" image file | |
; | |
tgaHeader_t | |
inFileHeader // Will contain input file Targa header | |
; | |
sealSpace_t | |
*sealRow // Pointer to row of seal space elements | |
; | |
// Print out the program identification and default values | |
printf( "<testseal.c>\nCopyright 9/20/94 by Steve Walton\n" ); | |
if( !openFiles() ) exit(0); // Get the files from the user and open them | |
fread( &inFileHeader, sizeof(tgaHeader_t), (size_t)1, fpIn ); | |
sealSpaceLength = (long)inFileHeader.width * (long)inFileHeader.height; | |
sealSpace = fopen( "temp", "wb+" ); // Open sealspace file for random R/W | |
sealRow = (sealSpace_t *)malloc( sizeof( sealSpace_t )*inFileHeader.width); | |
printf( "Clearing sealspace...\n" ); | |
// Clear the temporary file with the seal walkspace data | |
for( i=0; i<(short)inFileHeader.width; i++ ){ | |
sealRow[i].sealNum = NOSEAL; | |
sealRow[i].bitNum = 0; | |
} | |
for( j=0; j<(short)inFileHeader.height; j++ ){ | |
fwrite( sealRow, sizeof(sealSpace_t),(size_t)inFileHeader.width,sealSpace); | |
} | |
// Now that we have a place to put them, fill sealSpace with valid seals | |
// gotten from the user. Remember that the array containing the actual seal | |
// strings is the global static array <sealArray[255]> | |
numSeals = solicitSeals( sealSpace, sealSpaceLength ); | |
// Allocate some memory for all of our image manipulation to come... | |
rowIn = (BYTE *)malloc( inFileHeader.width ); | |
//rowOut = (BYTE *)malloc( inFileHeader.width ); | |
// We will now go through the image and calculate seal-warped checksums. | |
// Checksums are modulo-32, based on an iterative multiply-accumulate | |
// operation of the form cs32 <- (ran16 * (pixel>>1) ) % 0xFFFFFFFF + cs32 | |
// where cs32 is the check sum "summing" variable, pixel is the 8-bit image | |
// pixel data at address N, and ran16 is the upper 16 bits of the Nth | |
// iteration of a 32-bit linear congruential generator. The modulo 0xFFFFFFFF | |
// is obtained simply by using unsigned long integer arithmetic. | |
printf( "Measuring checksums...\n" ); | |
for( j=0; j<numSeals; j++ ){ | |
checksum[j] = 0L; // Clear all of the checksums | |
urandWASeed[j] = sealArray[j].bits32 % URANDWA_MODULUS; | |
} | |
fseek( fpIn, sizeof(tgaHeader_t) + (inFileHeader.mapLength * | |
sizeof( rgbTriplet_t ) ), SEEK_SET ); | |
for( i=0; i<(short)inFileHeader.height; i++ ){ | |
fread( rowIn, (size_t)1, (size_t)inFileHeader.width, fpIn ); | |
for( j=0; j<(short)inFileHeader.width; j++ ){ | |
for( k=0; k<numSeals; k++ ){ | |
checksum[k] += (ULONG)urandWA(k) * (ULONG)(rowIn[j]>>1); | |
} | |
} | |
} | |
// Set the file pointers of all files to the beginning of the image data | |
fseek( fpIn, sizeof(tgaHeader_t) + (inFileHeader.mapLength * | |
sizeof( rgbTriplet_t ) ), SEEK_SET ); | |
fseek( sealSpace, 0, SEEK_SET ); | |
// go through the image and embed checksums. Use the sealspace map to tell | |
// which bit of which checksum to place with each pixel... | |
printf( "Checking for embedded checksums in image data...\n" ); | |
for( i=0; i<numSeals; i++ ) checksumEmbedded[i] = 0L; | |
for( i=0; i<(short)inFileHeader.height; i++ ){ | |
fread( rowIn, (size_t)1, (size_t)inFileHeader.width, fpIn ); | |
fread( sealRow, sizeof(sealSpace_t),(size_t)inFileHeader.width,sealSpace ); | |
for( j=0; j<(short)inFileHeader.width; j++ ){ | |
if( sealRow[j].sealNum != NOSEAL ){ | |
checksumEmbedded[sealRow[j].sealNum] |= (ULONG)( rowIn[j] & 0x01 ) | |
<< sealRow[j].bitNum; | |
} | |
} | |
} | |
for( i=0; i<numSeals; i++ ){ | |
if( checksum[i] == checksumEmbedded[i] ){ | |
printf( "#%d, %c%c%c%c, is present\n", i, | |
sealArray[i].asciiChar[0], sealArray[i].asciiChar[1], | |
sealArray[i].asciiChar[2], sealArray[i].asciiChar[3] ); | |
} else { | |
printf( "#%d, %c%c%c%c, is not present\n", i, | |
sealArray[i].asciiChar[0], sealArray[i].asciiChar[1], | |
sealArray[i].asciiChar[2], sealArray[i].asciiChar[3] ); | |
} | |
} | |
free( rowIn ); | |
free( sealRow ); | |
fcloseall(); | |
system( "del temp" ); | |
printf( "Execution complete.\n" ); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment