⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 evp.cpp

📁 MiniCA V2.0版本源码。《小型CA系统V2.1含源码》发表以来
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// Evp.cpp: implementation of the CEvp class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "minica.h"
#include "Evp.h"
#include <io.h>
#include "CertKey.h"
#include "rc.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CProgressCtrlST *  CEvp::m_pProgress = NULL;
const UINT BUFLEN = 1024;
const float HUNDRED = 100.0;
CEvp::CEvp()
{

}

CEvp::~CEvp()
{

}

//函数功能:对称加解密
//参数:		[in] cpName - 算法名称
//			[in] inStream - 输入文件或内存区域
//			[in] inLen - 输入长度,0->标示输入为文件
//			[in] outStream - 输出为文件名或内存区域
//			[in,out] outLen - 输入为结果内存长度,输出为实际加密结果长度
//			[in] char * pwd - 用于初始iv的密码
//			[in] type - 1-加密、0-解密
//			[out] outMsg - 输出信息
BOOL CEvp::Crypt(const char * cpName, const char * inStream, UINT inLen, 
		   char * outStream, UINT & outLen, char * pwd, const int type,
		   char * outMsg)
{
	unsigned char inbuf[BUFLEN]="";
	unsigned char outbuf[BUFLEN + EVP_MAX_BLOCK_LENGTH]="";//所有算法最长的块长度。
	unsigned char key[EVP_MAX_KEY_LENGTH]="";//算法最长的KEY长度
    unsigned char iv[EVP_MAX_IV_LENGTH]="";//算法最长的IV长度
	int infilelen=0, outlen=0;
	BOOL ret=true;
	const EVP_CIPHER *cipher=NULL;
	EVP_CIPHER_CTX ctx;
	memset(&ctx,0,sizeof(ctx));
	long fileLen=0;//文件长度
	long finishLen=0;//完成长度
	int uMaxMem = outLen;	//可能为负数,不能用UINT
	outLen = 0;
	UINT len = 0;

	FILE * outfd=NULL,* infd=NULL;
	
	if(inLen==0&&(strlen(inStream)==0||strlen(outStream)==0))
	{
		strcpy(outMsg,"NO specify input or output file");
		return FALSE;
	}
	
	if(inLen==0)//文件
	{
		if ((infd = fopen (inStream, "rb")) == NULL)//原文
		{
			strcpy(outMsg,"open input file error");
			return FALSE;
		}
		fileLen = filelength(fileno(infd));//得到文件长度
		if ((outfd = fopen (outStream, "wb")) == NULL)//密文
		{
			strcpy(outMsg,"open output file error");
			fclose(infd);
			return FALSE;
		}
	}
	
	OpenSSL_add_all_algorithms();//add digests   and ciphers
	cipher=EVP_get_cipherbyname(cpName);
	if(cipher==NULL)
	{
		sprintf(outMsg,"Unknown cipher name %s\n",cpName);
		ret=FALSE;
		goto err;
	}
	
	//表示產生的 key 是給哪一種 cipher 用的
	//過程中所使用的 hash 演算法,
	//用來加密的 salt,至少為八個 bytes,否則必須NULL,
	//重覆幾次 hashing 的動作,愈多次愈花時間,但相對地也愈安全
	if(!EVP_BytesToKey(cipher,EVP_md5(),NULL,(unsigned char *)pwd,
		strlen(pwd),1,key,iv))
	{
		strcpy(outMsg,"Crypt初始化key or iv 失败");
		ret=FALSE;
		goto err;
	}
	
	EVP_CIPHER_CTX_init(&ctx);//初始化一个EVP_CIPHER_CTX结构体
	
	//type为1,则加密;如果type为0,则解密;如果type是-1,则不改变数据
	if(!EVP_CipherInit_ex(&ctx, cipher, NULL/*NULL使用缺省的实现算法*/,key,iv,type))//初始化
	{
		strcpy(outMsg,"Crypt初始化加解密结构体失败");
		ret=FALSE;
		goto err;		
	}
	
	//该函数进行加密算法结构EVP_CIPHER_CTX密钥长度的设置。
	//如果算法是一个密钥长度固定的算法,
	//那么如果设置的密钥长度跟它固定的长度不一致,就会产生错误。
	//	EVP_CIPHER_CTX_set_key_length(&ctx, 10); 		
	//	EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, type);
	if(inLen==0)//文件
	{
		for(;;)
		{                       
			infilelen = fread(inbuf, sizeof(char), BUFLEN, infd);
			if(infilelen <= 0) break;
			if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, infilelen))//中間過程 
			{
				strcpy(outMsg,"Crypt中间过程错误");
				ret=FALSE;
				goto err;
			}
			fwrite(outbuf, sizeof(char), outlen, outfd);
			finishLen+=infilelen;
			DrawProg(finishLen*HUNDRED/fileLen);
		}               
		if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))    //最終步驟-处理最后(Final)的一段数据
		{                       
			strcpy(outMsg,"Crypt最终过程错误"); 
			ret=FALSE;
			goto err;
		}               
		fwrite(outbuf, sizeof(char), outlen, outfd);
	}
	else//内存
	{
		fileLen = inLen;
		
		for(UINT i=0;;i++)
		{
			//每次1024
			len=(inLen>BUFLEN)?BUFLEN:inLen;
			inLen-=len;
			if(!EVP_CipherUpdate(&ctx, outbuf, &outlen,(UCHAR *)(inStream+i*BUFLEN), len))//中間過程
			{
				strcpy(outMsg,"Crypt中间过程错误");
				ret=FALSE;
				goto err;
			}
			//计算缓冲区长度是否能容纳结果数据集
			uMaxMem -= outlen;
			if(uMaxMem < 0)
			{
				strcpy(outMsg,"输出缓冲过小,不能容纳操作结果"); 
				ret = FALSE;
				goto err;
			}

			memcpy(outStream + outLen, outbuf, outlen);//拷贝到调用函数
			outLen+=outlen;
			if(inLen <= 0) break;          
		}		

		if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen)) //最終步驟-处理最后(Final)的一段数据
		{   
			strcpy(outMsg,"Crypt最终过程错误"); 
			ret=FALSE;
			goto err;
		}               
	
		uMaxMem -= outlen;
		if(uMaxMem < 0)
		{
			strcpy(outMsg,"输出缓冲过小,不能容纳操作结果"); 
			ret = FALSE;
			goto err;
		}
		memcpy(outStream + outLen,outbuf,outlen);//拷贝到调用函数		
		outLen += outlen;
		
	}
