9.3 功能实现

来源:互联网 发布:单片机程序烧录 编辑:程序博客网 时间:2024/05/16 09:32

本例的开发环境为Windows操作系统,VC6。基本步骤如下:

1 打开VC6,单击【File|New】命令,弹出【New】对话框。

2)在【Projects】选项卡中,选择【MFC AppWizard(exe)】选项,创建一个MFC应用程序。在【Projectname】文本框中,输入项目名称“文件保险箱”,如图9.12所示。

3)单击“OK”,在创建MFC应用程序向导对话框选择应用程序类型,这里选择“Dilag based”如图所示。然后单击“Finish”完成。

(4)IDD_MY_DIALOG对话框窗体添加组合框(Combo Box)控件。

(5) Ctrl+W 键或单击【View|ClassWizard】命令,启动“MFC ClassWizard”,对话框,选择【Member Variables】选项。如图所示。

 

6)选中“IDC_COMBO1”控件,单击“Add Variable…”按钮。添加控件变量m_ALGLIST,如图所示。

7)添加4个编辑框,ID分别为IDC_EDIT1IDC_EDIT2IDC_EDIT3IDC_EDIT4用户保存加密时的原文和密文文件路径以及解密时的密文和原文文件路径。

8)添加6个命令按钮。ID分别为IDC_BUTTON1IDC_BUTTON2IDC_BUTTON3IDC_BUTTON4IDC_BUTTON5IDC_BUTTON6。功能分别是选择待加密的原文路径、选择密文路径、加密、选择待解密的密文路径、选择保存明文文件的路径、解密。

9)添加其他控件。全部控件和布局如图所示。

10)添加自定义的密码算法ID和算法名称结构体。在“文件保险箱Dlg.h”文件中添加如下代码。

// CMyDlg dialog

typedef struct _alglist//算法列表结构体

{

         char  strAlgName[128];//算法名称

         int nAlgID;//算法ID

}ALG_LIST,*ALG_LIST_PTR;

11)定义全局变量g_Alg_List,保存支持的全部加密算法。在“文件保险箱Dlg.cpp”文件中添加如下代码:

ALG_LIST g_Alg_List[]=

{

         {"ECB模式的DES算法",NID_des_ecb},

         {"CBC模式的DES算法",NID_des_cbc},

         {"CBC模式3DES算法",NID_des_ede3_cbc},

         {"ECB模式3DES算法",NID_des_ede3_ecb},

         {"CBC模式的IDEA算法",NID_idea_cbc},

         {"ECB模式的IDEA算法",NID_idea_ecb},

         {"128位的ECB模式的AES算法",NID_aes_128_ecb},

         {"128位的CBC模式的AES算法",NID_aes_128_cbc},

         {"192位的ECB模式的AES算法",NID_aes_192_ecb},

         {"192位的CBC模式的AES算法",NID_aes_192_cbc},

         {"256位的ECB模式的AES算法",NID_aes_256_ecb},

         {"256位的CBC模式的AES算法",NID_aes_256_cbc},

         {NULL,0}

};

12)添加初始化代码,添加支持的算法到组合框以及初始化OpenSSL环境。在CMyDlgOnInitDialog方法中添加如下代码:

         // TODO: Add extra initialization here

         m_ALGLIST.Clear();

         for(int i=0;;i++)

         {

                   if(g_Alg_List[i].nAlgID ==0)

                   {

                            break;

                   }

                   m_ALGLIST.InsertString(i,g_Alg_List[i].strAlgName);

         }

         m_ALGLIST.SetCurSel(i-1);

         OpenSSL_add_all_algorithms();

         return TRUE;  // return TRUE  unless you set the focus to a control

13)在VC工程WorkSpace区,选择【ClassView】选项,在CMyDlg类中添加函数Encrypt_FileDecrypt_File,如图所示。

14)在“文件保险箱Dlg.cpp”文件中添加完整的Encrypt_FileDecrypt_File函数代码如下。

