找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4753|回复: 0

[加密解密]使用CryptoAPI进行文件加密解密——源码

[复制链接]
发表于 2012-2-29 15:08:56 | 显示全部楼层 |阅读模式
前一篇简单介绍了下CryptoAPI的东西,这篇就将那点代码放出来给大家看看,以作交流参考目的。
  1. /************************************************************************
  2.                 FileName:CryptoDefine.h
  3.                 Author        :eliteYang
  4.                 Mail        :elite_yang@163.com
  5.                 Desc        :加密需要的常量定义
  6. ************************************************************************/
  7. #ifndef __CRYPTO_DEFINE_H_
  8. #define __CRYPTO_DEFINE_H_
  9. #include <WinCrypt.h>
  10. #define MY_ENCODING_TYPE ( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING )
  11. #define KEY_LENGTH 0x00800000
  12. #define ENCRYPT_ALGORITHM CALG_RC4
  13. #define ENCRYPT_BLOCK_SIZE 8
  14. #endif
  15. /************************************************************************
  16.                 FileName:LogDefine.h
  17.                 Author        :eliteYang
  18.                 Mail        :elite_yang@163.com
  19.                 Desc        :提示信息
  20. ************************************************************************/
  21. #ifndef __LOG_DEFINE_H__
  22. #define __LOG_DEFINE_H__
  23. #define MAX_INFO 1024
  24. #include <stdio.h>
  25. void (*g_fnPrintInfoCallBack)( char* format ) = NULL;
  26. void OutputInfoMessage( char* format )
  27. {
  28.         if ( g_fnPrintInfoCallBack != NULL )
  29.         {
  30.                 char temp[ MAX_INFO ] = { 0 };
  31.                 memset( temp, 0, sizeof( temp ) );
  32.                 va_list list;
  33.                 va_start( list, format );
  34.                 vsprintf_s( temp, sizeof( temp ) - 1, format, list );
  35.                 va_end( list );
  36.                 g_fnPrintInfoCallBack( temp );
  37.         }
  38. }
  39. #endif
  40. /************************************************************************
  41.                         FileName:Crypto.h
  42.                         Author        :eliteYang
  43.                         Mail        :elite_yang@163.com
  44.                         Desc        :Crypto加解密算法实现函数
  45. ************************************************************************/
  46. #ifndef __CRYPTO_H__
  47. #define __CRYPTO_H__
  48. #pragma once
  49. #define MAX_INFO_LENGTH 1024
  50. #include "CryptoDefine.h"
  51. #include <windows.h>
  52. #include <string>
  53. #include <stdio.h>
  54. #include "LogDefine.h"
  55. extern void MyOutputInfoMessage( char* format );
  56. void HandleError( char* s )
  57. {
  58.         char cErrorInfo[ MAX_INFO_LENGTH ];
  59.         memset( cErrorInfo, 0, sizeof( cErrorInfo ) );
  60.         sprintf_s( cErrorInfo, sizeof( cErrorInfo ) - 1, "%s 错误代码:%x 程序终止执行!", s, GetLastError() );
  61.         MyOutputInfoMessage( cErrorInfo );
  62.         exit(1);
  63. }
  64. HCRYPTPROV GetCryptProv()
  65. {
  66.         HCRYPTPROV hCryptProv;
  67.         if ( CryptAcquireContext( &hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0 ) )
  68.         {
  69.                 MyOutputInfoMessage( "加密服务提供者(CSP)句柄获取成功" );
  70.         }
  71.         else
  72.         {
  73.                 if ( !CryptAcquireContext( &hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET ) )
  74.                 {
  75.                         HandleError( "重新建立一个新的密钥集出错!" );
  76.                 }
  77.         }
  78.         return hCryptProv;
  79. }
  80. HCRYPTKEY GetKeyByPassword( HCRYPTPROV hCryptProv,PCHAR szPassword )
  81. {
  82.         HCRYPTKEY hKey;
  83.         HCRYPTHASH hHash;
  84.         if ( CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash ) )
  85.         {
  86.                 MyOutputInfoMessage( "一个Hash句柄已经被创建" );
  87.         }
  88.         else
  89.         {
  90.                 HandleError( "CryptCreateHash 创建Hash句柄失败" );
  91.         }
  92.         if ( CryptHashData( hHash, (BYTE*)szPassword, strlen( szPassword ), 0 ) )
  93.         {
  94.                 MyOutputInfoMessage( "密码已经被添加到了Hash表中" );
  95.         }
  96.         else
  97.         {
  98.                 HandleError( "CryptHashData 计算密码的Hash值失败" );
  99.         }
  100.         // 通过Hash创建值创建会话密钥
  101.         if ( CryptDeriveKey( hCryptProv, ENCRYPT_ALGORITHM, hHash, KEY_LENGTH, &hKey ) )
  102.         {
  103.                 MyOutputInfoMessage( "通过密码的Hash值获得了加密密钥" );
  104.         }
  105.         else
  106.         {
  107.                 HandleError( "CryptDeriveKey 通过Hash值创建会话密钥失败" );
  108.         }
  109.         if ( hHash )
  110.         {
  111.                 if ( !CryptDestroyHash( hHash ) )
  112.                 {
  113.                         HandleError( "CryptDestroyHash 销毁Hash句柄失败" );
  114.                 }
  115.                 else
  116.                 {
  117.                         MyOutputInfoMessage( "释放Hash句柄成功" );
  118.                         hHash = 0;
  119.                 }
  120.         }
  121.         return hKey;
  122. }
  123. HCRYPTKEY GenKeyByRandom( HCRYPTPROV hCryptProv,FILE* hDestination )
  124. {
  125.         HCRYPTKEY hKey;
  126.         HCRYPTKEY hXchgKey;
  127.         PBYTE pbKeyBlob;
  128.         DWORD dwKeyBlobLen;
  129.         if( CryptGenKey( hCryptProv, ENCRYPT_ALGORITHM, KEY_LENGTH | CRYPT_EXPORTABLE, &hKey) )
  130.         {
  131.                 MyOutputInfoMessage( "一个会话密钥已经被创建" );
  132.         }
  133.         else
  134.         {
  135.                 HandleError("CryptGenKey 创建会话密钥失败");
  136.         }
  137.         // 创建交换密钥
  138.         if( CryptGenKey( hCryptProv, AT_KEYEXCHANGE, 0, &hXchgKey ) )
  139.         {
  140.                 MyOutputInfoMessage( "交换密钥对已经创建" );
  141.         }
  142.         else
  143.         {
  144.                 HandleError("在试图创建交换密钥时出错");
  145.         }
  146.         // 确定密钥数据块长度,并分配空间.
  147.         if( CryptExportKey( hKey, hXchgKey,  SIMPLEBLOB, 0, NULL, &dwKeyBlobLen ) )
  148.         {
  149.                 char cInfo[ MAX_INFO_LENGTH ];
  150.                 memset( cInfo, 0, sizeof( cInfo ) );
  151.                 sprintf_s( cInfo, sizeof( cInfo ) - 1, "此密钥块的长度是 %d 字节", dwKeyBlobLen );
  152.                 MyOutputInfoMessage( cInfo );
  153.         }
  154.         else
  155.         {
  156.                 HandleError( "计算密钥数据块长度出错" );
  157.         }
  158.         if (pbKeyBlob =(BYTE *)malloc( dwKeyBlobLen ) )
  159.         {
  160.                 MyOutputInfoMessage( "已经问此密钥块分配了内存" );
  161.         }
  162.         else
  163.         {
  164.                 HandleError("所需内存不够");
  165.         }
  166.         // 导出会话密钥到简单密钥数据块中.
  167.         if( CryptExportKey( hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwKeyBlobLen ) )
  168.         {
  169.                 MyOutputInfoMessage( "此会话密钥已经被导出" );
  170.         }
  171.         else
  172.         {
  173.                 HandleError("CryptExportKey 导出会话密钥到简单密钥数据块中失败");
  174.         }
  175.         //释放交换密钥句柄.
  176.         if( hXchgKey )
  177.         {
  178.                 if(!(CryptDestroyKey(hXchgKey)))
  179.                 {
  180.                         HandleError("CryptDestroyKey 释放交换密钥句柄失败");
  181.                 }
  182.                 else
  183.                         MyOutputInfoMessage( "释放交换密钥句柄成功" );
  184.                 hXchgKey = 0;
  185.         }
  186.         // 写密钥块长度到目标文件.
  187.         fwrite( &dwKeyBlobLen, sizeof(DWORD), 1, hDestination );
  188.         if( ferror( hDestination ) )
  189.         {
  190.                 HandleError("写密钥块长度出错");
  191.         }
  192.         else
  193.         {
  194.                 MyOutputInfoMessage( "密钥块长度已经被写入" );
  195.         }
  196.         //写密钥块数据到目标文件.
  197.         fwrite( pbKeyBlob, 1, dwKeyBlobLen, hDestination );
  198.         if( ferror( hDestination ) )
  199.         {
  200.                 HandleError( "写密钥数据出错" );
  201.         }
  202.         else
  203.         {
  204.                 MyOutputInfoMessage( "此密钥块数据已经被写入目标文件" );
  205.         }
  206.         // 释放内存空间.
  207.         free(pbKeyBlob);
  208.         //返回创建的会话密钥
  209.         return hKey;
  210. }
  211. BOOL MyEncryptFile( char* szSource, char* szDestination, char* szPassword )
  212. {
  213.         FILE *hSource;
  214.         FILE *hDestination;
  215.         HCRYPTPROV hCryptProv;
  216.         HCRYPTKEY hKey;
  217.         PBYTE pbBuffer;
  218.         DWORD dwBlockLen;
  219.         DWORD dwBufferLen;
  220.         DWORD dwCount;
  221.         char cInfo[ MAX_INFO_LENGTH ] = { 0 };
  222.         // 打开原文文件.
  223.         hSource = fopen( szSource,"rb" );
  224.         if ( hSource )
  225.         {
  226.                 memset( cInfo, 0, sizeof( cInfo ) );
  227.                 sprintf_s( cInfo, sizeof( cInfo ) - 1, "原文文件 %s 已经打开", szSource );
  228.                 MyOutputInfoMessage( cInfo );
  229.         }
  230.         else
  231.         {
  232.                 HandleError("打开原文文件出错!");
  233.         }
  234.         // 打开目标文件.
  235.         hDestination = fopen(szDestination,"w+");
  236.         if( hDestination )
  237.         {
  238.                 memset( cInfo, 0, sizeof( cInfo ) );
  239.                 sprintf_s( cInfo, sizeof( cInfo ) - 1, "目标文件 %s 已经打开", szDestination );
  240.                 MyOutputInfoMessage( cInfo );
  241.         }
  242.         else
  243.         {
  244.                 MyOutputInfoMessage( "文件不存在,创建文件" );
  245.         }
  246.         //获取加密服务者句柄
  247.         hCryptProv = GetCryptProv();
  248.         // 创建会话密钥.
  249.         if( !szPassword || strcmp(szPassword,"")==0 )
  250.         {
  251.                 // 当输入密码为空时,则创建随机的加密密钥,并导出创建的密钥保存到文件中.
  252.                 hKey = GenKeyByRandom( hCryptProv, hDestination);
  253.         }
  254.         else
  255.         {
  256.                 hKey = GetKeyByPassword( hCryptProv, szPassword);
  257.         }
  258.         // 因为加密算法按ENCRYPT_BLOCK_SIZE 大小块加密,所以被加密的
  259.         // 数据长度必须是ENCRYPT_BLOCK_SIZE 的整数倍。下面计算一次加密的
  260.         // 数据长度。
  261.         dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
  262.         // 确定加密后密文数据块大小. 若是分组密码模式,则必须有容纳额外块的空间
  263.         if( ENCRYPT_BLOCK_SIZE > 1 )
  264.                 dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
  265.         else
  266.                 dwBufferLen = dwBlockLen;
  267.         // 分配内存空间.
  268.         if( pbBuffer = (BYTE*)malloc( dwBufferLen ) )
  269.         {
  270.                 MyOutputInfoMessage( "已经为缓冲区分配了内存" );
  271.         }
  272.         else
  273.         {
  274.                 HandleError( "所需内存不够" );
  275.         }
  276.         // 循环加密 原文件
  277.         while( !feof(hSource) )
  278.         {
  279.                 // 每次从原文件中读取dwBlockLen字节数据.
  280.                 dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
  281.                 if( ferror(hSource) )
  282.                 {
  283.                         HandleError("读取明文文件出错");
  284.                 }
  285.                 // 加密数据.
  286.                 if( !CryptEncrypt(
  287.                         hKey,                        //密钥
  288.                         0,                                //如果数据同时进行散列和加密,这里传入一个散列对象
  289.                         feof(hSource),        //如果是最后一个被加密的块,输入TRUE.如果不是输入FALSE.
  290.                         //这里通过判断是否到文件尾来决定是否为最后一块。
  291.                         0,                                //保留
  292.                         pbBuffer,                //输入被加密数据,输出加密后的数据
  293.                         &dwCount,                //输入被加密数据实际长度,输出加密后数据长度
  294.                         dwBufferLen))        //pbBuffer的大小。
  295.                 {
  296.                         HandleError("CryptEncrypt 加密失败");
  297.                 }
  298.                 // 把加密后数据写到密文文件中
  299.                 fwrite(pbBuffer, 1, dwCount, hDestination);
  300.                 if( ferror(hDestination) )
  301.                 {
  302.                         HandleError("写入密文时出错");
  303.                 }
  304.         }
  305.         // 关闭文件
  306.         if( hSource )
  307.         {
  308.                 if(fclose(hSource))
  309.                 {
  310.                         HandleError("关闭源文文件出错!");
  311.                 }
  312.         }
  313.         if( hDestination )
  314.         {
  315.                 if(fclose(hDestination))
  316.                 {
  317.                         HandleError("关闭目标文件出错!");
  318.                 }
  319.         }
  320.         // 释放内存空间.
  321.         if(pbBuffer)
  322.                 free(pbBuffer);
  323.         // 销毁会话密钥
  324.         if ( hKey )
  325.         {
  326.                 if( !CryptDestroyKey( hKey ) )
  327.                 {
  328.                         HandleError("CryptDestroyKey 会话密钥失败");
  329.                 }
  330.         }
  331.         // 释放CSP句柄
  332.         if ( hCryptProv )
  333.         {
  334.                 if( !CryptReleaseContext(hCryptProv, 0) )
  335.                 {
  336.                         HandleError("CryptReleaseContext 释放CSP句柄失败");
  337.                 }
  338.         }
  339.         return(TRUE);
  340. }
  341. HCRYPTKEY GenKeyFromFile(HCRYPTPROV hCryptProv,FILE* hSource)
  342. {
  343.         HCRYPTKEY hKey;
  344.         PBYTE pbKeyBlob;
  345.         DWORD dwKeyBlobLen;
  346.         //从密文文件中获取密钥数据块长度,并分配内存空间.
  347.         fread(&dwKeyBlobLen, sizeof(DWORD), 1, hSource);
  348.         if(ferror(hSource) || feof(hSource))
  349.         {
  350.                 HandleError("读取密文文件中密钥数据块长度出错!");
  351.         }
  352.         if(!(pbKeyBlob = (BYTE *)malloc(dwKeyBlobLen)))
  353.         {
  354.                 HandleError("内存分配出错.");
  355.         }
  356.         //--------------------------------------------------------------------
  357.         // 从密文文件中获取密钥数据块
  358.         fread(pbKeyBlob, 1, dwKeyBlobLen, hSource);
  359.         if(ferror(hSource) || feof(hSource))
  360.         {
  361.                 HandleError("读取密文文件中密钥数据块出错!\n");
  362.         }
  363.         //--------------------------------------------------------------------
  364.         // 导入会话密钥到 CSP.
  365.         if(!CryptImportKey(
  366.                 hCryptProv,
  367.                 pbKeyBlob,
  368.                 dwKeyBlobLen,
  369.                 0,
  370.                 0,
  371.                 &hKey))
  372.         {
  373.                 HandleError("Error during CryptImportKey!");
  374.         }
  375.         if(pbKeyBlob)
  376.                 free(pbKeyBlob);
  377.         //返回导出的会话密钥
  378.         return hKey;
  379. }
  380. BOOL MyDecryptFile( char* szSource,        char* szDestination, char* szPassword)
  381. {
  382.         //--------------------------------------------------------------------
  383.         // 局部变量申明与初始化.
  384.         FILE *hSource;
  385.         FILE *hDestination;
  386.         HCRYPTPROV hCryptProv;
  387.         HCRYPTKEY hKey;
  388.         PBYTE pbBuffer;
  389.         DWORD dwBlockLen;
  390.         DWORD dwBufferLen;
  391.         DWORD dwCount;
  392.         BOOL status = FALSE;
  393.         //--------------------------------------------------------------------
  394.         // 打开密文文件.
  395.         if(!(hSource = fopen(szSource,"rb")))
  396.         {
  397.                 HandleError("打开密文文件出错!");
  398.         }
  399.         //--------------------------------------------------------------------
  400.         // 打开目标文件,用于存储解密后的数据.
  401.         hDestination = fopen( szDestination,"w+" );
  402.         if( !hDestination )
  403.         {
  404.                 HandleError("打开明文文件出错!");
  405.         }
  406.         //获取加密服务者句柄
  407.         hCryptProv = GetCryptProv();
  408.         //获取或创建会话密钥
  409.         if(!szPassword|| strcmp(szPassword,"")==0 )
  410.         {
  411.                 //--------------------------------------------------------------------
  412.                 //从密文文件导入保存的会话密钥
  413.                 hKey = GenKeyFromFile( hCryptProv,hSource);
  414.         }
  415.         else
  416.         {
  417.                 //--------------------------------------------------------------------
  418.                 // 通过输入密码重新创建会话密钥.
  419.                 hKey = GetKeyByPassword( hCryptProv, szPassword);
  420.         }
  421.         // 计算一次解密的数据长度,它是ENCRYPT_BLOCK_SIZE 的整数倍
  422.         dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
  423.         dwBufferLen = dwBlockLen;
  424.         //--------------------------------------------------------------------
  425.         // 分配内存空间.
  426.         if(!(pbBuffer = (BYTE *)malloc(dwBufferLen)))
  427.         {
  428.                 HandleError("所需内存不够!\n");
  429.         }
  430.         //--------------------------------------------------------------------
  431.         // 解密密文文件,解密后数据保存在目标文件
  432.         do {
  433.                 //--------------------------------------------------------------------
  434.                 // 每次从密文文件中读取dwBlockLen字节数据.
  435.                 dwCount = fread(
  436.                         pbBuffer,
  437.                         1,
  438.                         dwBlockLen,
  439.                         hSource);
  440.                 if(ferror(hSource))
  441.                 {
  442.                         HandleError("读取密文文件出错!");
  443.                 }
  444.                 //--------------------------------------------------------------------
  445.                 // 解密 数据
  446.                 if(!CryptDecrypt(
  447.                         hKey,
  448.                         0,
  449.                         feof(hSource),
  450.                         0,
  451.                         pbBuffer,
  452.                         &dwCount))
  453.                 {
  454.                         HandleError("Error during CryptDecrypt!");
  455.                 }
  456.                 //--------------------------------------------------------------------
  457.                 // 把解密后的数据写入目标文件中.
  458.                 fwrite(
  459.                         pbBuffer,
  460.                         1,
  461.                         dwCount,
  462.                         hDestination);
  463.                 if(ferror(hDestination))
  464.                 {
  465.                         HandleError("Error writing plaintext!");
  466.                 }
  467.         }         while(!feof(hSource));
  468.         status = TRUE;
  469.         //--------------------------------------------------------------------
  470.         // 关闭文件
  471.         if(hSource)
  472.         {
  473.                 if(fclose(hSource))
  474.                         HandleError("关闭原文件出错");
  475.         }
  476.         if(hDestination)
  477.         {
  478.                 if(fclose(hDestination))
  479.                         HandleError("关闭目标文件出错");
  480.         }
  481.         //--------------------------------------------------------------------
  482.         // 释放内存空间
  483.         if(pbBuffer)
  484.                 free(pbBuffer);
  485.         //--------------------------------------------------------------------
  486.         // 销毁会话密钥
  487.         if(hKey)
  488.         {
  489.                 if(!(CryptDestroyKey(hKey)))
  490.                         HandleError("Error during CryptDestroyKey");
  491.         }
  492.         //--------------------------------------------------------------------
  493.         // 释放CSP句柄
  494.         if(hCryptProv)
  495.         {
  496.                 if(!(CryptReleaseContext(hCryptProv, 0)))
  497.                         HandleError("Error during CryptReleaseContext");
  498.         }
  499.         return status;
  500. } // end Decryptfile
  501. #endif
复制代码
其中MyOutputInfoMessage函数为我自己定义的一个打印Log的函数,在一个ListBox上输出所有的提示信息,不然用MessageBox太恶心了,这点大家可以用别的方式实现,就不贴MFC部分的代码了。
   
本文固定链接: http://www.cppfans.org/985.html | C++爱好者博客™

您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-3-29 00:02 , Processed in 0.025582 second(s), 11 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表