隐写术-LSB算法

实验要求:
利用LSB算法将自己姓名隐藏到一张彩色图片
(R通道)中。
可以从图片中提取出隐藏的信息

实验用的是bmp文件。
bmp文件头(bmp file header):提供文件的格式、大小等信息
位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
位图数据(bitmap data):就是图像数据啦_

推荐一个软件(010 Editor),可以清楚的看到文件的二进制格式


软件介绍

bmp文件头

可以看到偏移量为54个字节


每个像素的信息

所以可以用c++打开这个二进制文件,然后将字符串转化为二进制,最后添加到R通道的最后一位。

思路简单,但是代码稍微复杂一点
代码如下:
头文件:

#pragma once
#include <windows.h>
#define  _CRT_SECURE_NO_WARNINGS
using namespace std;
class HideBmp
{
public:
    HideBmp(char* hstr);
    ~HideBmp();
    bool GetBmp(char* bmp);
    bool hidestring();
    bool showstring();
    int strtobin(char* hidestr);

private:
    BITMAPFILEHEADER *bmfh;//bmp文件信息
    char* hidestr;//需要隐藏的字符串
    LPBYTE pBuf;    //存储bmp文件
    DWORD BmpSize;  //bmp文件的大小
    BYTE* bin_str;  //字符串的二进制形式
    int strsize;    //字符串的长度


};

zjx_lsb.cpp

#include "zjx_lsb.h"
#include <fstream>
#include <iostream>
#include <typeinfo>
#include <sstream>
HideBmp::HideBmp(char* hstr)
{
    this->hidestr = hstr;
    this->pBuf = 0;
    this->BmpSize = 0;
    this->bin_str = new BYTE[8*strlen(hidestr)];
    this->strsize=strlen(hidestr);
}
HideBmp::~HideBmp()
{

}
//将字符串转化为二进制
int HideBmp::strtobin(char* hidestr)
{
    char temp_str;
    int count = 0;
    char* temp_bin_str = new char[8];
    for (int i = 0; i < strlen(hidestr); i++)
    {
        temp_str = hidestr[i];
        for (int j = 0; j < 8; j++)
        {
            if (temp_str % 2 == 0)
            {
                temp_bin_str[j] = '0';
            }
            else
            {
                temp_bin_str[j] = '1';
            }
            temp_str /= 2;
        }
        for (int k = 0; k < 8; k++)
        {
            bin_str[count] = temp_bin_str[7 - k];
            count++;
        }


    }

    return 0;
}
/*将图片的信息全部读入pBuf中*/
bool HideBmp::GetBmp(char*  bmp)
{
    if (pBuf)
    {
        delete[] pBuf;
    }
    HANDLE hfile = CreateFileA(bmp, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
    if (hfile == INVALID_HANDLE_VALUE)
    {
        return false;
    }
    BmpSize = GetFileSize(hfile,0);
    ifstream inFile(bmp, ios::in | ios::binary);
    if (!inFile.is_open()) {
        cout << "open error" << endl;
        return 0;
    }
    pBuf = new byte[BmpSize];
    inFile.read((char*)pBuf,BmpSize);
    cout << "读入图片成功" << endl;
    inFile.close();
    bmfh = (BITMAPFILEHEADER*)pBuf;
    return TRUE;
}

bool HideBmp::hidestring()
{
    strtobin(hidestr);
    string FileName = "EncodeBmp.bmp";
    LPBYTE rgbbegin = pBuf + bmfh->bfOffBits + 2;
    
    for (int i = 0, count = 0; count < 8*strsize; count++, i += 3)
    {
        bin_str[count] = (bin_str[count] | 0xFE) & 0x1;
        rgbbegin[i] = (rgbbegin[i] &0xFE)| bin_str[count];
    }
    
    cout << endl;
    cout << "***********************" << endl;
    cout << endl;
    
    ofstream outfile(FileName,ios::out|ios::binary);
    outfile.write((char*)pBuf, BmpSize);
    outfile.close();
    cout << "加密文件生成成功" << endl;
    cout << endl;
    cout << "***********************" << endl;
    return TRUE;
}
bool HideBmp::showstring()
{
    string FileName = "EncodeBmp.bmp";
    char* DeStr=new char[8*strsize];
    ifstream infile(FileName, ios::in | ios::binary);
    LPBYTE de_pBuf=new BYTE[BmpSize];
    infile.read((char*)de_pBuf, BmpSize);
    LPBYTE rgbbegin = de_pBuf + bmfh->bfOffBits + 2;
    for (int i = 0, count = 0; count < 8 * strsize; count++, i += 3)
    {
        if (rgbbegin[i] % 2 == 0)
            DeStr[count] = '0';
        else
            DeStr[count] = '1';
    }
    stringstream ss;
    int a;

    char* str = new char[8];
    char t = 0x1;
    //将解密出的二进制赋值
    for (int i = 0; i < strsize; i++)
    {
        str[i] = 0x00;
        
        for (int j = 0; j < 8; j++)
        {
            if (DeStr[i * 8 + j] == '1')
                str[i] = str[i] | (t << (7 - j));
        }
    }
    //输出解密出的字符串
    cout << endl;
    cout << "***********************" << endl;
    cout << "解密出的字符串:" << endl;
    cout << endl;
    for (int i = 0; i < strsize; i++)
    {
        cout << str[i];
    }
    cout << endl;
    cout << endl;
    cout << "***********************" << endl;
    return true;

}

main.cpp

#include"zjx_lsb.h"
#include <iostream>
int main()
{
    cout << "请输入要隐藏的字符串" << endl;
    //默认200个字符串
    char* hstr=new char[200] ;
    cin >> hstr;
    HideBmp hmp(hstr);
    hmp.GetBmp("test.bmp");
    hmp.hidestring();
    hmp.showstring();
}

运行截图如下:

image.png

可以看到这两个图片有细微的差距


原图.png
加密后的文件格式.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。