Steganography: Hiding Information in Plain Sight

Sometimes the best form of encryption is to avoid the challenge to would-be decryptors.


November 01, 1998
URL:http://www.drdobbs.com/steganography-hiding-information-in-plai/184403575

November 1998/Steganography: Hiding Information in Plain Sight/Figure 1

Figure 1: Source code to hide a watermark in an image

/* file bhidet.c */

#include "cips.h"

main(argc, argv)
   int argc;
   char *argv[];
{
   char  image_name[80], water_name[80];
   int   i, j;
   short factor;
   short **the_image, **out_image;
   struct   tiff_header_struct image_header1;
   struct   tiff_header_struct image_header2;

   ...

   /* code to interpret the command line - not shown */

   ...
   

   read_tiff_header(image_name, &image_header1);
   read_tiff_header(water_name, &image_header2);

   ...

   /* code to check that the two images are the same size -
      not shown */

   ...
   
   /* Allocate the two image arrays. */

   the_image =
      malloc(image_header1.image_length * sizeof(short  *));
   for(i=0; i<image_header1.image_length; i++){
      the_image[i] =
         malloc(image_header1.image_width * sizeof(short ));
      if(the_image[i] == '\0'){
         printf("\n\tmalloc of the_image[%d] failed", i);
         exit(0);
      }  /* ends if */
   }  /* ends loop over i */

   out_image =
      malloc(image_header2.image_length * sizeof(short  *));
   for(i=0; i<image_header2.image_length; i++){
      out_image[i] =
         malloc(image_header2.image_width * sizeof(short ));
      if(out_image[i] == '\0'){
         printf("\n\tmalloc of out_image[%d] failed", i);
         exit(0);
      }  /* ends if */
   }  /* ends loop over i */


   /* Read the images; add the factor to the image per the
      watermark image; write the resulting image */

   bread_tiff_image(image_name, the_image);
   bread_tiff_image(water_name, out_image);

   for(i=0; i<image_header1.image_length; i++){
      for(j=0; j<image_header1.image_width; j++){
         if(out_image[i][j] != 0){
            the_image[i][j] = the_image[i][j] + factor;
            if(the_image[i][j] > GRAY_LEVELS)
               the_image[i][j] = GRAY_LEVELS;
         }  /* ends if */

      } /* ends loop over j */
   }  /* ends loop over i */

   bwrite_tiff_image(image_name, the_image);

   free_image_array(the_image, image_header1.image_length);
   free_image_array(out_image, image_header2.image_length);

}  /* ends main  */


...

    /***********************************************
    *
    *  file bsub.c
    *
    *************************************************/

#include "cips.h"

main(argc, argv)
   int argc;
   char *argv[];
{
   char  min_name[80], sub_name[80];
   int   i, j;
   short **the_image, **out_image;
   struct   tiff_header_struct image_header1;
   struct   tiff_header_struct image_header2;

   ...
   
   /* code to read interpret the command line - not shown */

   ...

   read_tiff_header(min_name, &image_header1); /* minuend image */
   read_tiff_header(sub_name, &image_header2); /* subtrahend */

   ...

   /* code to ensure image files are same size - not shown */

   ...

   /*  Allocate the two image arrays. */

   the_image =
      malloc(image_header1.image_length * sizeof(short  *));
   for(i=0; i<image_header1.image_length; i++){
      the_image[i] =
         malloc(image_header1.image_width * sizeof(short ));
      if(the_image[i] == '\0'){
         printf("\n\tmalloc of the_image[%d] failed", i);
         exit(0);
      }  /* ends if */
   }  /* ends loop over i */

   out_image =
      malloc(image_header2.image_length * sizeof(short  *));
   for(i=0; i<image_header2.image_length; i++){
      out_image[i] =
         malloc(image_header2.image_width * sizeof(short ));
      if(out_image[i] == '\0'){
         printf("\n\tmalloc of out_image[%d] failed", i);
         exit(0);
      }  /* ends if */
   }  /* ends loop over i */

   /* Read the images; subtract one image from the other; write the
      resulting image */

   bread_tiff_image(min_name, the_image);
   bread_tiff_image(sub_name, out_image);

   for(i=0; i<image_header1.image_length; i++){
      for(j=0; j<image_header1.image_width; j++){
         the_image[i][j] = the_image[i][j] - out_image[i][j];
         if(the_image[i][j] < 0)
            the_image[i][j] = 0;
      } /* ends loop over j */
   }  /* ends loop over i */

   bwrite_tiff_image(min_name, the_image);

   free_image_array(the_image, image_header1.image_length);
   free_image_array(out_image, image_header2.image_length);

}  /* ends main  */


/* End of File */
November 1998/Steganography: Hiding Information in Plain Sight/Figure 2

Figure 2: Hiding three pixels from the column of a message image in three rows of the cover image (pixel values shown in decimal)

November 1998/Steganography: Hiding Information in Plain Sight/Figure 3

Figure 3: Source code to hide a message image in a cover image

/* This routine hides the message image in the cover image. Loop
   through the pixels in the message image and call hide_pixels
   for every pixel in the message image */

int hide_image(cover_image_name,
               message_image_name,
               cover_image,
               message_image,
               mlength,
               mwidth,
               clength,
               cwidth,
               lsb,
               n)
   char  cover_image_name[],
         message_image_name[];
   int   lsb, n;
   long  clength, cwidth, mlength, mwidth;
   short **cover_image, 
         **message_image;
{
   char response[80];
   int h_counter;

   bread_tiff_image(cover_image_name, cover_image);
   bread_tiff_image(message_image_name, message_image);

   for(h_counter=0; h_counter<mwidth; h_counter++){
      hide_pixels(cover_image,
                  message_image,
                  h_counter,
                  h_counter*n,
                  lsb,
                  n,
                  mlength);
   }  /* ends loop over h_counter */

   bwrite_tiff_image(cover_image_name, cover_image);

}  /* ends hide_image */