err:
	if(infd!=NULL)
		fclose(infd);
	if(outfd!=NULL)
		fclose(outfd);
	if(ctx.cipher) EVP_CIPHER_CTX_cleanup(&ctx); //清除所有信息释放内存
	EVP_cleanup();//frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
	return ret;
}

/*消息摘要*/ 
BOOL CEvp::Digest(const char * mdname/*摘要算法*/,const char * infoin/*输入,文件或内存*/,
			UINT inlen/*文件时候为0,内存为长度*/,unsigned char * md_value/*返回摘要*/,
			unsigned int * md_len/*摘要长度*/, char * outMsg)
{

const EVP_MD *md=NULL;
	char inbuf[BUFLEN]="";
	UINT len=0;
	BOOL ret=true;
	EVP_MD_CTX md_ctx;
	memset(&md_ctx,0,sizeof(md_ctx));
	FILE * infd=NULL;
	long fileLen=0;//文件长度
	long finishLen=0;//完成长度
	
	if(strlen(infoin)==0)
	{
		strcpy(outMsg,"NO specify input");
		return FALSE;
	}
	
	if(inlen==0)//输入为文件
	{
		if ((infd = fopen (infoin, "rb")) == NULL)//原文
		{
			strcpy(outMsg,"open input file error");
			return FALSE;
		}
		fileLen=filelength(fileno(infd));//得到文件长度
	}

	
	//使EVP_Digest系列函数支持所有有效的信息摘要算法
	OpenSSL_add_all_digests();
    
	//根据输入的信息摘要函数的名字得到相应的EVP_MD算法结构
	md = EVP_get_digestbyname(mdname);  
	if(!md) 
	{
		sprintf(outMsg,"Unknown message digest %s",mdname);
		ret=FALSE;
		goto err;
	}
	//初始化信息摘要结构md_ctx。
	EVP_MD_CTX_init(&md_ctx);
	
	//使用md的算法结构设置mdctx结构,impl为NULL,即使用缺省实现的算法(openssl本身提供的信息摘要算法)
	if(!EVP_DigestInit_ex(&md_ctx, md, NULL/*impl*/))
	{
		strcpy(outMsg,"Digest初始化算法结构错误");
		ret=FALSE;
		goto err;
	}
	
	//信息摘要运算
	if(inlen==0)//输入为文件
	{
		for(;;)
		{
			len = fread(inbuf, 1, BUFLEN, infd);
			if(len <= 0) break;          
			if(!EVP_DigestUpdate(&md_ctx, inbuf, len))
			{
				strcpy(outMsg,"Digest中间过程错误");
				ret=FALSE;
				goto err;
			}
			finishLen+=len;
			DrawProg(finishLen * HUNDRED / fileLen);
		}
	}
	else//内存区域
	{
		for(UINT i=0;;i++)
		{
			//每次BUFLEN
			len=(inlen>BUFLEN)?BUFLEN:inlen;
			inlen-=len;
			if(!EVP_DigestUpdate(&md_ctx, (infoin+i*BUFLEN), len))
			{
				strcpy(outMsg,"Digest中间过程错误");
				ret=FALSE;
				goto err;
			}
			if(inlen <= 0) break;          
		}		
	}
	//完成信息摘要计算过程,将完成的摘要信息存储在md_value里面,长度信息存储在md_len里面
	if(!EVP_DigestFinal_ex(&md_ctx, md_value, md_len))
	{	
		strcpy(outMsg,"Digest最终过程错误");
		ret=FALSE;
	}
	
err:
	//使用该函数释放mdctx占用的资源,如果使用_ex系列函数,这是必须调用的。
	if(infd!=NULL)
		fclose(infd);
	if(md_ctx.digest) EVP_MD_CTX_cleanup(&md_ctx);
	EVP_cleanup();
	return ret;
}

