winston 发表于 2012-3-8 15:02:45

[原]VC++信息安全编程(14)基于24位bmp位图的信息隐藏

信息隐藏指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是透明的。
传统的信息隐藏起源于古老的隐写术。如在古希腊战争中,为了安全地传送军事情报,奴隶主剃光奴隶 的头发,将情报文在奴隶的头皮上,待头发长起后再派出去传送消息。我国古代也早有以藏头诗、藏尾诗、漏格诗以及绘画等形式,将要表达的意思和“密语”隐藏在诗文或画卷中的特定位置,一般人只注意诗或画的表面意境,而不会去注意或破解隐藏其中的密语。   信息隐藏的发展历史可以一直追溯到"匿形术(Steganography)"的使用。"匿形术"一词来源于古希腊文中"隐藏的"和"图形"两个词语的组合。虽然"匿形术"与"密码术(Cryptography)"都是致力于信息的保密技术,但是,两者的设计思想却完全不同。"密码术"主要通过设计加密技术,使保密信息不可读,但是对于非授权者来讲,虽然他无法获知保密信息的具体内容,却能意识到保密信息的存在。而"匿形术"则致力于通过设计精妙的方法,使得非授权者根本无从得知保密信息的存在与否。相对于现代密码学来讲,信息隐藏的最大优势在于它并不限制对主信号的存取和访问,而是致力于签字信号的安全保密性。


我们进行信息交换的时候,需要保证数据的安全,所以需要进行适当的信息隐藏。
我们发送一个图片。但是图片里面隐含的加密信息,是就是信息隐藏,只有专属工具能够读出。
所以信息隐藏技术很重要。针对信息安全。
我们来实现一个案例代码。
BMP图信息隐藏头文件,请见代码分析

// BMPHider.h: interface for the CBMPHider class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_BMPHIDER_H__6287D87F_F0AA_4D0C_9502_4674B639CBB5__INCLUDED_)
#define AFX_BMPHIDER_H__6287D87F_F0AA_4D0C_9502_4674B639CBB5__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <complex>
using namespace std;
class CBMPHider
{
public:
        CBMPHider();
        virtual ~CBMPHider();
public:
        int m_BitCount;                        //位图的图像位数
        WORD * m_pWordData;
        CPalette m_Palette;
        unsigned char *m_pDib, *m_pDibBits;
        unsigned char *m_pOldDibShow;
        DWORD m_dwDibSize;
        BITMAPINFOHEADER *m_pBIH;
        RGBQUAD *m_pPalette;
        int m_nPaletteEntries;
        UINT bitmap_size;
        UINT embfile_size;
        unsigned char *p;                //指向宿主图像数据
        int tag;                                //此tag用以标记打开的图像中是否含有隐藏信息0:无 else:有
        unsigned char *q;                //指向隐藏文件数据
        unsigned char *m_pFile;
public:
        BOOL Draw( CDC *pDC, int nX = -1, int nY = -1, int nWidth = -1, int nHeight = -1, int Style = 1);
        BOOL Save( const char *pszFilename );
        BOOL Load( const char * );
       
        void BackUpDib();                //备份图像
        void Pick();                        //提取图像
        void Embed();                        //嵌入图像
        BOOL LoadEmbFile(const char *);
        BOOL DrawContrast(CDC *pDC,int rect_width, int rect_height);
        void SavePicked( const char *pszFilename );       

};

#endif // !defined(AFX_BMPHIDER_H__6287D87F_F0AA_4D0C_9502_4674B639CBB5__INCLUDED_)

请见详细代码实现
#include "stdafx.h"
#include "BMPHider.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBMPHider::CBMPHider()
{
        m_pDib = NULL;
        m_pWordData = NULL;
        m_pFile = NULL;
        m_pOldDibShow = NULL;
}

CBMPHider::~CBMPHider()
{
        if( m_pDib != NULL )
                delete [] m_pDib;
        if( m_pWordData != NULL )
                delete [] m_pWordData;
        if (m_pFile != NULL)
                delete [] m_pFile;
        if (m_pOldDibShow != NULL)
                delete [] m_pOldDibShow;
}

