将保存重要信息,如银行卡密码的文本文件隐藏到ARGB8888的A通道。
bitmap.h
#ifndef BMP_H #define BMP_H #include <fstream> #include <string> #include <iostream> #define DEBUG 0 #define LOG std::cout #define HEX std::hex #define DEC std::dec #define FLAG_0 (0xFF) #define FLAG_1 (0xEE) #define FLAG_2 (0xDD) #define FLAG_3 (0xCC) #define DATA_CODE (0xCC) #define BYTE_PER_PIXEL (4) #pragma pack(push, 1) typedef struct { uint16_t bfType; // Type of bitmap, in windows, always 'BM' uint32_t bfSize; // Size of the bitmap file uint16_t bfReserved1; // reserved feild uint16_t bfReserved2; // reserved feild uint32_t bfOffBits; // the start address of the bitmap data }BMP_FILE_HEADER; typedef struct { uint32_t biSize; // size of this struct uint32_t biWidth; // image width, unit is pixel uint32_t biHeight; // image height, unit is pixel uint16_t biPlanes; // alsways 1 uint16_t biBitCount; // color depth of the image, 1, 4, 8, 16, 24 and 32 uint32_t biCompression; // compression type, 0=no compress, 1=RLE8 compress // 2=RLE4 compress, 3=pixel color mask uint32_t biSizeImage; // pixel data size of the image uint32_t biXPelsPerMeter; // H resolution, pixel per meter uint32_t biYPelsPerMeter; // V resolution, pixel per meter uint32_t biClrUsed; // color number that used, 0=all color uint32_t biClrImportant; // important color amount, 0=all color important }BMP_INFO_HEADER; #pragma pacn(pop) class Bitmap { private: BMP_FILE_HEADER m_fileHeader; BMP_INFO_HEADER m_infoHeader; std::string m_bmpPath; bool m_parseFlag; public: Bitmap(std::string path); ~Bitmap(); bool bmpParse(); uint32_t getBmpSize(); uint32_t getBmpDataAddr(); std::string getBmpPath(); uint32_t getBmpPixelNum(); }; class DataHider { private: uint8_t m_flags[4]; uint8_t m_length[4]; Bitmap m_bitmapHeader; std::string m_dataFilePath; bool isAHider(); uint32_t getFileSize(std::ifstream &in); bool readTransByte(std::fstream &file, uint8_t &val, int pos); bool writeTransByte(std::fstream &file, uint8_t val, int pos); void length2Byte(uint32_t length); uint32_t byte2Length(); public: DataHider(std::string dataPath, std::string bmpPath); ~DataHider(); bool doEncode(); bool doDecode(); }; #endif // BMP_H
bitmap.cpp
#include "bitmap.h" Bitmap::Bitmap(std::string path) : m_fileHeader(), m_infoHeader(), m_bmpPath(path), m_parseFlag(false) { } Bitmap::~Bitmap() { } bool Bitmap::bmpParse() { std::ifstream in; in.open(m_bmpPath, std::ios::binary); in.read((char *)&m_fileHeader, sizeof(m_fileHeader)); /*char * p = (char *)&m_fileHeader; for(uint32_t i=0; i<sizeof(m_fileHeader); ++i) { in.read(p, 1); LOG << HEX << (int)*p << " "; ++p; }*/ if( !in.good() ) { LOG << "read bitmap file head error! "; in.close(); return false; } in.read((char *)&m_infoHeader, sizeof(m_infoHeader)); /* LOG << "read bitmap information header! "; p = (char *)&m_infoHeader; for(uint32_t i=0; i<sizeof(m_infoHeader); ++i) { in.read(p, 1); LOG << HEX << (int)*p << " "; ++p; }*/ if( !in.good() ) { LOG << "read bitmap information header error! "; in.close(); return false; } in.close(); m_parseFlag = true; #if 1 == DEBUG LOG << "Bitmap file header:" << " bfType: " << HEX << (int)m_fileHeader.bfType << " bfSize: " << (int)m_fileHeader.bfSize << " bfReserved1: " << (int)m_fileHeader.bfReserved1 << " bfReserved2: " << (int)m_fileHeader.bfReserved2 << " bfOffBits: " << (int)m_fileHeader.bfOffBits << " Bitmap information header:" << " biSize: " << (int)m_infoHeader.biSize << DEC << " "; #endif return true; } uint32_t Bitmap::getBmpSize() { if(!m_parseFlag) { LOG << "please do bitmap parse first! "; } return m_fileHeader.bfSize; } std::string Bitmap::getBmpPath() { return m_bmpPath; } uint32_t Bitmap::getBmpDataAddr() { if(!m_parseFlag) { LOG << "please do bitmap parse first! "; } return m_fileHeader.bfOffBits; } uint32_t Bitmap::getBmpPixelNum() { return m_infoHeader.biWidth * m_infoHeader.biHeight; } DataHider::DataHider(std::string dataPath, std::string bmpPath) : m_bitmapHeader(bmpPath), m_dataFilePath(dataPath) { } DataHider::~DataHider() { } bool DataHider::isAHider() { return (m_flags[0] == FLAG_0) & (m_flags[1] == FLAG_1) & (m_flags[2] == FLAG_2) & (m_flags[3] == FLAG_3); } uint32_t DataHider::getFileSize(std::ifstream &in) { if(!in.good()) { LOG << "the data file has some error. "; return false; } uint32_t pos = in.tellg(); in.seekg(0, std::ios_base::end); uint32_t size = in.tellg(); in.seekg(pos, std::ios_base::beg); return size; } bool DataHider::readTransByte(std::fstream &file, uint8_t &val, int pos) { file.seekg(m_bitmapHeader.getBmpDataAddr()+BYTE_PER_PIXEL*pos, std::ios_base::beg); #if DEBUG == 1 LOG << "pos " << HEX << m_bitmapHeader.getBmpDataAddr()+BYTE_PER_PIXEL*pos << " "; #endif file.read((char *)&val, 1); return file.good(); } bool DataHider::writeTransByte(std::fstream &file, uint8_t val, int pos) { file.seekp(m_bitmapHeader.getBmpDataAddr()+BYTE_PER_PIXEL*pos, std::ios_base::beg); file.write((char *)&val, 1); return file.good(); } void DataHider::length2Byte(uint32_t length) { for(uint32_t i=0; i<4; ++i) m_length[i] = (uint8_t)(length >> (i*8)) & 0xFF; #if DEBUG == 1 LOG << "length: " << length << " " << (int)m_length[0] << " " << (int)m_length[1] << " " << (int)m_length[2] << " " << (int)m_length[3] << " "; #endif } uint32_t DataHider::byte2Length() { uint32_t length = 0; uint32_t temp; for(uint32_t i=0; i<4; ++i) { temp = m_length[i]; #if DEBUG == 1 LOG << "temp: " << temp << " "; #endif temp <<= (i*8); #if DEBUG == 1 LOG << "temp: " << temp << " "; #endif length += temp; } #if DEBUG == 1 LOG << "length: " << length << " "; #endif return length; } bool DataHider::doEncode() { m_bitmapHeader.bmpParse(); std::ifstream dataFile; dataFile.open(m_dataFilePath, std::ios::binary); if(!dataFile.good()) { LOG << "open " << m_dataFilePath << " failed! "; return false; } uint32_t dataSize = getFileSize(dataFile); if(dataSize > m_bitmapHeader.getBmpPixelNum() + 8) // flag size add length size { LOG << "data is too big to save into the bitmap! "; dataFile.close(); return false; } std::fstream bmpFile; bmpFile.open(m_bitmapHeader.getBmpPath(), std::ios_base::binary| std::ios_base::out|std::ios_base::in); // |std::ios_base::ate|std::ios_base::app if(!bmpFile.good()) { LOG << "open " << m_bitmapHeader.getBmpPath() << " failed! "; dataFile.close(); return false; } dataFile.seekg(0, std::ios_base::beg); // flags m_flags[0] = FLAG_0; m_flags[1] = FLAG_1; m_flags[2] = FLAG_2; m_flags[3] = FLAG_3; for(uint32_t i=0; i<4; ++i) writeTransByte(bmpFile, m_flags[i], i); // length length2Byte(dataSize); for(uint32_t i=0; i<4; ++i) writeTransByte(bmpFile, m_length[i], i+4); // pos start at the 8th pixel int pos = 0; uint8_t data; while(pos < dataSize) { dataFile.read((char *)&data, 1); #if DEBUG == 1 LOG << HEX << (int)data << " "; #endif data ^= DATA_CODE; writeTransByte(bmpFile, data, pos+8); ++pos; } bmpFile.close(); dataFile.close(); return true; } bool DataHider::doDecode() { m_bitmapHeader.bmpParse(); std::fstream bmpFile; bmpFile.open(m_bitmapHeader.getBmpPath(), std::ios_base::binary|std::ios_base::in); if(!bmpFile.good()) { LOG << "open " << m_bitmapHeader.getBmpPath() << " failed! "; return false; } bmpFile.seekg(0, std::ios_base::beg); // flags for(uint32_t i=0; i<4; ++i) { readTransByte(bmpFile, m_flags[i], i); #if DEBUG LOG << HEX << (int)m_flags[i] << " "; #endif } if( !isAHider() ) { LOG << "this bitmap is not a hider file! "; bmpFile.close(); return false; } // length for(uint32_t i=0; i<4; ++i) readTransByte(bmpFile, m_length[i], i+4); #if DEBUG == 1 LOG << (int)m_length[0] << " " << (int)m_length[1] << " " << (int)m_length[2] << " " << (int)m_length[3] << " "; #endif uint32_t dataSize = byte2Length(); std::ofstream dataFile; dataFile.open(m_dataFilePath, std::ios::binary); if(!dataFile.good()) { LOG << "open " << m_dataFilePath << " failed! "; bmpFile.close(); return false; } // pos start at the 8th pixel int pos = 0; uint8_t data; while(pos < dataSize) { readTransByte(bmpFile, data, pos+8); data ^= DATA_CODE; dataFile.write((char *)&data, 1); ++pos; } bmpFile.close(); dataFile.close(); return true; }
main.cpp
#include <iostream> #include "bitmap.h" using namespace std; int main(int argc, char **argv) { cout << "Hello world!" << endl; if(argc < 4) { cout << "please type the right command! " << "DataHider encode ./data.txt ./ARGB8888.bmp " << "or DataHider decode ./data_out.txt ./ARGB8888.bmp "; return -1; } string mode = argv[1]; string dataFile = argv[2]; string bmpFile = argv[3]; if(mode == "encode") { cout << "encoder "; DataHider encoder(dataFile, bmpFile); encoder.doEncode(); } else if(mode == "decode") { cout << "decoder "; DataHider decoder(dataFile, bmpFile); decoder.doDecode(); } return 0; }