/**********************************************************************

函数名称:Encrypt_File

函数功能:加密文件

处理过程:

         1.根据选择的密码算法以及口令,生成keyiv

         2.把文件头写入密文文件

         3.循环读取原文文件数据加密后保存到密文文件路径中。

参数说明:

         strPstrPlainFilePath:[IN] CString,待加密的原文文件路径

         strCipherFilePath:[IN] CString,加密后的密文文件保存路径

         nAlg_ID:[IN] int 密码算法ID

         strPass:[IN] CString 口令

返回值:成功返回TRUE,否则返回FALSE      

备注说明:密文文件由文件头和密文数据组成,文件头里记录和加密算法信息。

************************************************************************/

BOOL CMyDlg::Encrypt_File(CString strPlainFilePath, CString strCipherFilePath, int nAlg_ID, CString strPass)

{

        

         unsigned char key[EVP_MAX_KEY_LENGTH]; //保存密钥的数组

         unsigned char iv[EVP_MAX_KEY_LENGTH];     ////保存初始化向量的数组

         EVP_CIPHER_CTX ctx;                                                   //EVP加密上下文环境

         unsigned char out[1024];                             //保存密文的缓冲区

         int outl;

         unsigned char in[1024];                                         //保存原文的缓冲区

         int inl;

         const EVP_CIPHER * cipher;                                //加密算法

         int rv;

         FILE *fpIn;                                                                           //输入文件句柄

         FILE *fpOut;                                                              //输出文件句柄

         char enchead[128]={0};                                          //保存密文文件头的数组

        

         //根据算法ID获得EVP_CIPHER算法

         cipher = EVP_get_cipherbynid(nAlg_ID);

         if(cipher==NULL)

         {

                   return FALSE;

         }

         //打开待加密的原文文件

         fpIn = fopen(strPlainFilePath.GetBuffer(0),"rb");

         if(fpIn==NULL)

         {

                   return FALSE;

         }

         //打开保存密文的文件

         fpOut = fopen(strCipherFilePath.GetBuffer(0),"wb");

         if(fpOut==NULL)

         {

                   fclose(fpIn);

                   return FALSE;

         }

         strPlainFilePath.ReleaseBuffer();

         strCipherFilePath.ReleaseBuffer();

         //文件头,保存算法信息

         sprintf(enchead,"ALGID:%d/n",nAlg_ID);

         fwrite(enchead,1,128,fpOut);

         //根据口令、密码算法生成keyiv

         EVP_BytesToKey(cipher,EVP_md5(),NULL,(const unsigned char *)strPass.GetBuffer(0),strPass.GetLength(),1,key,iv);

         //初始化ctx

         EVP_CIPHER_CTX_init(&ctx);

         //设置密码算法、keyiv

         rv = EVP_EncryptInit_ex(&ctx,cipher,NULL,key,iv);

         if(rv != 1)

         {

                   EVP_CIPHER_CTX_cleanup(&ctx);

                   return FALSE;

         }

         //1K为单位,循环读取原文,加密后后保存到密文文件。

         for(;;)

         {

                   inl = fread(in,1,1024,fpIn);

                   if(inl <= 0)//读取原文结束

                            break;

                   rv = EVP_EncryptUpdate(&ctx,out,&outl,in,inl);//加密

                   if(rv != 1)

                   {

                            fclose(fpIn);

                            fclose(fpOut);

                            EVP_CIPHER_CTX_cleanup(&ctx);

                            return FALSE;

                   }

                   fwrite(out,1,outl,fpOut);//保存密文到文件

         }

         //加密结束

         rv = EVP_EncryptFinal_ex(&ctx,out,&outl);

         if(rv != 1)

         {

                   fclose(fpIn);

                   fclose(fpOut);

                   EVP_CIPHER_CTX_cleanup(&ctx);

                   return FALSE;

         }

         fwrite(out,1,outl,fpOut);//保密密文到文件

         fclose(fpIn);

         fclose(fpOut);

         EVP_CIPHER_CTX_cleanup(&ctx);//清除EVP加密上下文环境

         return TRUE;

}

