Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

C Programming You are to write programs in C, to find and hide the steganographi

ID: 3697380 • Letter: C

Question

C Programming

You are to write programs in C, to find and hide the steganographic files

Here’s how we did it. We have two files:

the mask image (left, color/grayscale)

the hidden file (any format, but I suggest using a text file)

The method for hiding data in an existing image is rather simple. A standard grayscale image is made up of a 2-dimensional array of pixels. Each pixel is just an 8-bit unsigned char (a number between 0 and 255). 8 bits is usually enough to encode most information for a grayscale image. However, while your eye can probably tell the difference between a pixel value of 5 and a pixel value of 200, you probably will not notice a small difference (say the difference between 200 and 201). We can take advantage of this to hide information that a computer can detect but a person could not.

So, if we start with an 8-bit pixel, we can throw out the least significant bit, the one that distinguishes the value of 200 from 201. The binary value of 200 is: 11100010 and 201 is: 11100011.If we just toss out whatever value is in that last bit, we can hide a single bit from the file we want to hide. (like 1 if the hidden bit should be a 1, and 0 if the hidden bit should be a 0).

More specifically, you need to:

--Write a program to hide a file inside of another image

--allocate memory for a properly-sized multi-dimensional array

--for each pixel in the hidden image, encode that information along with the mask image

--write the new image to a file

--Write a program to unmask the hidden file from an encoded image and save it as a decoded file

--for each pixel in the encoded image, pull out the least significant bit and use those bits to build bytes

--write the bytes to the decoded file

Your goal (for the encode portion): to write a program that will:

--read three command-line arguments, the first is the image we wish to hide a file in, the second is the filename of the file we wish to hide, the third is the filename that we will write the hidden image to.

--copy the original image to an array

--create new pgm file to hold changed image

--allocate memory for the new image data

--start at the mask image’s 0,0 pixel

--for each bit in the hidden file

--drop the least significant bit from the mask image current pixel value

--add a 1 to that pixel value if the corresponding hidden file bit is a 1

--add a 0 (or don’t) to that pixel value if the corresponding hidden file bit should be a 0

--move to the next pixel in the image (the next column in the image, or the next row’s 0th column if at the max column has been reached)

--write an EOF character in the next 8 image pixels

--save the array to a file using the pgm image format we’ve been using for the prior projects

Your goal (for the decode portion): to write a program that will:

--read two command-line arguments; take the first command-line argument which is the filename of an image (we will provide two pgm images to test with)

--read that image from the provided filename to an array

--open the decoded file with the second command-line argument as the filename

--for each pixel in the imageif the last bit is zero

--make the next corresponding bit in the hidden file a 0

--if the last bit is one

--make the next corresponding bit in the hidden file a 1

--write each decoded byte to the decoded file

--If you recall from before, to do this you need to:

Name your files encode.c and decode.c

*FOR EXTRA CREDIT*

Challenge 1:

--For encode.c, test the files beforehand to make sure that every bit of the code file can fit into the mask image. Save this challenge as encode_challenge.c

Challenge 2:

--Create functions:

--One that takes a filename as an argument, and reads a PGM image from a file and return a dynamically allocated 2­D array that stores the image

--One that takes a filename, a dynamically allocated 2­D array, and image dimensions as arguments and writes the image to a file

--Save those functions in a separate filename, image.c. Put prototypes for those functions in a header file image.h, and use those files in a revised version of your program,

encode_challenge2.c

and decode_challenge2.c

Explanation / Answer

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#define BUF_LEN 256

void usage(char*);

int main(int argc, char **argv) {

int c, len, msgChar, i,j;

FILE *fpIn, *fpOut;

char *p;

char line[BUF_LEN];

char buf[BUF_LEN];

if (argc != 3) {

usage(argv[0]);

printf("Must have an input file and an output file as command line arguments");

}

if ((fpIn = fopen(argv[1], "r")) == NULL) {

printf("Error opening file %s for reading. ", argv[1]);

return 1;

}

if ((fpOut = fopen(argv[2], "w")) == NULL) {

printf("Error opening file %s for writing. ", argv[2]);

return 1;

}

printf("Please enter the length of your message ");

scanf("%u",&len);

printf("Please enter the message you want to hide ");

if (fgets(buf, sizeof(buf), stdin) != NULL)

{

if ((p = strchr(buf, ' ')) != NULL)

*p = '';

}

while (!feof(fpIn))

{

if (fgets(line, BUF_LEN, fpIn) != NULL) {

fprintf(fpOut, "%s", line);

if (line[0] != 'P' && line[1] != '6'){

printf("not a properly formatted .ppm file ");

return -1;

}

else if (fgets(line, BUF_LEN, fpIn) != NULL)

{

fprintf(fpOut, "%s", line);

while (line[0] == '#' && (fgets(line, BUF_LEN, fpIn) != NULL)){

printf("reading comments ");

fprintf(fpOut, "%s", line);

}

}

}

if (fgets(line, BUF_LEN, fpIn) != NULL){

fprintf(fpOut, "%s", line);

}

if (fgets(line, BUF_LEN, fpIn) != NULL){

fprintf(fpOut, "%s", line);

}

/* at pixel data, write length of message first, then message */

msgChar = len;

for (j = 0; j < 8; j++){

c = fgetc(fpIn); /* get next char of input stream */

unsigned int temp = (msgChar >> j) & 1;

if (c & 1 && temp == 0)

{

c = c - 1;

fprintf(fpOut, "%c", c);

}

else

{

c = c | temp;

fprintf(fpOut, "%c", c);

}

}

for (i = 0; i < len; i++){

msgChar = buf[i];

for (j = 0; j < 8; j++){

c = fgetc(fpIn); /* get next char of input stream */

unsigned int temp = (msgChar >> j) & 1;

if (c & 1 && temp == 0)

{

c = c - 1;

fprintf(fpOut, "%c", c);

}

else

{

c = c | temp;

fprintf(fpOut, "%c", c);

}

}

}

}

fclose(fpIn);

fclose(fpOut);

/* test read message */

fpIn = fopen(argv[2], "r");

while (!feof(fpIn))

{

if (fgets(line, BUF_LEN, fpIn) != NULL) {

if (line[0] != 'P' && line[1] != '6'){

printf("not a properly formatted .ppm file ");

return -1;

}

else if (fgets(line, BUF_LEN, fpIn) != NULL)

{

while (line[0] == '#' && (fgets(line, BUF_LEN, fpIn) != NULL)){

printf("reading comments ");

}

}

}

if (fgets(line, BUF_LEN, fpIn) != NULL){

printf("reading width and height");

}

if (fgets(line, BUF_LEN, fpIn) != NULL){

printf("reading color value");

}

/* at pixel data, write length of message first, then message */

msgChar = 0;

for (j = 0; j < 8; j++){

c = fgetc(fpIn); /* get next char of input stream */

int temp = c & 1;

temp = temp << (7 - j);

msgChar = msgChar & temp;

}

printf("Message length is %d", msgChar);

len = msgChar;

for (i = 0; i < len; i++){

msgChar = 0;

for (j = 0; j < 8; j++){

c = fgetc(fpIn); /* get next char of input stream */

int temp = c & 1;

temp = temp << (7 - j);

msgChar = msgChar & temp;

}

printf("%c", msgChar);

}

}

return 0;

}

void usage(char * prog_name){

printf("usage: %s filename ", prog_name);

}