/*数字签名*/
BOOL CEvp::Sign(const char * key/*私钥*/,const int keylen/*0-内存私钥*/,const char * pwd,
				const char * mdname/*签名算法*/,const char * infoin/*输入文件*/,
				int inlen,/*输入长度,0->内存*/char * infout/*输出*/,
				UINT & outlen/*输出长度,输入文件时=0*/,char * outMsg)
{
	BOOL ret=true;
	unsigned char * sig_buf=NULL;
	unsigned int sig_len,len=0;
	unsigned char inbuf[BUFLEN]="";
	EVP_PKEY * pkey=NULL;
	const EVP_MD *md=NULL;
	EVP_MD_CTX md_ctx;
	memset(&md_ctx,0,sizeof(md_ctx));
	BIO *in=NULL;
	FILE * outfd=NULL,* infd=NULL;
	long fileLen=0;//文件长度
	long finishLen=0;//完成长度

	BOOL bType=inlen;

	if(bType==0&&(strlen(infoin)==0||strlen(infout)==0))//输入文件时候
	{
		strcpy(outMsg,"NO specify input or output file");
		return FALSE;
	}
	if(bType==0)//文件
	{
		if ((infd = fopen (infoin, "rb")) == NULL)//原文
		{
			strcpy(outMsg,"open input file error");
			return FALSE;
		}
		if ((outfd = fopen (infout, "wb")) == NULL)//密文
		{
			strcpy(outMsg,"open output file error");
			fclose(infd);
			return FALSE;
		}
		fileLen=filelength(fileno(infd));//得到文件长度
	}
	
	OpenSSL_add_all_digests();
	
	pkey = CCertKey::LoadKey((char *)key,keylen,(char *)pwd,outMsg);
	if (pkey == NULL)
	{ 
		ret=FALSE;
		goto err;
	}
	
	/* Do the signature */
	md = EVP_get_digestbyname(mdname);
	if(!md)
	{
		sprintf(outMsg,"Unknown message digest %s",mdname);
		ret=FALSE;
		goto err;
	}
	EVP_MD_CTX_init(&md_ctx);
	if(!EVP_SignInit_ex(&md_ctx,md,NULL))
	{
		strcpy(outMsg,"初始化算法结构出错");
		ret=FALSE;
		goto err;
	}

	if(bType==0)//文件
	{	
		for(;;)
		{
			len = fread(inbuf, sizeof(char), BUFLEN, infd);
			if(len <= 0) break;
			if(!EVP_SignUpdate(&md_ctx, inbuf, len))
			{
				sprintf(outMsg,"中间过程出错");
				ret=FALSE;
				goto err;
			}
			finishLen+=len;
			DrawProg(finishLen*HUNDRED/fileLen);
		}
	}

	else//内存区域
	{
		for(UINT i=0;;i++)
		{
			//每次BUFLEN
			len=(inlen>BUFLEN)?BUFLEN:inlen;
			inlen-=len;
			if(!EVP_SignUpdate(&md_ctx, (infoin+i*BUFLEN), len))
			{
				strcpy(outMsg,"中间过程错误");
				ret=FALSE;
				goto err;
			}
			if(inlen <= 0) break;          
		}		
	}

	sig_len =EVP_PKEY_size(pkey);
	sig_buf=new unsigned char[sig_len];
	
	// 簽名後的結果,必須是個夠大視 private key 長度不同而不同,可以 EVP_PKEY_size() 取得
	if(!EVP_SignFinal (&md_ctx, sig_buf, &sig_len, pkey))
	{
		sprintf(outMsg,"最终过程出错");
		ret=FALSE;
	}
	else if(bType!=0)//内存
	{
		memcpy(infout,sig_buf,sig_len);
		outlen=sig_len;
	}

	if(outfd!=NULL)
	{
		fwrite(sig_buf,sizeof(char),sig_len,outfd);
		outlen=0;
	}
	
err:
	if(infd!=NULL)
		fclose(infd);
	if(outfd!=NULL)
		fclose(outfd);
	BIO_free(in);
	
	if(pkey) EVP_PKEY_free (pkey);
	if(md_ctx.digest) EVP_MD_CTX_cleanup(&md_ctx);
	delete [] sig_buf;
	EVP_cleanup();
	return ret;
}

