你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
深入理解MFC编写自己的加密编辑器
 

摘 要:本文通过对微软基础类MFC基本框架的深入分析,利用文档类与视类之间交换数据的渠道,最大限度地利用了MFC为我们提供的功能,用一种简洁的方法实现了加密编辑器,同时对于广大使用MFC编程的人来说也有很好的借鉴作用。

关键词:微软 MFC 加密 编辑器

一、自己编写的的必要性

现代社会大量的事物都由计算机来处理,社会财富和机密已经越来越集中到计算机中,安全就显得尤为重要,对于广大使用个人电脑的人来说在计算机中一般也存有自己的秘密(日记等)。虽然现在的编辑软件都具有加密功能,如WPSWORD,但是这些软件过于庞大,加密效果也不见得好,如WORD对大量连续明文加密效果不好,WPSDOS版竟然还留有后门,加密功能如同虚设,WINDOWS版可能也存在。因此我们使用自己的加密算法,编写自己的加密编辑器还是很有必要的。

二、更好的安全性

    对于一个加密产品而言它有三个要素:算法,加密密钥,解密密钥。要解密的人知道这三个因素越多,解密就越容易,如果自己编写加密产品,则三个因素都可以做到是保密的。这对破译者无疑增加了很大的难度。本文主要论述使用MFC实现的方法,加加密算法只是作了很简单的异或运算,读者可以自行修改加入自己的加密算法(最好是基于随机数的,以对付字符频率的分析)。

三、实现原理

    但是完全依靠自己的力量编写一个编辑器谈何容易,要做的工作实在是太多了,好在有了微软的MFC类,可以为我们完成一些基本工作,只要我们深入理解MFC有关类的相互关系和作用(特别是数据的串行化),灵活应用,就可以很快地编写一个自己的编辑器了。

    我们使用VCApplication Wizard生成的应用程序框主要是由视类(CView)和文档类(CDocument)构成的。视类主要用于显示数据和实现与用户之间的交互,而文档类则用于对数据的处理,文档处理的数据和用户的输入都是通过数据的串行化(serialize)来实现视类与文档信息双向交流的。其中视类又有很多子类以适应不同的应用需要,通常默认的选择为CView,这里我们应该选择其衍生类CEditView来构成我们的视类,此类封装了很多编辑器需要的功能,如查找、块操作、UNDO等。这样我们的程序就已经是一个编辑器了。

    有了基本的程序框架后,关键就是如何将自己的加密算法无缝地嵌入到此框架中去,这里我们必须理解Serialize的功能,它是一个对存储介质进行读写的进程,包含在CObject类中,而MFC几乎所有的类均是从CObject类中继承而来的,因此绝大部的MFC类都支持Serialize过程。Serialize过程对类CArchive进行操作,而CArchive类又都有一个CFile对象,通过串行化,就将要操作的数据抽象化,只需要对CArchive类进行操作而不必须关心被串行化对象的具体特征。CArchive类不但可以对字符进行操作而且还可以对二进制数据进行操作。因此Serialize是文档类与视类之间联系的纽带,我们可以将自己对数据进行加密处理的功能加到文档类中,再将处理后的数据封装在一个CArchive类中通过Serialize传到视类中去显示,编辑,编辑后的数据再通过一个CArchive类由Serialize送回文档类进行保存。需要注意的是,虽然作了加密处理,但是视类处理的必须是明文,所以它操作的文件与文档类操作的文件是不同的,一个是明文文件一个是密文文件(设计时包含了一个512字节的文件头,用于存入密码和有关的信息),为了增加安全性将明文文件作为内存文件,这样在磁盘上就没有任何明文的痕迹了。

四、一个实例

    首先生成一个基于单文档的程序,在第6步改视类从CView CEditView(如果选择CRichEditView,则生成的加密编辑器还可以加入图形等对象),以下是主要的程序片段:

    重载文档类对文件打开的成员函数

# define CIPHER 0xa6 //一个简单的加密密钥

BOOL CDreadDoc::OnOpenDocument(LPCTSTR lpszPathName)

