[加密解密]使用CryptoAPI进行文件加密解密——源码
前一篇简单介绍了下CryptoAPI的东西,这篇就将那点代码放出来给大家看看,以作交流参考目的。/************************************************************************
FileName:CryptoDefine.h
Author :eliteYang
Mail :elite_yang@163.com
Desc :加密需要的常量定义
************************************************************************/
#ifndef __CRYPTO_DEFINE_H_
#define __CRYPTO_DEFINE_H_
#include <WinCrypt.h>
#define MY_ENCODING_TYPE ( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING )
#define KEY_LENGTH 0x00800000
#define ENCRYPT_ALGORITHM CALG_RC4
#define ENCRYPT_BLOCK_SIZE 8
#endif
/************************************************************************
FileName:LogDefine.h
Author :eliteYang
Mail :elite_yang@163.com
Desc :提示信息
************************************************************************/
#ifndef __LOG_DEFINE_H__
#define __LOG_DEFINE_H__
#define MAX_INFO 1024
#include <stdio.h>
void (*g_fnPrintInfoCallBack)( char* format ) = NULL;
void OutputInfoMessage( char* format )
{
if ( g_fnPrintInfoCallBack != NULL )
{
char temp[ MAX_INFO ] = { 0 };
memset( temp, 0, sizeof( temp ) );
va_list list;
va_start( list, format );
vsprintf_s( temp, sizeof( temp ) - 1, format, list );
va_end( list );
g_fnPrintInfoCallBack( temp );
}
}
#endif
/************************************************************************
FileName:Crypto.h
Author :eliteYang
Mail :elite_yang@163.com
Desc :Crypto加解密算法实现函数
************************************************************************/
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#pragma once
#define MAX_INFO_LENGTH 1024
#include "CryptoDefine.h"
#include <windows.h>
#include <string>
#include <stdio.h>
#include "LogDefine.h"
extern void MyOutputInfoMessage( char* format );
void HandleError( char* s )
{
char cErrorInfo[ MAX_INFO_LENGTH ];
memset( cErrorInfo, 0, sizeof( cErrorInfo ) );
sprintf_s( cErrorInfo, sizeof( cErrorInfo ) - 1, "%s 错误代码:%x 程序终止执行!", s, GetLastError() );
MyOutputInfoMessage( cErrorInfo );
exit(1);
}
HCRYPTPROV GetCryptProv()
{
HCRYPTPROV hCryptProv;
if ( CryptAcquireContext( &hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0 ) )
{
MyOutputInfoMessage( "加密服务提供者(CSP)句柄获取成功" );
}
else
{
if ( !CryptAcquireContext( &hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET ) )
{
HandleError( "重新建立一个新的密钥集出错!" );
}
}
return hCryptProv;
}
HCRYPTKEY GetKeyByPassword( HCRYPTPROV hCryptProv,PCHAR szPassword )
{
HCRYPTKEY hKey;
HCRYPTHASH hHash;
if ( CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash ) )
{
MyOutputInfoMessage( "一个Hash句柄已经被创建" );
}
else
{
HandleError( "CryptCreateHash 创建Hash句柄失败" );
}
if ( CryptHashData( hHash, (BYTE*)szPassword, strlen( szPassword ), 0 ) )
{
MyOutputInfoMessage( "密码已经被添加到了Hash表中" );
}
else
{
HandleError( "CryptHashData 计算密码的Hash值失败" );
}
// 通过Hash创建值创建会话密钥
if ( CryptDeriveKey( hCryptProv, ENCRYPT_ALGORITHM, hHash, KEY_LENGTH, &hKey ) )
{
MyOutputInfoMessage( "通过密码的Hash值获得了加密密钥" );
}
else
{
HandleError( "CryptDeriveKey 通过Hash值创建会话密钥失败" );
}
if ( hHash )
{
if ( !CryptDestroyHash( hHash ) )
{
HandleError( "CryptDestroyHash 销毁Hash句柄失败" );
}
else
{
MyOutputInfoMessage( "释放Hash句柄成功" );
hHash = 0;
}
}
return hKey;
}
HCRYPTKEY GenKeyByRandom( HCRYPTPROV hCryptProv,FILE* hDestination )
{
HCRYPTKEY hKey;
HCRYPTKEY hXchgKey;
PBYTE pbKeyBlob;
DWORD dwKeyBlobLen;
if( CryptGenKey( hCryptProv, ENCRYPT_ALGORITHM, KEY_LENGTH | CRYPT_EXPORTABLE, &hKey) )
{
MyOutputInfoMessage( "一个会话密钥已经被创建" );
}
else
{
HandleError("CryptGenKey 创建会话密钥失败");
}
// 创建交换密钥
if( CryptGenKey( hCryptProv, AT_KEYEXCHANGE, 0, &hXchgKey ) )
{
MyOutputInfoMessage( "交换密钥对已经创建" );
}
else
{
HandleError("在试图创建交换密钥时出错");
}
// 确定密钥数据块长度,并分配空间.
if( CryptExportKey( hKey, hXchgKey,SIMPLEBLOB, 0, NULL, &dwKeyBlobLen ) )
{
char cInfo[ MAX_INFO_LENGTH ];
memset( cInfo, 0, sizeof( cInfo ) );
sprintf_s( cInfo, sizeof( cInfo ) - 1, "此密钥块的长度是 %d 字节", dwKeyBlobLen );
MyOutputInfoMessage( cInfo );
}
else
{
HandleError( "计算密钥数据块长度出错" );
}
if (pbKeyBlob =(BYTE *)malloc( dwKeyBlobLen ) )
{
MyOutputInfoMessage( "已经问此密钥块分配了内存" );
}
else
{
HandleError("所需内存不够");
}
// 导出会话密钥到简单密钥数据块中.
if( CryptExportKey( hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwKeyBlobLen ) )
{
MyOutputInfoMessage( "此会话密钥已经被导出" );
}
else
{
HandleError("CryptExportKey 导出会话密钥到简单密钥数据块中失败");
}
//释放交换密钥句柄.
if( hXchgKey )
{
if(!(CryptDestroyKey(hXchgKey)))
{
HandleError("CryptDestroyKey 释放交换密钥句柄失败");
}
else
MyOutputInfoMessage( "释放交换密钥句柄成功" );
hXchgKey = 0;
}
// 写密钥块长度到目标文件.
fwrite( &dwKeyBlobLen, sizeof(DWORD), 1, hDestination );
if( ferror( hDestination ) )
{
HandleError("写密钥块长度出错");
}
else
{
MyOutputInfoMessage( "密钥块长度已经被写入" );
}
//写密钥块数据到目标文件.
fwrite( pbKeyBlob, 1, dwKeyBlobLen, hDestination );
if( ferror( hDestination ) )
{
HandleError( "写密钥数据出错" );
}
else
{
MyOutputInfoMessage( "此密钥块数据已经被写入目标文件" );
}
// 释放内存空间.
free(pbKeyBlob);
//返回创建的会话密钥
return hKey;
}
BOOL MyEncryptFile( char* szSource, char* szDestination, char* szPassword )
{
FILE *hSource;
FILE *hDestination;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
PBYTE pbBuffer;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
char cInfo[ MAX_INFO_LENGTH ] = { 0 };
// 打开原文文件.
hSource = fopen( szSource,"rb" );
if ( hSource )
{
memset( cInfo, 0, sizeof( cInfo ) );
sprintf_s( cInfo, sizeof( cInfo ) - 1, "原文文件 %s 已经打开", szSource );
MyOutputInfoMessage( cInfo );
}
else
{
HandleError("打开原文文件出错!");
}
// 打开目标文件.
hDestination = fopen(szDestination,"w+");
if( hDestination )
{
memset( cInfo, 0, sizeof( cInfo ) );
sprintf_s( cInfo, sizeof( cInfo ) - 1, "目标文件 %s 已经打开", szDestination );
MyOutputInfoMessage( cInfo );
}
else
{
MyOutputInfoMessage( "文件不存在,创建文件" );
}
//获取加密服务者句柄
hCryptProv = GetCryptProv();
// 创建会话密钥.
if( !szPassword || strcmp(szPassword,"")==0 )
{
// 当输入密码为空时,则创建随机的加密密钥,并导出创建的密钥保存到文件中.
hKey = GenKeyByRandom( hCryptProv, hDestination);
}
else
{
hKey = GetKeyByPassword( hCryptProv, szPassword);
}
// 因为加密算法按ENCRYPT_BLOCK_SIZE 大小块加密,所以被加密的
// 数据长度必须是ENCRYPT_BLOCK_SIZE 的整数倍。下面计算一次加密的
// 数据长度。
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
// 确定加密后密文数据块大小. 若是分组密码模式,则必须有容纳额外块的空间
if( ENCRYPT_BLOCK_SIZE > 1 )
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
else
dwBufferLen = dwBlockLen;
// 分配内存空间.
if( pbBuffer = (BYTE*)malloc( dwBufferLen ) )
{
MyOutputInfoMessage( "已经为缓冲区分配了内存" );
}
else
{
HandleError( "所需内存不够" );
}
// 循环加密 原文件
while( !feof(hSource) )
{
// 每次从原文件中读取dwBlockLen字节数据.
dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
if( ferror(hSource) )
{
HandleError("读取明文文件出错");
}
// 加密数据.
if( !CryptEncrypt(
hKey, //密钥
0, //如果数据同时进行散列和加密,这里传入一个散列对象
feof(hSource), //如果是最后一个被加密的块,输入TRUE.如果不是输入FALSE.
//这里通过判断是否到文件尾来决定是否为最后一块。
0, //保留
pbBuffer, //输入被加密数据,输出加密后的数据
&dwCount, //输入被加密数据实际长度,输出加密后数据长度
dwBufferLen)) //pbBuffer的大小。
{
HandleError("CryptEncrypt 加密失败");
}
// 把加密后数据写到密文文件中
fwrite(pbBuffer, 1, dwCount, hDestination);
if( ferror(hDestination) )
{
HandleError("写入密文时出错");
}
}
// 关闭文件
if( hSource )
{
if(fclose(hSource))
{
HandleError("关闭源文文件出错!");
}
}
if( hDestination )
{
if(fclose(hDestination))
{
HandleError("关闭目标文件出错!");
}
}
// 释放内存空间.
if(pbBuffer)
free(pbBuffer);
// 销毁会话密钥
if ( hKey )
{
if( !CryptDestroyKey( hKey ) )
{
HandleError("CryptDestroyKey 会话密钥失败");
}
}
// 释放CSP句柄
if ( hCryptProv )
{
if( !CryptReleaseContext(hCryptProv, 0) )
{
HandleError("CryptReleaseContext 释放CSP句柄失败");
}
}
return(TRUE);
}
HCRYPTKEY GenKeyFromFile(HCRYPTPROV hCryptProv,FILE* hSource)
{
HCRYPTKEY hKey;
PBYTE pbKeyBlob;
DWORD dwKeyBlobLen;
//从密文文件中获取密钥数据块长度,并分配内存空间.
fread(&dwKeyBlobLen, sizeof(DWORD), 1, hSource);
if(ferror(hSource) || feof(hSource))
{
HandleError("读取密文文件中密钥数据块长度出错!");
}
if(!(pbKeyBlob = (BYTE *)malloc(dwKeyBlobLen)))
{
HandleError("内存分配出错.");
}
//--------------------------------------------------------------------
// 从密文文件中获取密钥数据块
fread(pbKeyBlob, 1, dwKeyBlobLen, hSource);
if(ferror(hSource) || feof(hSource))
{
HandleError("读取密文文件中密钥数据块出错!\n");
}
//--------------------------------------------------------------------
// 导入会话密钥到 CSP.
if(!CryptImportKey(
hCryptProv,
pbKeyBlob,
dwKeyBlobLen,
0,
0,
&hKey))
{
HandleError("Error during CryptImportKey!");
}
if(pbKeyBlob)
free(pbKeyBlob);
//返回导出的会话密钥
return hKey;
}
BOOL MyDecryptFile( char* szSource, char* szDestination, char* szPassword)
{
//--------------------------------------------------------------------
// 局部变量申明与初始化.
FILE *hSource;
FILE *hDestination;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
PBYTE pbBuffer;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
BOOL status = FALSE;
//--------------------------------------------------------------------
// 打开密文文件.
if(!(hSource = fopen(szSource,"rb")))
{
HandleError("打开密文文件出错!");
}
//--------------------------------------------------------------------
// 打开目标文件,用于存储解密后的数据.
hDestination = fopen( szDestination,"w+" );
if( !hDestination )
{
HandleError("打开明文文件出错!");
}
//获取加密服务者句柄
hCryptProv = GetCryptProv();
//获取或创建会话密钥
if(!szPassword|| strcmp(szPassword,"")==0 )
{
//--------------------------------------------------------------------
//从密文文件导入保存的会话密钥
hKey = GenKeyFromFile( hCryptProv,hSource);
}
else
{
//--------------------------------------------------------------------
// 通过输入密码重新创建会话密钥.
hKey = GetKeyByPassword( hCryptProv, szPassword);
}
// 计算一次解密的数据长度,它是ENCRYPT_BLOCK_SIZE 的整数倍
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
dwBufferLen = dwBlockLen;
//--------------------------------------------------------------------
// 分配内存空间.
if(!(pbBuffer = (BYTE *)malloc(dwBufferLen)))
{
HandleError("所需内存不够!\n");
}
//--------------------------------------------------------------------
// 解密密文文件,解密后数据保存在目标文件
do {
//--------------------------------------------------------------------
// 每次从密文文件中读取dwBlockLen字节数据.
dwCount = fread(
pbBuffer,
1,
dwBlockLen,
hSource);
if(ferror(hSource))
{
HandleError("读取密文文件出错!");
}
//--------------------------------------------------------------------
// 解密 数据
if(!CryptDecrypt(
hKey,
0,
feof(hSource),
0,
pbBuffer,
&dwCount))
{
HandleError("Error during CryptDecrypt!");
}
//--------------------------------------------------------------------
// 把解密后的数据写入目标文件中.
fwrite(
pbBuffer,
1,
dwCount,
hDestination);
if(ferror(hDestination))
{
HandleError("Error writing plaintext!");
}
} while(!feof(hSource));
status = TRUE;
//--------------------------------------------------------------------
// 关闭文件
if(hSource)
{
if(fclose(hSource))
HandleError("关闭原文件出错");
}
if(hDestination)
{
if(fclose(hDestination))
HandleError("关闭目标文件出错");
}
//--------------------------------------------------------------------
// 释放内存空间
if(pbBuffer)
free(pbBuffer);
//--------------------------------------------------------------------
// 销毁会话密钥
if(hKey)
{
if(!(CryptDestroyKey(hKey)))
HandleError("Error during CryptDestroyKey");
}
//--------------------------------------------------------------------
// 释放CSP句柄
if(hCryptProv)
{
if(!(CryptReleaseContext(hCryptProv, 0)))
HandleError("Error during CryptReleaseContext");
}
return status;
} // end Decryptfile
#endif
其中MyOutputInfoMessage函数为我自己定义的一个打印Log的函数,在一个ListBox上输出所有的提示信息,不然用MessageBox太恶心了,这点大家可以用别的方式实现,就不贴MFC部分的代码了。
本文固定链接: http://www.cppfans.org/985.html | C++爱好者博客™
页:
[1]