/* This routine hides the bits in a pixel from the message image
   into the least significant bit of eight pixels in the cover
   image.

   Do this operation for every row of pixels in the message and
   cover images */

int hide_pixels(cover_image, 
                message_image,
                mie, 
                cie,
                lsb,
                n,
                mlength)
   int   cie, lsb, mie, n;
   long  mlength;
   short **cover_image, 
         **message_image;
{
   char result,
        new_message,
        sample;

   char mask1[EIGHT] =  {0x01,  /* 0000 0001 */
                         0x02,  /* 0000 0010 */
                         0x04,  /* 0000 0100 */
                         0x08,  /* 0000 1000 */
                         0x10,  /* 0001 0000 */
                         0x20,  /* 0010 0000 */
                         0x40,  /* 0100 0000 */
                         0x80}; /* 1000 0000 */


   char mask2[EIGHT] = {0xFE,  /* 1111 1110 */
                        0xFD,  /* 1111 1101 */
                        0xFB,  /* 1111 1011 */
                        0xF7,  /* 1111 0111 */
                        0xEF,  /* 1110 1111 */
                        0xDF,  /* 1101 1111 */
                        0xBF,  /* 1011 1111 */
                        0x7F}; /* 0111 1111 */


   int c_counter,
       i, j;

   for(i=0; i<mlength; i++){
      c_counter = 0;
      sample    = message_image[i][mie];

      for(j=n-1; j>-1; j--){

         /* Find out if the jth bit is a 1 or 0. If it is non-zero,
            set the LSB of the message image's pixel. Else, clear
            that LSB. */

         new_message = cover_image[i][cie+c_counter];
         result      = sample & mask1[j];

         if(result != 0x00){ /* set lsb */
            if(lsb)
               new_message = new_message | mask1[0];
            else
               new_message = new_message | mask1[EIGHT];
         } /* ends if set lsb */

         else{ /* clear lsb */
            if(lsb)
               new_message = new_message & mask2[0];
            else
               new_message = new_message & mask2[EIGHT];
         }  /* ends if clear lsb */

         cover_image[i][cie+c_counter] = new_message;
         c_counter++;

      }  /* ends loop over j */
   }  /* ends loop over i */
}  /* ends hide_pixels */


/* End of File */
November 1998/Steganography: Hiding Information in Plain Sight/Figure 4

Figure 4: Source code to "unhide" a message image from a cover image

/* This routine pulls the message image out of the cover image
   (the opposite of the cover_image routine) */

int uncover_image(cover_image_name,
                  message_image_name,
                  cover_image,
                  message_image,
                  mlength,
                  mwidth,
                  clength,
                  cwidth,
                  lsb,
                  n)
   char  cover_image_name[],
         message_image_name[];
   int   lsb, n;
   long  clength, cwidth, mlength, mwidth;
   short **cover_image, 
         **message_image;
{
   int h_counter;

   bread_tiff_image(cover_image_name, cover_image);

   for(h_counter=0; h_counter<mwidth; h_counter++){
      uncover_pixels(cover_image, 
                     message_image,
                     h_counter,
                     h_counter*n,
                     lsb,
                     n,
                     mlength);
   }  /* ends loop over h_counter */

   bwrite_tiff_image(message_image_name, message_image);

}  /* ends uncover_image */

/* This routine pulls the eight bits that make up a pixel in the
   message image out of the LSB of the eight pixels in the cover
   image. It is the opposite of the cover_pixels routine. */

int uncover_pixels(cover_image, 
                message_image,
                mie, 
                cie,
                lsb,
                n,
                mlength)
   int   cie, lsb, mie, n;
   long  mlength;
   short **cover_image, 
         **message_image;
{
   char result,
        new_message,
        sample;

   char mask1[EIGHT] =  
                        {0x80,  /* 1000 0000 */
                         0x40,  /* 0100 0000 */
                         0x20,  /* 0010 0000 */
                         0x10,  /* 0001 0000 */
                         0x08,  /* 0000 1000 */
                         0x04,  /* 0000 0100 */
                         0x02,  /* 0000 0010 */
                         0x01}; /* 0000 0001 */

   int c, c_counter, i, j;

   /* If a pixel in the cover image is odd, its lsb has been set,
      so the corresponding bit in the message image should be
      set */

   for(i=0; i<mlength; i++){
      c = n-1;
      new_message = 0x00;
      for(j=0; j<n; j++){
         if(is_odd(cover_image[i][cie+j])){
            /* set bit c */
            if(lsb)
               new_message = new_message | mask1[j];
            else
               new_message = new_message | mask1[c];
         }  /* ends if is_odd */
         c--;
      }  /* ends loop over j */
      message_image[i][mie] = new_message;
   }  /* ends loop over i */
}  /* ends uncover_pixels */

/* is_odd returns 1 if argument is odd, 0 if even */

int is_odd(number)
   short number;
{
   int result = 0;
   result     = number % 2;
   return(result);
}  /* ends is_odd */


/* End of File */
November 1998/Steganography: Hiding Information in Plain Sight/Image 1

Image 1: The original boy image

November 1998/Steganography: Hiding Information in Plain Sight/Image 2

Image 2: The watermark image

November 1998/Steganography: Hiding Information in Plain Sight/Image 3

Image 3: Overlaying the watermark on the boy image

November 1998/Steganography: Hiding Information in Plain Sight/Image 4

Image 4: Hiding the watermark on the boy image

November 1998/Steganography: Hiding Information in Plain Sight/Image 5

Image 5: The message image

November 1998/Steganography: Hiding Information in Plain Sight/Image 6

Image 6: The cover image

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.