BOOL CBMPHider::Load( const char *pszFilename )
{
        CFile cf;
        if( !cf.Open( pszFilename, CFile::modeRead ) )
                return( FALSE );
       
        DWORD dwDibSize;
        dwDibSize =
                cf.GetLength() - sizeof( BITMAPFILEHEADER );

        unsigned char *pDib;
        pDib = new unsigned char ;
        if( pDib == NULL )
                return( FALSE );

        BITMAPFILEHEADER BFH;
        try
        {
                if( cf.Read( &BFH, sizeof( BITMAPFILEHEADER ) )
                        != sizeof( BITMAPFILEHEADER ) ||
                        BFH.bfType != 'MB' ||
                        cf.Read( pDib, dwDibSize ) != dwDibSize )
                {
                        delete [] pDib;
                        return( FALSE );
                }
        }
       
        catch( CFileException *e )
        {
                e->Delete();
                delete [] pDib;
                return( FALSE );
        }
        cf.Close();
        if( m_pDib != NULL )
                delete m_pDib;
        if (BFH.bfReserved1 != 0)          //含有隐藏信息,保存其大小
        {
                if (BFH.bfReserved2 == 0)
                        embfile_size = BFH.bfReserved1;
                else
                        embfile_size = BFH.bfReserved1 + 65535;
        }
        m_pDib = pDib;
        m_dwDibSize = dwDibSize;
        m_pBIH = (BITMAPINFOHEADER *) m_pDib;
        m_pPalette =(RGBQUAD *) &m_pDib;
        m_nPaletteEntries = 1 << m_pBIH->biBitCount;
        if( m_pBIH->biBitCount > 8 )         
                m_nPaletteEntries = 0;
        else if( m_pBIH->biClrUsed != 0 )
                m_nPaletteEntries = m_pBIH->biClrUsed;
        m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER)+
                        m_nPaletteEntries*sizeof(RGBQUAD)];

        if( m_Palette.GetSafeHandle() != NULL )
                m_Palette.DeleteObject();

        if( m_nPaletteEntries != 0 )
        {      

                LOGPALETTE *pLogPal = (LOGPALETTE *) new char
                                [sizeof(LOGPALETTE)+
                                m_nPaletteEntries*sizeof(PALETTEENTRY)];

                if( pLogPal != NULL )
                {
                        pLogPal->palVersion = 0x300;
                        pLogPal->palNumEntries = m_nPaletteEntries;

                        for( int i=0; i<m_nPaletteEntries; i++ )
                        {
                                pLogPal->palPalEntry.peRed =
                                        m_pPalette.rgbRed;
                                pLogPal->palPalEntry.peGreen =
                                        m_pPalette.rgbGreen;
                                pLogPal->palPalEntry.peBlue =
                                        m_pPalette.rgbBlue;
                        }

                        m_Palette.CreatePalette( pLogPal );
                        delete [] pLogPal;
                }
        }

        m_BitCount = 24;             //24位位图
        p = m_pDibBits;            //指向位图数据的指针,用来执行处理操作用
        bitmap_size = m_dwDibSize - (m_pDibBits - m_pDib);//真正的位图数据的大小(即除头结构外)
       
        tag = BFH.bfReserved1;
        return( TRUE );

}

BOOL CBMPHider::Save( const char *pszFilename ) //保存含有隐藏信息的bmp
{
        if( m_pDib == NULL )
                return( FALSE );
        CFile cf;
        if( !cf.Open( pszFilename,
                CFile::modeCreate | CFile::modeWrite ) )
                return( FALSE );
        try
        {
                BITMAPFILEHEADER BFH;
                memset( &BFH, 0, sizeof( BITMAPFILEHEADER ) );
                BFH.bfType = 'MB';
                BFH.bfSize = sizeof( BITMAPFILEHEADER ) + m_dwDibSize;
                BFH.bfOffBits = sizeof( BITMAPFILEHEADER ) +
                        sizeof( BITMAPINFOHEADER ) +
                        m_nPaletteEntries * sizeof( RGBQUAD );
                if (embfile_size <= 65535)   
                        //由于bfReserved1是unsigned short型的,大小可能不能满足要求,可能要用到reserved2
                        BFH.bfReserved1 = embfile_size;   
                else
                {
                        BFH.bfReserved1 = embfile_size - 65535;
                        BFH.bfReserved2 = 1; //标记
                }
                cf.Write( &BFH, sizeof( BITMAPFILEHEADER ) );
                cf.Write( m_pDib, m_dwDibSize );
        }
        catch( CFileException *e )
        {
                e->Delete();
                return( FALSE );
        }
        return( TRUE );
}