/**********************************************************************

函数名称:Decrypt_File

函数功能:对加密文件解密

处理过程:

         1.读取文件头获得加密算法。

         2.根据算法和口令生成keyiv

         3.循环读取原文文件数据解密,并保存在原文文件。

参数说明:

         strCipherFilePath:[IN] CString,密文文件路径

         strPstrPlainFilePath:[IN] CString,解密后的原文文件保存路径。

         strPass:[IN] CString 口令

返回值:成功返回TRUE,否则返回FALSE      

************************************************************************/

 

BOOL CMyDlg::Decrypt_File(CString strCipherFilePath, CString strPlainFilePath, CString strPass)

{

         unsigned char key[EVP_MAX_KEY_LENGTH];           //保存密钥的数组

         unsigned char iv[EVP_MAX_KEY_LENGTH];              //保存初始化向量的数组    

         EVP_CIPHER_CTX ctx;                                                             //EVP加密上下文环境

         unsigned char out[1024+EVP_MAX_KEY_LENGTH];         //保存解密后明文的缓冲区数组

         int outl;

         unsigned char in[1024];                                                  //保存密文数据的数组

         int inl;

         const EVP_CIPHER * cipher;                                         //加密算法

         int rv;

         FILE *fpIn;                                                                                    //输入文件句柄

         FILE *fpOut;                                                                        //输出文件句柄 

         char enchead[128]={0};                                                   //保存密文文件头的数组                      

         int nAlg_ID=0;                                                                    //加密算法

        

         //打开待解密的密文文件

         fpIn = fopen(strCipherFilePath.GetBuffer(0),"rb");

         if(fpIn==NULL)

         {

                   return FALSE;

         }

         //打开保存明文的文件

         fpOut = fopen(strPlainFilePath.GetBuffer(0),"wb");

         if(fpOut==NULL)

         {

                   fclose(fpIn);

                   return FALSE;

         }

         strPlainFilePath.ReleaseBuffer();

         strCipherFilePath.ReleaseBuffer();

         //读取密文文件头,获取加密算法

         fread(enchead,1,128,fpIn);

         sscanf(enchead,"ALGID:%d/n",&nAlg_ID);

         if(nAlg_ID==0)

         {

                   return FALSE;

         }

         //根据算法ID获得EVP_CIPHER算法

         cipher = EVP_get_cipherbynid(nAlg_ID);

         if(cipher==NULL)

         {

                   return FALSE;

         }

         //根据口令、密码算法生成keyiv

         EVP_BytesToKey(cipher,EVP_md5(),NULL,(const unsigned char *)strPass.GetBuffer(0),strPass.GetLength(),1,key,iv);

         //初始化ctx

         EVP_CIPHER_CTX_init(&ctx);

         //设置解密的算法、keyiv

         rv = EVP_DecryptInit_ex(&ctx,cipher,NULL,key,iv);

         if(rv != 1)

         {

                   EVP_CIPHER_CTX_cleanup(&ctx);

                   return FALSE;

         }

         //1K为单位,循环读取原文,解密后后保存到明文文件。

         for(;;)

         {

                   inl = fread(in,1,1024,fpIn);

                   if(inl <= 0)

                            break;

                   rv = EVP_DecryptUpdate(&ctx,out,&outl,in,inl);//解密

                   if(rv != 1)

                   {

                            fclose(fpIn);

                            fclose(fpOut);

                            EVP_CIPHER_CTX_cleanup(&ctx);

                            return FALSE;

                   }

                   fwrite(out,1,outl,fpOut);//保存明文到文件

         }

         //解密结束

         rv = EVP_DecryptFinal_ex(&ctx,out,&outl);

         if(rv != 1)

         {

                   fclose(fpIn);

                   fclose(fpOut);

                   EVP_CIPHER_CTX_cleanup(&ctx);

                   return FALSE;

         }

         fwrite(out,1,outl,fpOut);//保存明文到文件

         fclose(fpIn);

         fclose(fpOut);

         EVP_CIPHER_CTX_cleanup(&ctx);//清除EVP加密上下文环境

         return TRUE;

}

详细的VC工程请参考本书附光盘“code/第二篇-OpenSSL开发/文件保险箱”目录 
原创粉丝点击