一、基础功能
(1)将指定的文本信息隐藏到24位bmp位图中。信息隐藏的具体实现方法为最低有效位(LSB)方法,将密文插入像素颜色值的最低有效位中,由此引发的RGB颜色值的微小变化人眼无法感知。
(2)从携密图像文件中恢复隐秘的文本信息。分析按照(1)中方法生成的携密图像,从中提取出密文的信息并输出,注意要将二进制密文还原成字符串。
二、升级功能
(1)先对待隐藏的文本信息加密,然后再将密文隐藏到24位bmp位图中。这里使用凯撒密码(密钥为3的移位密码)先将明文转换成密文后再隐藏到位图中。这样即使位图密码被截获,也不会泄露密文信息。
(2)从按照(1)中方法加密的位图中恢复隐秘的文本信息。这里先从位图文件中得到密文,然后用密钥恢复出明文信息。
三、C语言代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <stdlib.h>
/*菜单*/
void myMenu() {
printf(" * * * * * * * * * 菜 单 * * * * * * * * * * * * * * * * * *\n");
printf(" 1 直接将密文隐藏入图片中 2 直接解密图片中的密文 \n");
printf(" 3 通过移位密码加密后隐藏 4 通过移位密码解密密文 \n");
printf(" 5 退出系统 \n");
printf(" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
}
/*位图文件头*/
typedef uint16_t WORD;
typedef uint32_t DWORD;
#pragma pack(1)
typedef struct tagBITMAPFILEHEADER {
WORD bfType;//文件类型2
DWORD bfSize;//文件大小4
WORD bfReserved1;//保留字2
WORD bfReserved2;//保留字2
DWORD bfOffBits;//偏移量4
} BITMAPFILEHEADER;
#pragma pack()
/*位图信息头*/
typedef uint32_t LONG;
#pragma pack(1)
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;//长度
LONG biWidth;//宽度
LONG biHeight;//高度
WORD biPlanes;//1
WORD biBitCount;//颜色位数
DWORD biCompression;//位图是否压缩
DWORD biSizeImage;//位图大小
LONG biXPelsPerMeter;//水平分辨率
LONG biYPelsPerMeter;//垂直分辨率
DWORD biClrUsed;//颜色数量
DWORD biClrImportant;//重要颜色数
} BITMAPINFOHEADER;
#pragma pack()
/*显示文件头*/
void show_bit_map_file_header(BITMAPFILEHEADER* p)
{
printf("bfType=%04x\n", p->bfType);
printf("bfSize=%d\n", p->bfSize);
printf("bfReserved1=%d\n", p->bfReserved1);
printf("bfReserved2=%d\n", p->bfReserved2);
printf("bfOffBits=%d\n", p->bfOffBits);
}
/*显示信息头*/
void show_bit_map_info_header(BITMAPINFOHEADER* p)
{
printf("biSize=%d\n", p->biSize);
printf("biWidth=%d\n", p->biWidth);
printf("biHeight=%d\n", p->biHeight);
printf("biPlanes=%d\n", p->biPlanes);
printf("biBitCount=%d\n", p->biBitCount);
printf("biCompression=%d\n", p->biCompression);
printf("biSizeImage=%d\n", p->biSizeImage);
printf("biXPelsPerMeter=%d\n", p->biXPelsPerMeter);
printf("biYPelsPerMeter=%d\n", p->biYPelsPerMeter);
printf("biClrUsed=%d\n", p->biClrUsed);
printf("biClrImportant=%d\n", p->biClrImportant);
}
/*加密图片*/
void show_bmp(char* name1, char* name2)
{
BITMAPFILEHEADER bit_map_file_header;
BITMAPINFOHEADER bit_map_info_header;
/*将文件头和信息头存储*/
char ch = 0;
FILE* pfr = fopen(name1, "rb");
FILE* pfw = fopen(name2, "wb");
/*错误处理*/
if (NULL == pfw)
perror("open file test2.txt");
if (NULL == pfr)
perror("open file test1.txt");
/*将文件头和信息头存储*/
fread(&bit_map_file_header, sizeof(bit_map_file_header), 1, pfr);
fread(&bit_map_info_header, sizeof(bit_map_info_header), 1, pfr);
/*将文件头和信息头写入*/
fwrite(&bit_map_file_header, sizeof(bit_map_file_header), 1, pfw);
fwrite(&bit_map_info_header, sizeof(bit_map_info_header), 1, pfw);
/*提取RGB数据长度*/
int IMAGE_SIZE = bit_map_file_header.bfSize;
/*移动指针*/
fseek(pfr, 54, SEEK_SET);
fseek(pfw, 54, SEEK_SET);
/*输入密文*/
char password[100];
int pin[800];
printf("请输入要加密的信息:");
scanf("%s", password);
int p = 0;
for (int k = 0; k < strlen(password); k++)
{
int asc = password[k];
int y, a[8] = { 0,0,0,0,0,0,0,0 };
/*转换为二进制*/
for (int i = 7; asc != 0; i--)
{
y = asc % 2;
asc = asc / 2;
a[i] = y;
}
for (int j = 0; j < 8; j++)
{
pin[p] = a[j]; //printf("%d", pin[p]);
p += 1; //printf("%d ", p);
}
}
/*生成图片*/
int g = 0, q = 0;
while (!feof(pfr))
{
ch = fgetc(pfr);
if (g < p + strlen(password))
{
if (g % 9 != 0)
{
if ((ch & 0x01) && pin[q] == 0)
{
ch = ch - 1;
}
if (!(ch & 0x01) && pin[q] == 1)
{
ch = ch + 1;
}
q++;
}
g++;
}
fputc(ch, pfw);
}
fclose(pfr);
fclose(pfw);
}
/*解密图片*/
void get_bmp(char* name)
{
char ch = 0;
FILE* pfr = fopen(name, "rb");
fseek(pfr, 54, SEEK_SET);
int ans = 0;
int q = 0;
int v = 8;
printf("密码为:");
/*翻译密码*/
while (1)
{
ch = fgetc(pfr);
if (q % 9 != 0)
{
v -= 1;
ans += (ch & 0x01) * pow(2, v);
}
q += 1;
if (v == 0)
{
if ((ans >= 65 && ans <= 90) || (ans >= 97 && ans <= 122))
{
printf("%c", ans);
v = 8;
ans = 0;
}
else
break;
}
}
printf("\n");
}
/*移位密码——加密*/
void encryption1(char* name1, char* name2)
{
char C[100];
char M[100];
int K = 3, i;
//加密
printf("请输入明文M(不可输入空白串):");
scanf("%s", M);
//gets(M);
for (i = 0; M[i] != '\0'; i++)
{
if (M[i] >= 'a' && M[i] <= 'z')
{
C[i] = (M[i] - 'a' + K) % 26 + 'a';
}
else if (M[i] >= 'A' && M[i] <= 'Z')
{
C[i] = (M[i] - 'A' + K) % 26 + 'A';
}
}
C[i] = '\0';
//printf("加密后的密文是:\n%s\n", C);
BITMAPFILEHEADER bit_map_file_header;
BITMAPINFOHEADER bit_map_info_header;
/*将文件头和信息头存储*/
char ch = 0;
FILE* pfr = fopen(name1, "rb");
FILE* pfw = fopen(name2, "wb");
/*错误处理*/
if (NULL == pfw)
perror("open file test2.txt");
if (NULL == pfr)
perror("open file test1.txt");
/*将文件头和信息头存储*/
fread(&bit_map_file_header, sizeof(bit_map_file_header), 1, pfr);
fread(&bit_map_info_header, sizeof(bit_map_info_header), 1, pfr);
/*将文件头和信息头写入*/
fwrite(&bit_map_file_header, sizeof(bit_map_file_header), 1, pfw);
fwrite(&bit_map_info_header, sizeof(bit_map_info_header), 1, pfw);
/*提取RGB数据长度*/
int IMAGE_SIZE = bit_map_file_header.bfSize;
/*移动指针*/
fseek(pfr, 54, SEEK_SET);
fseek(pfw, 54, SEEK_SET);
/*输入密文*/
int pin[800];
int p = 0;
for (int k = 0; k < strlen(C); k++)
{
int asc = C[k];
int y, a[8] = { 0,0,0,0,0,0,0,0 };
/*转换为二进制*/
for (int i = 7; asc != 0; i--)
{
y = asc % 2;
asc = asc / 2;
a[i] = y;
}
for (int j = 0; j < 8; j++)
{
pin[p] = a[j]; //printf("%d", pin[p]);
p += 1; //printf("%d ", p);
}
}
/*生成图片*/
int g = 0, q = 0;
while (!feof(pfr))
{
ch = fgetc(pfr);
if (g < p + strlen(C))
{
if (g % 9 != 0)
{
if ((ch & 0x01) && pin[q] == 0)
{
ch = ch - 1;
}
if (!(ch & 0x01) && pin[q] == 1)
{
ch = ch + 1;
}
q++;
}
g++;
}
//printf("%d ", ch);
fputc(ch, pfw);
}
fclose(pfr);
fclose(pfw);
}
/*移位密码——解密*/
void encryption2(char* name1)
{
/*打开图片*/
char C[100] = {'\0'};
char ch = 0;
FILE* pfr = fopen(name1, "rb");
fseek(pfr, 54, SEEK_SET);
int ans = 0,ki = 0;
int q = 0;
int v = 8;
/*翻译密码*/
while (1)
{
ch = fgetc(pfr);
if (q % 9 != 0)
{
v -= 1;
ans += (ch & 0x01) * pow(2, v);
}
q += 1;
if (v == 0)
{
if ((ans >= 65 && ans <= 90) || (ans >= 97 && ans <= 122))
{
C[ki] = ans;
ki += 1;
v = 8;
ans = 0;
}
else
break;
}
}
char M[100];
int K = 3, i;
//解密
for (i = 0; C[i] != '\0'; i++)
{
if (C[i] >= 'a' && C[i] <= 'z')
{
M[i] = (C[i] - 'a' - K + 26) % 26 + 'a';
}
else if (C[i] >= 'A' && C[i] <= 'Z')
{
M[i] = (C[i] - 'A' - K + 26) % 26 + 'A';
}
}
M[i] = '\0';
printf("解密后的明文是:%s\n", M);
}
int main(int argc, char* argv[])
{
int num;
myMenu();
while (1)
{
printf("请输入功能编号(1-5):");
scanf("%d", &num);
switch (num)
{
case 1://直接加密
show_bmp("D:\\桌面\\网安实践2—位图信息加密\\风景位图2.bmp", "D:\\桌面\\网安实践2—位图信息加密\\600.bmp");
break;
case 2://直接解密
get_bmp("D:\\桌面\\网安实践2—位图信息加密\\600.bmp");
break;
case 3://二次加密
encryption1("D:\\桌面\\网安实践2—位图信息加密\\风景位图2.bmp", "D:\\桌面\\网安实践2—位图信息加密\\600.bmp");
break;
case 4:
encryption2("D:\\桌面\\网安实践2—位图信息加密\\600.bmp");
break;
case 5:
printf("已退出系统,感谢您的使用!");
return 0;
default:
printf("输入不正确,应该输入1-5之间的数。\n\n");
break;
}
}
system("pause");
return 0;
}