BOOL CBMPHider::Draw( CDC *pDC, int nX, int nY, int nWidth, int nHeight, int Style )
{
        if( m_pDib == NULL )
                return( FALSE );
        long vWidth = m_pBIH->biWidth;
        if( nWidth == -1 )
                nWidth = m_pBIH->biWidth;
        if( nHeight == -1 )
                nHeight = m_pBIH->biHeight;
        if (Style)   
        {
                StretchDIBits( pDC->m_hDC, nX, nY,
                        nWidth, nHeight,
                        0, 0,
                        m_pBIH->biWidth, m_pBIH->biHeight,
                        m_pDibBits,
                        (BITMAPINFO *) m_pBIH,
                        BI_RGB, SRCCOPY );
        }
        else
        {
                SetDIBitsToDevice( pDC->m_hDC, nX, nY,
                        m_pBIH->biWidth, m_pBIH->biHeight,
                        0, 0,
                        0, m_pBIH->biHeight,
                        m_pDibBits,
                        (BITMAPINFO *) m_pBIH,
                        BI_RGB);
        }
        return( TRUE );
}



BOOL CBMPHider::LoadEmbFile(const char * pszFilename)
{       
        CFile cf;
        if( !cf.Open( pszFilename, CFile::modeRead ) )
                return( FALSE );

        DWORD dwFileSize;
        dwFileSize = cf.GetLength();

        embfile_size = dwFileSize;
        unsigned char *pFile;
        pFile = new unsigned char ;
        cf.Read( pFile, dwFileSize );       //将文件中内容读入数组,解下来就开始嵌入操作

        m_pFile = pFile;
        q = pFile;      //记录下位置
        return true;
}

void CBMPHider::Embed()//嵌入
{
        unsigned char bmdata;//bitmap data
        unsigned char efdata;//embeddedfile data
        int t = 7;               
        int x;       
        int s;
        int last_bit; //记录字节最低位本来的bit

        for(UINT i1 = 0, i2 = 0; i1 <= bitmap_size - 1, i2 <= embfile_size - 1; i1++)
        {
                bmdata = *p;

                for (int j = 0; j <= 7; j++) //计算各bit位
                {
                        x = bmdata & 1;
                        bmdata >>= 1;
                }
               
                last_bit = x;
                x = x ^ x ^ x ^ x ^ x ^ x ^ x;
               
                if (t == 7)    //宿主图片每走过八个字节,计算一次s[]
                {
                        efdata = *q;
                        for (j = 0; j <= 7; j++)
                        {
                                s = efdata & 1;
                                efdata >>= 1;
                        }
                }
                x ^= s;//隐藏信息
                if (last_bit == 0)//嵌入隐藏信息
                {
                        *p |= x;
                }
                else
                {
                        *p &= 254 + x;
                }
       
                p++;
                t--;
                if (t == -1)//需要计算一次s[]
                {
                        t = 7;
                        q++;
                        i2++;
                }
        }

}

void CBMPHider::Pick()//提取
{
        m_pFile = new unsigned char ;
        unsigned char *q = m_pFile;

        unsigned char bmdata;//bitmap data

        int x;       
        int s;
        int t = 7;
        for (UINT i1 = 0, i2 = 0; i1 <= bitmap_size - 1, i2 <= embfile_size - 1; i1++)
        {
                bmdata = *p;
                for (int j = 0; j <= 7; j++) //计算各bit位
                {
                        x = bmdata & 1;
                        bmdata >>= 1;
                }
                s = x ^ x ^ x ^ x ^ x ^ x ^ x ^ x;
                t--;
                if (t == -1) //s到s组成一个字节
                {
                        *q = s * 128 + s * 64 + s * 32 + s * 16 +
                                s * 8 + s * 4 + s * 2 + s;
                        t = 7;
                        i2++;
                        q++;
                }
                p++;
        }

}
       
void CBMPHider::SavePicked( const char *pszFilename )
{
        CFile cf;
        cf.Open( pszFilename, CFile::modeCreate | CFile::modeWrite );
        cf.Write( m_pFile, embfile_size );
}

void CBMPHider::BackUpDib()
{
        m_pOldDibShow = new unsigned char ;
   
        ::CopyMemory(m_pOldDibShow, m_pDibBits, bitmap_size); //将原始的数据单独保存以便对比显示
}

BOOL CBMPHider::DrawContrast(CDC *pDC, int rect_width, int rect_height)
{                           //看原图,如果容纳得下两个图,则不要压缩,否则要压缩
        if (m_pOldDibShow == NULL)
                return FALSE;
        if (rect_width >= 2*m_pBIH->biWidth + 30 && rect_height >= m_pBIH->biHeight)
        {
                StretchDIBits( pDC->m_hDC, 0, 0,
                m_pBIH->biWidth, m_pBIH->biHeight,
                0, 0,
                m_pBIH->biWidth, m_pBIH->biHeight,
                m_pOldDibShow,
                (BITMAPINFO *) m_pBIH,
                BI_RGB, SRCCOPY );    // 原图

                StretchDIBits( pDC->m_hDC, m_pBIH->biWidth+30, 0,
                m_pBIH->biWidth, m_pBIH->biHeight,
                0, 0,
                m_pBIH->biWidth, m_pBIH->biHeight,
                m_pDibBits,
                (BITMAPINFO *) m_pBIH,
                BI_RGB, SRCCOPY );    // 嵌入隐藏信息的图
        }
        else
        {
                int scale_i = m_pBIH->biWidth * 5 / (rect_width*2);
                int scale_j = m_pBIH->biHeight / rect_height;
                if (scale_i < scale_j)
                        scale_i = scale_j;

                StretchDIBits( pDC->m_hDC, 0, 0,
                m_pBIH->biWidth / scale_i, m_pBIH->biHeight / scale_i,
                0, 0,
                m_pBIH->biWidth, m_pBIH->biHeight,
                m_pOldDibShow,
                (BITMAPINFO *) m_pBIH,
                BI_RGB, SRCCOPY );    // 原图

                StretchDIBits( pDC->m_hDC, m_pBIH->biWidth / scale_i+30, 0,
                m_pBIH->biWidth / scale_i, m_pBIH->biHeight / scale_i,
                0, 0,
                m_pBIH->biWidth, m_pBIH->biHeight,
                m_pDibBits,
                (BITMAPINFO *) m_pBIH,
                BI_RGB, SRCCOPY );    // 嵌入隐藏信息的图

        }

        return TRUE;
}


具体代码调用实现
#include "stdafx.h"
#include "DataHideInBMP.h"

#include "DataHideInBMPDoc.h"
#include "DataHideInBMPView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDataHideInBMPView

IMPLEMENT_DYNCREATE(CDataHideInBMPView, CView)

BEGIN_MESSAGE_MAP(CDataHideInBMPView, CView)
        //{{AFX_MSG_MAP(CDataHideInBMPView)
        ON_COMMAND(ID_NORMAL, OnNormal)
        ON_COMMAND(ID_STRETCH, OnStretch)
        ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
        ON_COMMAND(ID_EMBED, OnEmbed)
        ON_UPDATE_COMMAND_UI(ID_EMBED, OnUpdateEmbed)
        ON_COMMAND(ID_PICK, OnPick)
        ON_UPDATE_COMMAND_UI(ID_PICK, OnUpdatePick)
        //}}AFX_MSG_MAP
        // Standard printing commands
        ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
        ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
        ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDataHideInBMPView construction/destruction

CDataHideInBMPView::CDataHideInBMPView()
{
        // TODO: add construction code here
        ImageStyle = 0;
    have_open_a_file = false;

        embed = false;
        pick = false;
        show_contrast = false;
}

CDataHideInBMPView::~CDataHideInBMPView()
{
}

BOOL CDataHideInBMPView::PreCreateWindow(CREATESTRUCT& cs)
{
        // TODO: Modify the Window class or styles here by modifying
        //the CREATESTRUCT cs
        WNDCLASSEX wndcls;
        wndcls.cbSize=sizeof(WNDCLASSEX);
        HINSTANCE hinst=AfxGetInstanceHandle();
        if(CView::PreCreateWindow(cs)&&cs.lpszClass!=NULL)
        {
                HBRUSH hbkbrush=CreateSolidBrush(RGB(0,0,0));
                if(!GetClassInfoEx(hinst,cs.lpszClass,&wndcls))
                        return FALSE;
                UnregisterClass(cs.lpszClass,hinst);
                wndcls.hbrBackground=hbkbrush;
                RegisterClassEx(&wndcls);
                return TRUE;
        }
        else
                return FALSE;
        return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CDataHideInBMPView drawing

void CDataHideInBMPView::OnDraw(CDC* pDC)
{
        CDataHideInBMPDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        // TODO: add draw code for native data here
        RECT Rect;
        GetClientRect( &Rect );

        if (!show_contrast)
                m_BMPHider.Draw( pDC, 0, 0, Rect.right, Rect.bottom, ImageStyle );
        else
        {
                m_BMPHider.DrawContrast(pDC, Rect.right, Rect.bottom);
                pDC->SetBkColor((0,0,0));
                pDC->SetTextColor((255,255,255));
                pDC->TextOut(0, Rect.bottom-30, "左图为原始图,右图为嵌入了隐藏信息的图");
        }
}

/////////////////////////////////////////////////////////////////////////////
// CDataHideInBMPView printing

BOOL CDataHideInBMPView::OnPreparePrinting(CPrintInfo* pInfo)
{
        // default preparation
        return DoPreparePrinting(pInfo);
}

void CDataHideInBMPView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
        // TODO: add extra initialization before printing
}

void CDataHideInBMPView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
        // TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CDataHideInBMPView diagnostics