{

    //原来的处理函数必须屏蔽,因为这里处理的是密文

    /* if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; */

    // TODO: Add your specialized creation code here

    DWORD dwFileLength;

    unsigned int i,j;

    CString PathFile;//store the filename

    char mBuff[1024];//buffer that transfer content from disk file to the memory file

    unsigned char pAttach[60000];//the buffers attached to the CFile of MY OWN CArchive

    POSITION pos = GetFirstViewPosition();

    CView* pFirstView;//The CView attached this CDocment

    CInputpsw InputPassword;//dialog for input password

    char tmp[11];

    unsigned int iProperty;// property of dwj file

    //above all is data defined

    pFirstView=GetNextView( pos );//get the view of this docment

    PathFile=lpszPathName;//get the file name opened

    CFile HisFile(PathFile,CFile::modeRead);//HisFile is The disk file will be opened

    dwFileLength=HisFile.GetLength()-512;

    //subtract the length of head file

    HisFile.Read(cCipherWrite,512);//read the head of file

    //对文件头进行求和校验

    iProperty=0;

    for(i=0;i<182;i++)

    {

        iProperty+=cCipherWrite[i];

    }//calculate the check sum of head file

    if(iProperty!=0x3521)//not the dwj file

    {

        pFirstView->MessageBox("This is not a dwj file!");

        return FALSE;

    }

    for(i=0;i<10;i++)//convert the password from ciphertext to plaintext

    {

        tmp[i]=cCipherWrite[189+i]^CIPHER;

    }

    tmp[10]=0;

    mPassword=tmp;

    mPassword.TrimRight();

    InputPassword.DoModal();

    if(mPassword!=InputPassword.m_psw)

    //the password inputed is not corresponding to the saved

    {

        pFirstView->MessageBox("The Password is not correct!");

        return FALSE;

    }

    CMemFile MyFile; //一个内存文件,通过Serialize传给视类进行显示编辑

    MyFile.Open("\temp.txt",CFile::modeCreate|CFile::modeWrite);   

//首先以写的形式打开内存文件,这样才能将解密后的密文写入内存文件

    MyFile.Attach(pAttach,dwFileLength);

    //将密文的磁盘文件内容经过解密后读入内存文件

    for(i=0;i<dwFileLength/1024;i++)

    {

        HisFile.Read(mBuff,1024);

        for(j=0;j<1024;j++) //decode

        {

            mBuff[j]^=CIPHER;

        }

        MyFile.Write(mBuff,1024);

    }

    HisFile.Read(mBuff,dwFileLength%1024);

    for(j=0;j<dwFileLength%1024;j++) //uncode

    {

        mBuff[j]^=CIPHER;

    }

    MyFile.Write(mBuff,dwFileLength%1024);

    //transfer the data from HisFile to MyFile

    HisFile.Close();

    MyFile.Close();

    MyFile.Open("\temp.txt",CFile::modeRead);

//再次以读的方式打开内存文件,因为从OnOpenDocument中调用的Serialize//数只能接收读属性的文件

    if(dwFileLength>=59999)

    {

        pFirstView->MessageBox("The length of file is too large to load!");

        *pAttach=0;

        MyFile.Attach(pAttach,1024,1);

    }

    else

    {

        MyFile.Attach(pAttach,dwFileLength);

    }

    //生成内存文件的CArchive对象ar,显式地调用Serialize函数将它传给视类

    CArchive ar(&MyFile,CArchive::load);

    Serialize(ar);//throw my memory file to CEditView  

    return TRUE;

}

另一个需要重载的函数是文档类的保存文件函数

BOOL CDreadDoc::OnSaveDocument(LPCTSTR lpszPathName)

{

    // TODO: Add your specialized code here and/or call the base class

    CString PathFile;//store the filename saved

    unsigned char pAttach[60000];//the buffers attached to the CFile of CArchive

    CMemFile MyFile;//The memory file that will retrive the content of CEditView

    CFile DesFile;//The destination disk file saved

    DWORD dwFileLength;

    unsigned int i,j;

    unsigned char mBuff[1024];//buffer that transfer content from memory file to destination file

    POSITION pos = GetFirstViewPosition();

    CView* pFirstView;//CView attached this CDocment

    CPasswrd mInputPsw;

    //varialbes defined above

    pFirstView=GetNextView( pos );//get the CView of this Docment

    if(mPassword=="")

    //there is not password in this file that will be saved

    {

        mInputPsw.DoModal();//input the password

        mPassword=mInputPsw.m_psw;//get the first password

    }

    PathFile=lpszPathName;//get the saved file name

    MyFile.Open("\temp.txt",CFile::modeCreate | CFile::modeWrite);

    for(i=0;i<60000;i++) pAttach[i]=0;//clear the memory file buffers

    MyFile.Attach(pAttach,60000);

    CArchive ar(&MyFile,CArchive::store);

    //显式地调用Serialize函数,从视类中取得编辑后内容存入内存文件

    Serialize(ar);//get the data of docment to my memory file

    dwFileLength=strlen((char *)pAttach);

    if(dwFileLength>=59999)

    {

    pFirstView->MessageBox("The length of file is too large to save entirely!");

    }

    DesFile.Open(PathFile,CFile::modeCreate | CFile::modeWrite);

  strcpy((char*)cCipherWrite,(LPCTSTR)mVersion);//mVersion是存入在文件头

//中的版本信息

    //retrive the version information

    mBuff[0]=0x1a;

    mBuff[1]=0x00;

    strcat((char*)cCipherWrite,(char*)mBuff);

    //write the end flag of text file

    for(i=0;i<(unsigned int)(mPassword.GetLength());i++)

    {

        cCipherWrite[189+i]=mPassword.GetAt(i);

    }

    for(i=0;i<(unsigned int)(10-mPassword.GetLength());i++)

    {

        cCipherWrite[189+mPassword.GetLength()+i]=0x20;

    }//the spare room is filled by space

    for(i=0;i<10;i++)//convert the password from plaintext to ciphertext

    {

        cCipherWrite[189+i]^=CIPHER;

    }

    //fill with password

    DesFile.Write(cCipherWrite,512);//write the head of file

    //handle the head of file above

    //将存入内存文件中的明文经过加密后存入磁盘文件中

    MyFile.SeekToBegin();

    for(i=0;i<dwFileLength/1024;i++)

    {

        MyFile.Read(mBuff,1024);

        for(j=0;j<1024;j++) //encode

        {

            mBuff[j]^= CIPHER;

        }

        DesFile.Write(mBuff,1024);

    }

    MyFile.Read(mBuff,dwFileLength%1024);

    for(j=0;j<dwFileLength%1024;j++) //encode

    {

        mBuff[j]^= CIPHER;

    }

    DesFile.Write(mBuff,dwFileLength%1024);

    DesFile.Close();

    //transfer the data from HisFile to MyFile

    SetModifiedFlag(FALSE);

    return TRUE;   

    //return CDocument::OnSaveDocument(lpszPathName);

}

    当然你还需要在你的程序中加入接收用户输入密码的对话框,笔者在这里就不赘述了。

 

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089