C中的隐写术
Posted
技术标签:
【中文标题】C中的隐写术【英文标题】:Steganography in C 【发布时间】:2013-03-17 02:30:00 【问题描述】:尝试对 PPM 图像进行基本的隐写术。
我已经完成了基本算法。读入文件,查看header以P6开头,获取图片宽高,像素数据。
我一共需要四个方法:ReadPPM、WritePPM、WriteMsg和ReadMsg。
我已经关闭了 ReadImg 和 WriteImg 方法,但我卡住的地方是我的 WriteMsg 方法。这是基本的隐写术,只是将字符串的每一位写入每个字节的最后一位。假设前 8 个字节包含被隐藏字符串的大小,然后每个字节开始隐藏消息。
我的想法是创建一个庞大的数组,其中包含字符串大小的二进制代码,然后是字符串本身的二进制代码。我只是想弄清楚如何获取该数组并将其添加到图像中的每个字节。
非常感谢任何帮助。这是我当前的代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct
unsigned char red,green,blue;
PPMPixel;
typedef struct
int x, y;
PPMPixel *data;
PPMImage;
#define CREATOR "RPFELGUEIRAS"
#define RGB_COMPONENT_COLOR 255
static PPMImage *readPPM(const char *filename)
char buff[16];
PPMImage *img;
FILE *fp;
int c, rgb_comp_color;
//open PPM file for reading
fp = fopen(filename, "rb");
if (!fp)
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
//read image format
if (!fgets(buff, sizeof(buff), fp))
perror(filename);
exit(1);
//check the image format
if (buff[0] != 'P' || buff[1] != '6')
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(1);
//alloc memory form image
img = (PPMImage *)malloc(sizeof(PPMImage));
if (!img)
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
//check for comments
c = getc(fp);
while (c == '#')
while (getc(fp) != '\n') ;
c = getc(fp);
ungetc(c, fp);
//read image size information
if (fscanf(fp, "%d %d", &img->x, &img->y) != 2)
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);
//read rgb component
if (fscanf(fp, "%d", &rgb_comp_color) != 1)
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
//check rgb component depth
if (rgb_comp_color!= RGB_COMPONENT_COLOR)
fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
exit(1);
while (fgetc(fp) != '\n') ;
//memory allocation for pixel data
img->data = (PPMPixel*)malloc(img->x * img->y * sizeof(PPMPixel));
if (!img)
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
//read pixel data from file
if (fread(img->data, 3 * img->x, img->y, fp) != img->y)
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);
fclose(fp);
return img;
void writePPM(const char *filename, PPMImage *img)
FILE *fp;
//open file for output
fp = fopen(filename, "wb");
if (!fp)
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);
//write the header file
//image format
fprintf(fp, "P6\n");
//comments
fprintf(fp, "# Created by %s\n",CREATOR);
//image size
fprintf(fp, "%d %d\n",img->x,img->y);
// rgb component depth
fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);
// pixel data
fwrite(img->data, 3 * img->x, img->y, fp);
fclose(fp);
void writeMsg(PPMImage *img, char *s)
int i;
int len;
len = sizeof(s);
if (img)
j = 0;
for (i=0; i < img->x * img->y; i++)
while(j < 8)
if(len & 0x80)
img->data[i].red= img->data[i].red | 0x01;
else
img->data[i].red= img->data[i].red & 0xFE;
len=len << 1;
j++;
if (len & 0x80)
img->data[i].green= img->data[i].green | 0x01;
else
img->data[i].green= img->data[i].green & 0xFE;
len = len << 1;
j++;
if (len & 0x80)
img->data[i].blue= img->data[i].blue | 0x01;
else
img->data[i].blue= img->data[i].blue & 0xFE;
j++;
【问题讨论】:
您的代码格式基本没问题...除了您真正需要帮助的功能!请修复它。它是完全不可读的。 您需要两个周期:一个按 len,另一个按每个字符的位,仅在第二个周期内写入数据,如 @Patashu 所说或以相反的顺序 (byte << i & 0x80
)。不要滚动长度可变!
len = sizeof(s)
将返回指针的大小。如果您想要字符串的长度,请使用strlen()
。
【参考方案1】:
要从一个字节中提取一个位,请执行以下操作:
bit(i) = byte >> i & 0x1
这会将字节的位向右移动 i 次,然后将 and
s 与 0000 0001 一起移动(这样除了最低位之外的所有位都归零,最低位为 0 表示 0,1 表示 1)。
您可以对 16 位短、32 位整数、64 位长……甚至对字符串的 char
s 执行类似操作。您可以使用 sizeof(char) 查看一个 char 中有多少字节。
但当然,您将拥有不止一个 char(或 long 或 int 或...)来获得额外的位。决定从哪个元素中增加一点:
如果您想要i
th 位且元素为x
位宽,则从元素[i/x]
获取i%x
位
现在您有了这个位,要将其放在一个字节(或 int 或 char 或...)内,请执行以下操作:
隐写术字节 = 原始字节&(~0x1) + 位
这意味着,你取数字 ... 0000 0001,反转它的位,所以它是 ... 1111 1110,and
它与原始字节一样,所以它的所有位都被保留,除了最低的,然后只是添加你的一点。
【讨论】:
以上是关于C中的隐写术的主要内容,如果未能解决你的问题,请参考以下文章