#ifdef _DEBUG
void CDataHideInBMPView::AssertValid() const
{
        CView::AssertValid();
}

void CDataHideInBMPView::Dump(CDumpContext& dc) const
{
        CView::Dump(dc);
}

CDataHideInBMPDoc* CDataHideInBMPView::GetDocument() // non-debug version is inline
{
        ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDataHideInBMPDoc)));
        return (CDataHideInBMPDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CDataHideInBMPView message handlers

void CDataHideInBMPView::OnNormal()
{
        // TODO: Add your command handler code here
        ImageStyle = 0;

        CMenu *pMnu = AfxGetMainWnd()->GetMenu( );
        pMnu->CheckMenuItem(ID_STRETCH,MF_UNCHECKED);
        pMnu->CheckMenuItem(ID_NORMAL,MF_CHECKED);
       
        InvalidateRect( NULL, TRUE );
        UpdateWindow();       
}

void CDataHideInBMPView::OnStretch()
{
        // TODO: Add your command handler code here
        ImageStyle = 1;
       
        CMenu *pMnu = AfxGetMainWnd()->GetMenu( );
        pMnu->CheckMenuItem(ID_STRETCH,MF_CHECKED);
        pMnu->CheckMenuItem(ID_NORMAL,MF_UNCHECKED);
       
        InvalidateRect( NULL, TRUE );
        UpdateWindow();       
}

void CDataHideInBMPView::OnFileOpen()
{
        // TODO: Add your command handler code here
        show_contrast = false;   //非对比显示
        static char szFilter[] = "BMP Files(*.BMP)|*.BMP||";

        CFileDialog FileDlg( TRUE, NULL, NULL,
                OFN_HIDEREADONLY, szFilter );

        if( FileDlg.DoModal() == IDOK &&
                m_BMPHider.Load( FileDlg.GetPathName() ) )
        {
                InvalidateRect( NULL, TRUE );
                UpdateWindow();
                have_open_a_file=true;
                if (m_BMPHider.tag == 0)//该图无隐藏信息
                {
                        embed = true;
                        pick = false;//菜单亮暗控制
                }//
                else
                {
                        embed = false;
                        pick = true;//菜单亮暗控制
                }//
        }       
}

void CDataHideInBMPView::OnEmbed()
{
        // TODO: Add your command handler code here
        //弹出打开对话框,用户选择嵌入的文件

        static char szFilter[] = "All Files(*.*)|*.*||";

        CFileDialog FileDlg( TRUE, NULL, NULL,
                OFN_HIDEREADONLY, szFilter );

        if( FileDlg.DoModal() == IDOK &&
                m_BMPHider.LoadEmbFile( FileDlg.GetPathName() ) )
        {
                if (m_BMPHider.bitmap_size / m_BMPHider.embfile_size < 8)
                {
                        AfxMessageBox("文件太大,无法嵌入!");
                }
                else
                {
                        show_contrast = true;
                        m_BMPHider.BackUpDib(); //图片原始数据备份供对比显示
                        m_BMPHider.Embed();   //嵌入
                       
                        Invalidate(true);//刷屏,显示加入隐藏信息后的图像
                       
                        static char szFilter[] = "BMP Files(*.BMP)|*.BMP||";
                        CFileDialog FileDlg( FALSE, "bmp", NULL,                //保存
                                OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter );
                       
                        if( FileDlg.DoModal() == IDOK )
                        {
                                m_BMPHider.Save( FileDlg.GetPathName() );
                        }
                        embed = false;
                }
               
        }       
}

void CDataHideInBMPView::OnUpdateEmbed(CCmdUI* pCmdUI)
{
        // TODO: Add your command update UI handler code here
        pCmdUI->Enable(embed);       
}

void CDataHideInBMPView::OnPick()
{
        // TODO: Add your command handler code here
        //提取完毕,弹出保存对话框,用户进行保存
        static char szFilter[] = "All Files(*.*)|*.*||";
        CFileDialog FileDlg( FALSE, "", NULL,                //保存
                OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter );
                               
        if (FileDlg.DoModal() == IDOK)
        {       
                m_BMPHider.Pick();
                m_BMPHider.SavePicked(FileDlg.GetPathName());
                pick = false;
        }       
}

void CDataHideInBMPView::OnUpdatePick(CCmdUI* pCmdUI)
{
        // TODO: Add your command update UI handler code here
        pCmdUI->Enable(pick);       
}


作者:yincheng01 发表于2011-12-15 7:40:27 原文链接

页: [1]
查看完整版本: [原]VC++信息安全编程(14)基于24位bmp位图的信息隐藏