隐写术功能可以很好地处理文本,但二进制输出会出现乱码
Steganography function works fine with text but garbles binary output
我试图通过使用每个像素中每种颜色的最后 2 个 LSB(蓝色的最后 3 个)在图像中嵌入一个文件,每当我 encode/decode,文本工作正常,但是像 ELF 文件、随机数据等任何二进制数据都会混淆。这是我的隐写术和去隐写术函数:
bool steganographize(int height, int width, unsigned long long filesize, unsigned char *file, RGBTRIPLE image[height][width], bmpstatus about)
{
int f = 0; //for char access
int i = 0;
int j = 0;
for (i = 0 ; i < height; i++)
{
if (f >= filesize)
{
goto finis;
}
for (j = 0 ; j < width; j++)
{
if (f >= filesize)
{
goto finis;
}
image[i][j].rgbtRed = ((image[i][j].rgbtRed & ~0x3) | ((file[f] & 0x60) >> 5));
image[i][j].rgbtGreen = ((image[i][j].rgbtGreen & ~0x3) | ((file[f] & 0x18) >> 3));
image[i][j].rgbtBlue = ((image[i][j].rgbtBlue & ~0x7) | ((file[f] & 0x7)));
f++;
}
}
finis:
if (f == (filesize))
{
printf("%d\n", i);
printf("%d\n", j);
print_status("Embedded file into BMP");
print_status("Inserting EOF");
image[i][j].rgbtRed = 0;
image[i][j].rgbtGreen = 92;
image[i][j].rgbtBlue = 183;
image[i][j + 1].rgbtRed = 12;
image[i][j + 1].rgbtGreen = 57;
image[i][j + 1].rgbtBlue = 237;
image[i + 1][j].rgbtRed = 91;
image[i + 1][j].rgbtGreen = 34;
image[i + 1][j].rgbtBlue = 45;
return true;
}
return false;
}
bool desteganographize(int height, int width, RGBTRIPLE image[height][width], bmpstatus about, FILE* output)
{
unsigned char* buffer = calloc(height * width * 3, sizeof(unsigned char));
int i = 0;
int j = 0;
int f = 0;
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
if (image[i][j].rgbtRed == 0 && image[i][j].rgbtGreen == 92 && image[i][j].rgbtBlue == 183) {
if (image[i][j + 1].rgbtRed == 12 && image[i][j + 1].rgbtGreen == 57 && image[i][j + 1].rgbtBlue == 237
&& image[i + 1][j].rgbtRed == 91 && image[i + 1][j].rgbtGreen == 34 && image[i + 1][j].rgbtBlue == 45) {
goto finis;
}
}
unsigned char c =
((image[i][j].rgbtRed & 0x3) << 5) |
((image[i][j].rgbtGreen & 0x3) << 3 ) |
(image[i][j].rgbtBlue & 0x7);
buffer[f] = c;
f++;
}
}
finis:
fwrite(buffer, sizeof(unsigned char), f, output);
printf("%d\n", i);
printf("%d\n", j);
fclose(output);
return true;
return false;
}
这也是我的主要功能的相关部分:
int main(int argc, char** argv) {
if (strstr(argv[1], encode) != NULL) {
FILE *bmp = fopen(bitmap, "rb");
bmpstatus *result = is_valid_bmp(bmp);
if (result == NULL)
{
print_error("Bad BMP. Maybe you specified the wrong file?");
}
//Get BMP into memory
char buffer[BUFFER_LEN];
sprintf(buffer, "Found BMP of Height %d and width %d", result->height, result->width);
print_status(buffer);
cleararr(buffer);
int width = result->width;
int height = result->height;
RGBTRIPLE(*image)
[width] = calloc(height, width * sizeof(RGBTRIPLE));
if (!scanimage(height, width, bmp, image, *result))
{
print_error("Error scanning BMP into memory. Probably not enough RAM.");
}
print_status("Scanned BMP into memory");
//Scan file into memory
unsigned long long filesize = file_size(fopen(filename, "rb"));
sprintf(buffer, "Found file with %llu kilobytes", filesize / 1024);
print_status(buffer);
cleararr(buffer);
if (filesize > ((unsigned long long)width * height * 3) / 8)
{
print_error("Bitmap not big enough to hold file");
}
unsigned char *file = calloc(filesize, sizeof(unsigned char));
printf("%llu\n", filesize);
if (!scan_file(file, filesize, fopen(filename, "rb")))
{
print_error("Error scanning file into memory");
}
print_status("Scanned file into memory");
if (!steganographize(height, width, filesize, file, image, *result))
{
print_error("Error embedding file into BMP");
}
//Output manipulated BMP
sprintf(buffer, "Outputting finished BMP to %s", output);
print_status(buffer);
outputimage(height, width, fopen(output, "wb"), image, *result);
cleararr(buffer);
free(result);
free(image);
free(file);
print_success("Finished!");
return 0;
}
if (strstr(argv[1], decode)) {
bmpstatus *result = is_valid_bmp(input);
if (result == NULL)
{
print_error("Bad BMP");
}
int height = result->height;
int width = result->width;
RGBTRIPLE(*image)
[width] = calloc(height, width * sizeof(RGBTRIPLE));
char buffer[BUFFER_LEN];
sprintf(buffer, "Found a BMP with height %d and width %d", height, width);
print_status(buffer);
cleararr(buffer);
if (!scanimage(height, width, input, image, *result))
{
print_error("Cannot scan BMP into memory. Not enough RAM, maybe?");
}
print_status("Scanned BMP into memory");
char tmpname[16] = "/tmp/tmp.XXXXXX";
mkstemp(tmpname);
print_status("Made temporary file");
FILE* finish = fopen(tmpname, "wb");
if (!desteganographize(height, width, image, *result, finish)) {
print_error("Could not extract file.");
}
free(result);
free(image);
return 0;
}
}
这不是最优雅的方式,但似乎可以完成工作(至少对于文本而言)。 bmpstatus 是一个具有 bmp 高度和宽度的结构,filesize 具有输入数据的大小,RGBTRIPLE 是一个具有 3 个元素的结构,红绿蓝。我已经验证了这两个工作。 scanimage 获取 BMP 并将其放入 RGBTRIPLE 矩阵中,scan_file 获取文件指针并将数据扫描到 unsigned char 数组中。所有这些工作,所以我假设它与隐写术功能本身有关。
事实证明,我只从每个字符中读取 7 位,而不是 8 位。一旦我在红色组件中将 0x60 替换为 0xe0 并将 0x3 替换为 0x7,它就起作用了。
我试图通过使用每个像素中每种颜色的最后 2 个 LSB(蓝色的最后 3 个)在图像中嵌入一个文件,每当我 encode/decode,文本工作正常,但是像 ELF 文件、随机数据等任何二进制数据都会混淆。这是我的隐写术和去隐写术函数:
bool steganographize(int height, int width, unsigned long long filesize, unsigned char *file, RGBTRIPLE image[height][width], bmpstatus about)
{
int f = 0; //for char access
int i = 0;
int j = 0;
for (i = 0 ; i < height; i++)
{
if (f >= filesize)
{
goto finis;
}
for (j = 0 ; j < width; j++)
{
if (f >= filesize)
{
goto finis;
}
image[i][j].rgbtRed = ((image[i][j].rgbtRed & ~0x3) | ((file[f] & 0x60) >> 5));
image[i][j].rgbtGreen = ((image[i][j].rgbtGreen & ~0x3) | ((file[f] & 0x18) >> 3));
image[i][j].rgbtBlue = ((image[i][j].rgbtBlue & ~0x7) | ((file[f] & 0x7)));
f++;
}
}
finis:
if (f == (filesize))
{
printf("%d\n", i);
printf("%d\n", j);
print_status("Embedded file into BMP");
print_status("Inserting EOF");
image[i][j].rgbtRed = 0;
image[i][j].rgbtGreen = 92;
image[i][j].rgbtBlue = 183;
image[i][j + 1].rgbtRed = 12;
image[i][j + 1].rgbtGreen = 57;
image[i][j + 1].rgbtBlue = 237;
image[i + 1][j].rgbtRed = 91;
image[i + 1][j].rgbtGreen = 34;
image[i + 1][j].rgbtBlue = 45;
return true;
}
return false;
}
bool desteganographize(int height, int width, RGBTRIPLE image[height][width], bmpstatus about, FILE* output)
{
unsigned char* buffer = calloc(height * width * 3, sizeof(unsigned char));
int i = 0;
int j = 0;
int f = 0;
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
if (image[i][j].rgbtRed == 0 && image[i][j].rgbtGreen == 92 && image[i][j].rgbtBlue == 183) {
if (image[i][j + 1].rgbtRed == 12 && image[i][j + 1].rgbtGreen == 57 && image[i][j + 1].rgbtBlue == 237
&& image[i + 1][j].rgbtRed == 91 && image[i + 1][j].rgbtGreen == 34 && image[i + 1][j].rgbtBlue == 45) {
goto finis;
}
}
unsigned char c =
((image[i][j].rgbtRed & 0x3) << 5) |
((image[i][j].rgbtGreen & 0x3) << 3 ) |
(image[i][j].rgbtBlue & 0x7);
buffer[f] = c;
f++;
}
}
finis:
fwrite(buffer, sizeof(unsigned char), f, output);
printf("%d\n", i);
printf("%d\n", j);
fclose(output);
return true;
return false;
}
这也是我的主要功能的相关部分:
int main(int argc, char** argv) {
if (strstr(argv[1], encode) != NULL) {
FILE *bmp = fopen(bitmap, "rb");
bmpstatus *result = is_valid_bmp(bmp);
if (result == NULL)
{
print_error("Bad BMP. Maybe you specified the wrong file?");
}
//Get BMP into memory
char buffer[BUFFER_LEN];
sprintf(buffer, "Found BMP of Height %d and width %d", result->height, result->width);
print_status(buffer);
cleararr(buffer);
int width = result->width;
int height = result->height;
RGBTRIPLE(*image)
[width] = calloc(height, width * sizeof(RGBTRIPLE));
if (!scanimage(height, width, bmp, image, *result))
{
print_error("Error scanning BMP into memory. Probably not enough RAM.");
}
print_status("Scanned BMP into memory");
//Scan file into memory
unsigned long long filesize = file_size(fopen(filename, "rb"));
sprintf(buffer, "Found file with %llu kilobytes", filesize / 1024);
print_status(buffer);
cleararr(buffer);
if (filesize > ((unsigned long long)width * height * 3) / 8)
{
print_error("Bitmap not big enough to hold file");
}
unsigned char *file = calloc(filesize, sizeof(unsigned char));
printf("%llu\n", filesize);
if (!scan_file(file, filesize, fopen(filename, "rb")))
{
print_error("Error scanning file into memory");
}
print_status("Scanned file into memory");
if (!steganographize(height, width, filesize, file, image, *result))
{
print_error("Error embedding file into BMP");
}
//Output manipulated BMP
sprintf(buffer, "Outputting finished BMP to %s", output);
print_status(buffer);
outputimage(height, width, fopen(output, "wb"), image, *result);
cleararr(buffer);
free(result);
free(image);
free(file);
print_success("Finished!");
return 0;
}
if (strstr(argv[1], decode)) {
bmpstatus *result = is_valid_bmp(input);
if (result == NULL)
{
print_error("Bad BMP");
}
int height = result->height;
int width = result->width;
RGBTRIPLE(*image)
[width] = calloc(height, width * sizeof(RGBTRIPLE));
char buffer[BUFFER_LEN];
sprintf(buffer, "Found a BMP with height %d and width %d", height, width);
print_status(buffer);
cleararr(buffer);
if (!scanimage(height, width, input, image, *result))
{
print_error("Cannot scan BMP into memory. Not enough RAM, maybe?");
}
print_status("Scanned BMP into memory");
char tmpname[16] = "/tmp/tmp.XXXXXX";
mkstemp(tmpname);
print_status("Made temporary file");
FILE* finish = fopen(tmpname, "wb");
if (!desteganographize(height, width, image, *result, finish)) {
print_error("Could not extract file.");
}
free(result);
free(image);
return 0;
}
}
这不是最优雅的方式,但似乎可以完成工作(至少对于文本而言)。 bmpstatus 是一个具有 bmp 高度和宽度的结构,filesize 具有输入数据的大小,RGBTRIPLE 是一个具有 3 个元素的结构,红绿蓝。我已经验证了这两个工作。 scanimage 获取 BMP 并将其放入 RGBTRIPLE 矩阵中,scan_file 获取文件指针并将数据扫描到 unsigned char 数组中。所有这些工作,所以我假设它与隐写术功能本身有关。
事实证明,我只从每个字符中读取 7 位,而不是 8 位。一旦我在红色组件中将 0x60 替换为 0xe0 并将 0x3 替换为 0x7,它就起作用了。