/*数字签名验证*/
BOOL CEvp::VerifySign(const char * cert/*公钥*/,const int certlen,
					  const char * pwd,const char * mdname/*签名算法*/,
					  const char * infoin,/*原始信息*/ 
					  int inlen/*输入长度0->文件*/,char * sign/*签名结果*/,
					  char * outMsg)
{
	const EVP_MD *md=NULL;
	unsigned char inbuf[BUFLEN]="";
	BOOL ret=true;
	unsigned char * sig_buf=NULL;
	unsigned int sig_len,len=0;
	FILE * outfd=NULL,* infd=NULL;
	long fileLen=0;//文件长度
	long finishLen=0;//完成长度
	X509 *	x509=NULL;
	EVP_PKEY * pcert=NULL;
	EVP_MD_CTX md_ctx;
	memset(&md_ctx,0,sizeof(md_ctx));
	
	BOOL bType=inlen;

	if(bType==0&&(strlen(infoin)==0||strlen(sign)==0))//输入文件时候
	{
		strcpy(outMsg,"NO specify input file");
		return FALSE;
	}
	if(bType==0)//内存
	{
		if ((infd = fopen (infoin, "rb")) == NULL)//原文
		{
			strcpy(outMsg,"open input file error");
			return FALSE;
		}
		if ((outfd = fopen (sign, "rb")) == NULL)//密文
		{
			strcpy(outMsg,"open output file error");
			fclose(infd);
			return FALSE;
		}
		fileLen=filelength(fileno(infd));//得到文件长度
	}

	OpenSSL_add_all_digests();
	x509 = CCertKey::LoadCert((char *)cert,certlen,(char *)pwd,outMsg);
	if (x509 == NULL)
	{
		ret=FALSE;
		goto err;
	}
	pcert=X509_get_pubkey(x509);
	if (pcert == NULL)
	{
		sprintf(outMsg,"Read Public Key Failed!");
		ret=FALSE;
		goto err;
	}
	
	md = EVP_get_digestbyname(mdname);  
	if(!md) 
	{
		sprintf(outMsg,"Unknown message digest %s",mdname);
		ret=FALSE;
		goto err;
	}
	
	EVP_MD_CTX_init(&md_ctx);	
	if(!EVP_VerifyInit_ex(&md_ctx,md,NULL))
	{
		strcpy(outMsg,"初始化算法结构出错");
		ret=FALSE;
		goto err;
	}

	if(bType==0)//文件
	{		
		for(;;)
		{
			len = fread(inbuf, sizeof(char), BUFLEN, infd);                  
			if(len <= 0) break;
			if(!EVP_VerifyUpdate (&md_ctx, inbuf, len))
			{
				strcpy(outMsg,"中间过程出错");
				ret=FALSE;
				goto err;
			}
			finishLen+=len;
			DrawProg(finishLen*HUNDRED/fileLen);
		}
	}	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -