Skip to content

Instantly share code, notes, and snippets.

@sbeckeriv
Created March 16, 2016 03:11
Show Gist options
  • Save sbeckeriv/0ff5100f464e88a9caa2 to your computer and use it in GitHub Desktop.
Save sbeckeriv/0ff5100f464e88a9caa2 to your computer and use it in GitHub Desktop.
// _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