home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / mandsteg.zip / mandsteg.c < prev    next >
C/C++ Source or Header  |  1999-01-19  |  10KB  |  471 lines

  1. /*
  2.  * MandelSteg.c V1.0
  3.  * (C) Copyright Henry Hastur 1994
  4.  *
  5.  * Hides arbitrary data in a mandelbrot GIF image.
  6.  *
  7.  * May or may not be covered by US ITAR encryption export regulations, if
  8.  * in doubt, don't export it. It would be pretty stupid if it was, but
  9.  * hey, governments have done some pretty stupid things before now....
  10.  *
  11.  * This program is copyright Henry Hastur 1994, but may be freely distributed,
  12.  * modified, incorporated into other programs and used, as long as the
  13.  * copyright stays attached and you obey any relevant import or export
  14.  * restrictions on the code. No warranty is offered, and no responsibility
  15.  * is taken for any damage use of this program may cause. In other words,
  16.  * do what you want with it, but don't expect me to pay up if anything
  17.  * unexpected goes wrong - you're using it at your own risk...
  18.  */
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22.  
  23. #ifdef __IBMC__
  24. #include <string.h>
  25. #include <fcntl.h>
  26. #include <io.h>
  27. #include <process.h>
  28. #include <time.h>
  29. #endif
  30.  
  31. #ifdef DOS
  32. #include <fcntl.h>
  33. #include <io.h>
  34. #endif
  35.  
  36. #include "ext.h"
  37.  
  38. #define WRITE_PREFIX    0
  39. #define WRITE_DATA      1
  40. #define WRITE_SUFFIX    2
  41.  
  42. static  int32   w,h;
  43. static  byte    r[256],g[256],b[256];
  44. static  byte    *data = 0;
  45.  
  46. static  byte    encoding = FALSE;
  47. static  byte    same_col = TRUE;
  48. static  byte    counting = FALSE;
  49. static  byte    full_palette = FALSE;
  50. static  byte    random_pad = FALSE;
  51. static  byte    data_bit = 0x80;
  52. static  byte    write_state = WRITE_PREFIX;
  53. static  long    byte_pad = 0;
  54.  
  55. void    usage()
  56.  
  57. {
  58.     printf("Usage:\tmandelsteg [-sz w h] [-md x y w h] [-c] [-b n]\n");
  59.     printf("\t\t[-ns] [-fp] [-bp n] [-r] [-e [file]]\n\n");
  60.     printf(" Use:\n");
  61.     printf("\t-sz to specify width and height in pixels\n");
  62.     printf("\t-md to specify mandelbrot area : start (x,y) size (w,h)\n");
  63.     printf("\t-c  to count available space in the image\n");
  64.     printf("\t-b  to specify the bit number to use (default 7)\n");
  65.     printf("\t-ns to specify no storing of data in consecutive identical pixels\n");
  66.     printf("\t-fp for a full 256-colour palette rather than 128\n");
  67.     printf("\t-bp to store the data n bytes into the available space\n");
  68.     printf("\t-r to pad the data with random bytes\n");
  69.     printf("\t-e  to encode data from stdin into the image file. If no file\n");
  70.     printf("\t\tis specified, output goes to stdout.\n");
  71.  
  72.     exit (2);
  73. }
  74.  
  75. #ifdef LOW_MEM
  76. static  double  incx,incy,nx,ny,rx,ry,nx2,ny2;
  77. static  double  dw,dh,dxs,dys;
  78. static  int16   pix,opix,mpix,lpix;
  79. static  int     inc = 0;
  80. static  int     in_count = 0;
  81. static  int     lim;
  82. static  byte    last_missed = FALSE;
  83. static  byte    eof_reached = FALSE;
  84. static  long    steg_count = 0;
  85.  
  86. /* Calculate a pixel value */
  87.  
  88. int16   calc_pixel (off)
  89.  
  90. long    off;
  91.  
  92. {
  93.     register        int     z;
  94.     double  x,y;
  95.  
  96.     if (!(off % w))
  97.         opix = lpix;
  98.  
  99.     rx = (dxs + dw * (double)(off % w));
  100.     ry = (dys + dh * (double)(off / w));
  101.  
  102.     x = 0.0;
  103.     y = 0.0;
  104.  
  105.     nx2 = ny2 = 0.0;
  106.     for (z = 0 ; z <= lim; z++) {
  107.         nx = nx2-ny2+rx;
  108.         ny = x*y*2.0+ry;
  109.  
  110.         if ((nx2=nx*nx)+(ny2=ny*ny) > 4.0)
  111.             break;
  112.  
  113.         x = nx;
  114.         y = ny;
  115.     }
  116.  
  117.     if (z > lim)
  118.         pix = (int16) lim;
  119.     else
  120.         pix = (int16) z;
  121.  
  122.     mpix = pix & ~data_bit;
  123.  
  124.     if (same_col || (mpix != opix && off)) {
  125.         if (last_missed) {
  126.             last_missed = FALSE;
  127.         }
  128.         else {
  129.         if (encoding) {
  130.             if (!in_count) {
  131.                 in_count = 8;
  132.                 if (!byte_pad) {
  133.                     write_state = WRITE_DATA;
  134.                     inc = getchar();
  135.                 }
  136.  
  137.                 /* We could not generate random bytes
  138.                    when not needed, but a) one call
  139.                    per 8 pixels is probably not
  140.                    important given the amount of FP
  141.                    math involved in generating those
  142.                    pixels, and b) it may help to make
  143.                    finding a pattern in any generated
  144.                    data harder (though they'll have the
  145.                    entire palette to analyse. */
  146.  
  147.                 if (inc == EOF) {
  148.                     inc = random() & 0xFF;
  149.                     eof_reached = TRUE;
  150.                     write_state = WRITE_SUFFIX;
  151.                 }
  152.                 else if (byte_pad) {
  153.                     inc = random() & 0xFF;
  154.                     byte_pad--;
  155.                 }
  156.             }
  157.  
  158.             in_count--;
  159.             if (random_pad || write_state == WRITE_DATA) {
  160.                 pix = mpix;
  161.                 if ((inc & 0x80))
  162.                     pix = mpix | data_bit;
  163.                 inc <<= 1;
  164.             }
  165.         }
  166.         steg_count++;
  167.         }
  168.     }
  169.     else
  170.         last_missed = TRUE;
  171.  
  172.     opix = mpix;
  173.  
  174.     if (!(off % w))
  175.         lpix = mpix;
  176.  
  177.     return pix;
  178. }
  179. #endif
  180.  
  181. main(argc,argv)
  182.  
  183. int     argc;
  184. char    *argv[];
  185.  
  186. {
  187.     int     i,z;
  188.     double  x,y;
  189. #ifndef LOW_MEM
  190.     byte    pix,opix,mpix;
  191.     double  incx,incy,nx,ny,rx,ry,nx2,ny2;
  192.     double  dw,dh,dxs,dys;
  193.     int     inc = 0;
  194.     int     in_count = 0;
  195.     int     lim;
  196.     byte    last_missed = FALSE;
  197.     byte    eof_reached = FALSE;
  198.     long    steg_count = 0;
  199. #endif
  200.     int     ix,iy;
  201.     char    *output_name = NULL;
  202.     int     c;
  203.     byte    *d = NULL;
  204.  
  205.     i = 1;
  206.     opix = 0;
  207.  
  208.     /* Default size */
  209.  
  210.     w = 640l;
  211.     h = 480l;
  212.  
  213.     /* Default coordinates */
  214.  
  215.     dxs = -0.555;
  216.     dys = -0.555;
  217.     dw = 0.01;
  218.     dh = 0.01;
  219.  
  220.     /* Check arguments */
  221.  
  222.    while (i < argc && argv[i]) {
  223.         if (!strcmp(argv[i],"-h"))
  224.             usage ();
  225.         if (!strcmp(argv[i],"-e")) {
  226.             encoding = TRUE;
  227.             if ((i+1) == argc) {
  228.                 fprintf(stderr,"Outputting to stdout\n");
  229.                 output_name = NULL;
  230.                 i = argc;
  231.             }
  232.             else {
  233.                 i++;
  234.                 if (!strcmp(argv[i],"-")) {
  235.                     output_name = NULL;
  236.                 }
  237.                 else
  238.                     output_name = argv[i];
  239.             }
  240.         }
  241.         else if (!strcmp(argv[i],"-md")) {
  242.             i++;
  243.             if (i > (argc-4)) {
  244.                 fprintf(stderr,"use -md start-x start-y width height !\n");
  245.                 i = argc;
  246.             }
  247.             else {
  248.                 dxs = atof(argv[i]);
  249.                 dys = atof(argv[i+1]);
  250.                 dw = atof(argv[i+2]);
  251.                 dh = atof(argv[i+3]);
  252.  
  253.                 i+= 3;
  254.             }
  255.         }
  256.         else if (!strcmp(argv[i],"-sz")) {
  257.             i++;
  258.             if (i > (argc-2)) {
  259.                 fprintf(stderr,"use -sz width height !\n");
  260.             }
  261.             else {
  262.                 w = atol(argv[i]);
  263.                 h = atol(argv[i+1]);
  264.                 i++;
  265.             }
  266.         }
  267.         else if (!strcmp(argv[i],"-ns")) {
  268.             same_col = FALSE;
  269.         }
  270.         else if (!strcmp(argv[i],"-c")) {
  271.             counting = TRUE;
  272.         }
  273.         else if (!strcmp(argv[i],"-fp")) {
  274.             full_palette = TRUE;
  275.         }
  276.         else if (!strcmp(argv[i],"-b")) {
  277.             if (i != (argc-1)) {
  278.                 data_bit = (1 << atoi(argv[++i])) & 0xFF;
  279.                 if (!data_bit)
  280.                     data_bit = 0x80;
  281.             }
  282.         }
  283.         else if (!strcmp(argv[i],"-r")) {
  284.             random_pad = TRUE;
  285.         }
  286.         else if (!strcmp(argv[i],"-bp")) {
  287.             if (i != (argc-1)) {
  288.                 byte_pad = atol(argv[++i]);
  289.             }
  290.         }
  291.         i++;
  292.     }
  293.     /* Following needed for binary stdin/stdout on DOS */
  294.  
  295. #ifdef DOS
  296.     _fmode = O_BINARY;
  297.     setmode (fileno(stdin), O_BINARY);
  298.     setmode (fileno(stdout), O_BINARY);
  299. #endif
  300.  
  301. /* ... for OS/2 too */
  302.  
  303. #ifdef __IBMC__
  304.         _setmode(fileno(stdin),O_BINARY);
  305.         _setmode(fileno(stdout),O_BINARY);
  306. #endif
  307.  
  308.     if (w <= 0 || h <= 0) {
  309.         fprintf (stderr, "Width and height must be > 0 !\n");
  310.         exit (1);
  311.     }
  312.  
  313.     /* Calculate delta */
  314.  
  315.     dw /= (double)w;
  316.     dh /= (double)h;
  317.  
  318.     /* If we have a full palette, we'll create all 256 colours */
  319.  
  320.     if (same_col || !full_palette)
  321.         lim = 255 & ~data_bit;
  322.     else
  323.         lim = 255;
  324.  
  325.     /* I know random() isn't crypto-secure, but for our purposes it
  326.        doesn't neccesarily need to be. If you're really trying hard
  327.        to hide things, you ought to used idea_rand() from PGP or
  328.        something similar.  */
  329.  
  330. #ifdef __IBMC__
  331.         srandom(time(NULL)+getpid());
  332. #else
  333.     srandom(time(0)+getpid());
  334. #endif
  335.  
  336. #ifndef LOW_MEM
  337.     /* Allocate data buffer */
  338.  
  339.     data = (byte *)malloc (w*h);
  340.  
  341.     if (!data) {
  342.         fprintf(stderr, "Can't allocate %d bytes !\n",w*h);
  343.         exit (1);
  344.     }
  345.  
  346.     d = data;
  347. #endif
  348.  
  349.     /* Generate a random palette */
  350.  
  351.     for (i=0; i<256; i++) {
  352.         r[i] = random()&0xFF;
  353.         g[i] = random()&0xFF;
  354.         b[i] = random()&0xFF;
  355.     }
  356.  
  357.     /* If -fp not specified, cut palette down to 128 colours */
  358.  
  359.     if (!full_palette) {
  360.         int     j;
  361.  
  362.         for (i=0; i<256; i++) {
  363.             j = i & (~data_bit);
  364.  
  365.             r[j|data_bit] = r[j];
  366.             g[j|data_bit] = g[j];
  367.             b[j|data_bit] = b[j];
  368.         }
  369.     }
  370.  
  371. #ifndef LOW_MEM
  372.     ry = dys;
  373.  
  374.     for (iy = 0; iy < h; iy++) {
  375.         ry += dh;
  376.         rx = dxs;
  377.  
  378.         if (iy)
  379.             opix = data[(iy-1)*w] & ~data_bit;
  380.  
  381.         for (ix = 0; ix < w; ix++) {
  382.             rx += dw;
  383.             x = 0.0;
  384.             y = 0.0;
  385.  
  386.             nx2 = ny2 = 0.0;
  387.             for (z = 0 ; z <= lim; z++) {
  388.                 nx = nx2-ny2+rx;
  389.                 ny = x*y*2.0+ry;
  390.  
  391.                 if ((nx2=nx*nx)+(ny2=ny*ny) > 4.0)
  392.                     break;
  393.  
  394.                 x = nx;
  395.                 y = ny;
  396.             }
  397.  
  398.             if (z > lim)
  399.                 pix = (byte) lim;
  400.             else
  401.                 pix = (byte) z;
  402.  
  403.             mpix = pix & ~data_bit;
  404.  
  405.             if (same_col || (mpix != opix && (ix || iy))) {
  406.                 if (last_missed) {
  407.                     last_missed = FALSE;
  408.                 }
  409.                 else {
  410.                 if (encoding) {
  411.                     if (!in_count) {
  412.                         in_count = 8;
  413.                         if (!byte_pad) {
  414.                             inc = getchar();
  415.                             write_state = WRITE_DATA;
  416.                         }
  417.                         if (inc == EOF) {
  418.                             inc = random() & 0xFF;
  419.                             write_state = WRITE_SUFFIX;
  420.                             eof_reached = TRUE;
  421.                         }
  422.                         else if (byte_pad) {
  423.                             inc = random() & 0xFF;
  424.                             byte_pad--;
  425.                         }
  426.                     }
  427.  
  428.                     in_count--;
  429.                     if (random_pad || write_state == WRITE_DATA) {
  430.                         pix = mpix;
  431.                         if ((inc & 0x80))
  432.                             pix = mpix | data_bit;
  433.                         inc <<= 1;
  434.                     }
  435.                 }
  436.                 steg_count++;
  437.                 }
  438.             }
  439.             else
  440.                 last_missed = TRUE;
  441.  
  442.             *d++ = pix;
  443.             opix = mpix;
  444.         }
  445.     }
  446.  
  447.     if (counting) {
  448.         fprintf(stderr,"Image has space for %d bits (%d bytes)\n",
  449.             steg_count,steg_count/8l);
  450.     }
  451.  
  452.     if (encoding && !eof_reached) {
  453.         fprintf(stderr,"WARNING : INPUT DATA TRUNCATED !\n");
  454.     }
  455.  
  456.     save_gif_image(w,h,256,data,output_name,r,g,b);
  457. #else
  458.     save_gif_image(w,h,256,NULL,output_name,r,g,b);
  459.  
  460.     if (counting) {
  461.         fprintf(stderr,"Image has space for %ld bits (%ld bytes)\n",
  462.             steg_count,steg_count/8l);
  463.     }
  464.  
  465.     if (encoding && !eof_reached) {
  466.         fprintf(stderr,"WARNING : INPUT DATA TRUNCATED !\n");
  467.     }
  468. #endif
  469. }
  470.  
  471.