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

📄 evp.cpp

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

    if (!(rsa = EVP_PKEY_get1_RSA(pcert)))
	{
		sprintf(OperMsg,"取得RSA密钥失败");
		ret=FALSE;
		goto err;
    }
	iblock_size = BN_num_bytes(rsa->n);//预解密长度128
	oblock_size = BN_num_bytes(rsa->n) - 11;//解密后长度117
	bufin=new unsigned char[iblock_size];
	bufout=new unsigned char[oblock_size];
	if(nInlen==0)//文件
	{	
		for(;;)
		{
			inlen = fread(bufin,sizeof(char),iblock_size,infd);
			if(!inlen)
				break;
			outlen = RSA_public_decrypt(inlen,bufin,bufout,rsa,RSA_PKCS1_PADDING);
			if (outlen == -1)//加密后资料长度
			{
				sprintf(OperMsg,"RSA解密失败");
				ret=FALSE;
				goto err;
			}
			if(bOutType)
			{
				fwrite(bufout,sizeof(char),outlen,outfd);
				memset(bufout,0,oblock_size);
			}
			else
			{
				uMaxMem -= outlen;	//剩余缓冲大小
				if(uMaxMem < 0)
				{
					strcpy(OperMsg, "输出缓冲过小,不能容纳操作结果"); 
					ret = FALSE;
					goto err;
				}
				memcpy(pOutStream + memtemplen,bufout,outlen);//拷贝到调用函数
				memtemplen += outlen;
			}
			finishLen += inlen;
			DrawProg(finishLen*HUNDRED/fileLen);
		}
		nOutlen = memtemplen;
	}

	else//内存区域
	{
		for(UINT i=0;;i++)
		{
			//每次 iblock_size 或实际长度
			len = (nInlen>iblock_size)?iblock_size:nInlen;//内存区域长度
			nInlen -= len;
			outlen = RSA_public_decrypt(len,(UCHAR *)(pInStream+i*iblock_size),bufout,rsa,RSA_PKCS1_PADDING);
			if (outlen == -1)//加密后资料长度
			{
				sprintf(OperMsg,"RSA解密失败");
				ret = FALSE;
				goto err;
			}
			if(bOutType)
			{
				fwrite(bufout,sizeof(char),outlen,outfd);
				memset(bufout,0,outlen);
			}
			else
			{
				uMaxMem -= outlen;	//剩余缓冲大小
				if(uMaxMem < 0)
				{
					strcpy(OperMsg, "输出缓冲过小,不能容纳操作结果"); 
					ret = FALSE;
					goto err;
				}
				memcpy(pOutStream + memtemplen,bufout,outlen);//拷贝到调用函数
				memtemplen += outlen;
			}
			finishLen += len;
			DrawProg(finishLen*HUNDRED/fileLen);
			if(nInlen <= 0) break;     

		}	
		nOutlen = memtemplen;
	}
err:
	if(infd!=NULL)
		fclose(infd);
	if(outfd!=NULL)
		fclose(outfd);
	if(pcert) EVP_PKEY_free(pcert);
    if(x509) X509_free(x509);
	if(rsa) RSA_free(rsa);
	delete [] bufin;
	delete [] bufout;
	return ret;

}

void CEvp::DrawProg(float fPot)
{
	if(m_pProgress)
		m_pProgress->SetPos((int)fPot);
}

void CEvp::SetProgRess(CProgressCtrlST *pProgress)
{
	m_pProgress = pProgress;
}

//功能:得到加密后缓冲区大小
//参数:
//		pCertBuf [in] - 公钥
//		nCertLen [in] - 公钥长度
//		nInlen   [in] - 数据长度
//返回值:输出缓冲区大小 -1 标示函数操作失败
DWORD CEvp::GetEncLen(const char * pCertBuf, const UINT nCertLen, const DWORD nInlen)
{
	X509 * x509 = NULL;
	EVP_PKEY * pcert = NULL;
	RSA * rsa = NULL;
	DWORD len = 0;
	UINT iblock_size = 0, //输入块长度
		oblock_size = 0; //输出块长度
	UINT uMultiple = 0;//输入是块长度的倍数,用于计算输出
	char OperMsg[100] = {0};
	x509 = CCertKey::LoadCert((char *)pCertBuf,nCertLen,"",OperMsg);
	if (x509 == NULL)
	{
		len = -1;
		goto err;
	}
	pcert = X509_get_pubkey(x509);
	if(pcert==NULL)
	{
		sprintf(OperMsg,"取得公钥密钥失败");
		len = -1;
		goto err;
	}

    if (!(rsa = EVP_PKEY_get1_RSA(pcert)))
	{
		sprintf(OperMsg,"取得RSA密钥失败");
		len = 0;
		goto err;
    }

	iblock_size = BN_num_bytes(rsa->n) - 11;//预加密长度,117
	oblock_size = BN_num_bytes(rsa->n);//加密后长度,128

	if(nInlen%iblock_size == 0)//正好整除
		uMultiple = nInlen/iblock_size;
	else
		uMultiple = nInlen/iblock_size + 1;

	len = (nInlen > iblock_size) ? (uMultiple * oblock_size) : oblock_size;//内存区域长度

err:
	if(pcert) EVP_PKEY_free(pcert);
    if(x509) X509_free(x509);
	if(rsa) RSA_free(rsa);
	return len;
}

//目录部分


//功能:初始化对称加密结构
//支持目录加密
//返回值 : 成功TRUE
//		   失败FALSE
//参数 : 
//			strCpName - 算法名称
//			strPwd - 密钥
//			type - 类型 1 - 加密; 0 - 解密
//			Ctx - 返回加密信息体
//调用时机: 加密前
BOOL CEvp::InitCrypt2(const CString strCpName, CString strPwd, const int type, EVP_CIPHER_CTX & Ctx)
{
	const EVP_CIPHER * cipher=NULL;
	unsigned char key[EVP_MAX_KEY_LENGTH]="";//算法最长的KEY长度
    unsigned char iv[EVP_MAX_IV_LENGTH]="";//算法最长的IV长度
	OpenSSL_add_all_algorithms();//add digests   and ciphers
	
	cipher = EVP_get_cipherbyname(strCpName);
	if(cipher==NULL)
	{
//		sprintf(outMsg,"Unknown cipher name %s\n",cpname);
		return FALSE;
	}
	
	//表示產生的 key 是給哪一種 cipher 用的
	//過程中所使用的 hash 演算法,
	//用來加密的 salt,至少為八個 bytes,否則必須NULL,
	//重覆幾次 hashing 的動作,愈多次愈花時間,但相對地也愈安全

	if(!EVP_BytesToKey(cipher,EVP_md5(),NULL,(unsigned char *)strPwd.GetBuffer(0),
		strPwd.GetLength(),1,key,iv))
	{
//		strcpy(outMsg,"Crypt初始化key or iv 失败");
		return FALSE;
	}
	
	//EVP_CIPHER_CTX Ctx;
	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初始化加解密结构体失败");
		return FALSE;
	}
	EVP_cleanup();//frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
	return TRUE;

}

//功能:清除对称加密结构
//调用:加密完毕后
void CEvp::CleanCrypt2(EVP_CIPHER_CTX & Ctx)
{
	if(Ctx.cipher) 
		EVP_CIPHER_CTX_cleanup(&Ctx); //清除所有信息释放内存
	CRYPTO_cleanup_all_ex_data();
}

//返回值 : 加密时候返回加密后文件大小
//		   解密时候返回解密后文件大小
//参数 : 
//			pCtx - 已经初始化的加密信息体
//			strFileName - 加密为要加密的文件名,解密为解密后保存的文件名
//			File - 文件指针 ,具体位置的偏移有调用者负责
//			dBolckLen - 块长度,块标示某个文件加密后的内容,只在解密时候有效,可以解密某个文件
//						 加密时候无效,为0
//			outStr - 返回错误信息
DWORD CEvp::Crypt2(EVP_CIPHER_CTX * pCtx, const CString & strFileName,
					CFile & File, DWORD dBolckLen, CString & outStr)	   
{
	if(File.m_hFile == CFile::hFileNull)
		return -1;

	unsigned char inbuf[BUFLEN] = "";
	unsigned char outbuf[BUFLEN + EVP_MAX_BLOCK_LENGTH] = "";//所有算法最长的块长度。
	int infilelen = 0,
		outlen=0;
	BOOL ret = true;
	DWORD dFileLen = 0;//文件长度
	DWORD dFinishLen = 0;//完成长度
	long lReadLen = 0; //每次读取的块长度
	DWORD dReturnLen = 0;//返回加解密结果长度

	CFile inSideFile;//内部文件
	if(0 == dBolckLen)//块长度为0标示要加密
	{
		if(!inSideFile.Open(strFileName, CFile::modeRead | CFile::typeBinary))
		{
			outStr.Format("打开文件%s失败", strFileName);
			return -1;
		}

		dFileLen = inSideFile.GetLength();

		for(;;)
		{                       
			infilelen = inSideFile.Read(inbuf, BUFLEN);
			if(infilelen <= 0) break;
			if(!EVP_CipherUpdate(pCtx, outbuf, &outlen, inbuf, infilelen))//中間過程 
			{
				/* Error */              
				outStr = "Crypt中间过程错误";
				ret = FALSE;
				goto err;
			}
			File.Write(outbuf, outlen);
			dFinishLen += infilelen;
			dReturnLen += outlen;
			DrawProg(dFinishLen*HUNDRED/dFileLen);
		} 

		if(!EVP_CipherFinal_ex(pCtx, outbuf, &outlen))    //最終步驟-处理最后(Final)的一段数据
		{   /* Error */                       
			outStr = "Crypt最终过程错误"; 
			ret = FALSE;
			goto err;
		}               
		File.Write(outbuf, outlen);

	}
	else	//解密
	{
		if(!inSideFile.Open(strFileName, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary))
		{
			outStr.Format("创建文件%s失败", strFileName);
			return -1;
		}

		dFileLen = dBolckLen;

		for(;;)
		{
			//每次 iblock_size 或实际长度
			lReadLen = (dBolckLen > BUFLEN) ? BUFLEN:dBolckLen;//内存区域长度
			infilelen = File.Read(inbuf, lReadLen);
			if(0 == infilelen)
				break;


			if(!EVP_CipherUpdate(pCtx, outbuf, &outlen, inbuf, infilelen))//中間過程 
			{
				/* Error */              
				outStr = "Crypt中间过程错误";
				ret = FALSE;
				goto err;
			}

			inSideFile.Write(outbuf, outlen);
			dReturnLen += outlen;
			dFinishLen += infilelen;
			DrawProg(dFinishLen*HUNDRED/dFileLen);
			dBolckLen -= infilelen;
			if(dBolckLen <= 0) break;
		}

		if(!EVP_CipherFinal_ex(pCtx, outbuf, &outlen))    //最終步驟-处理最后(Final)的一段数据
		{   /* Error */                       
			outStr = "Crypt最终过程错误"; 
			ret = FALSE;
			goto err;
		}	               
		inSideFile.Write(outbuf, outlen);
	}

	dReturnLen += outlen;

err:
	if(inSideFile.m_hFile != CFile::hFileNull )
		inSideFile.Close();
	if(ret)
		return dReturnLen;
	else return -1;
}

BOOL CEvp::InitDigest2(CString strMdName, EVP_MD_CTX & Ctx)
{
	const EVP_MD *md = NULL;
	if(strMdName.IsEmpty())
	{
//		outStr = "未指定摘要算法";
		return FALSE;
	}
	//使EVP_Digest系列函数支持所有有效的信息摘要算法
	OpenSSL_add_all_digests();
    
	//根据输入的信息摘要函数的名字得到相应的EVP_MD算法结构
	md = EVP_get_digestbyname(strMdName.GetBuffer(0));  
	strMdName.ReleaseBuffer();
	if(!md) 
	{
//		outStr.Format("未知摘要算法名称 %s",strMdName);
		EVP_cleanup();
		return FALSE;
	}

	//初始化信息摘要结构md_ctx。
	EVP_MD_CTX_init(&Ctx);
	
	//使用md的算法结构设置mdctx结构,impl为NULL,即使用缺省实现的算法(openssl本身提供的信息摘要算法)
	if(!EVP_DigestInit_ex(&Ctx, md, NULL/*impl*/))
	{
//		outStr.Format("Digest初始化算法结构错误");
		EVP_cleanup();
		return FALSE;
	}
	EVP_cleanup();
	return TRUE;
}


void CEvp::CleanDigest2(EVP_MD_CTX & mdCtx)
{
	if(mdCtx.digest) EVP_MD_CTX_cleanup(&mdCtx);
	CRYPTO_cleanup_all_ex_data();
}


/*消息摘要*/ 
//返回值:摘要后长度,-1标示失败
//参数 :	strMdName - 摘要算法名称
//			strFileName  - 输入文件名称
//			File - 已经打开的结果文件
//			outStr - 返回错误信息
DWORD CEvp::Digest2(EVP_MD_CTX * pCtx, const CString strFileName,
			CFile & File, CString & outStr)
{
	if(File.m_hFile == CFile::hFileNull)
		return -1;
	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;//完成长度

	unsigned char md_value[MAX_MD_SIZE]="";
	UINT md_len = 0;/*摘要长度*/
	

	if(strFileName.IsEmpty())
	{
		outStr = "未指定输入文件";
		return -1;
	}
	
	CFile inSideFile;//内部文件
	if(!inSideFile.Open(strFileName, CFile::modeRead | CFile::typeBinary))
	{
		outStr = "不能打开指定文件";
		return -1;
	}


	for(;;)
	{
		len = fread(inbuf, 1, BUFLEN, infd);
		if(len <= 0) break;          
		if(!EVP_DigestUpdate(&md_ctx, inbuf, len))
		{
			outStr.Format("Digest中间过程错误");
			ret=FALSE;
			goto err;
		}
		finishLen+=len;
		DrawProg(finishLen * HUNDRED / fileLen);
	}
	//完成信息摘要计算过程,将完成的摘要信息存储在md_value里面,长度信息存储在md_len里面
	if(!EVP_DigestFinal_ex(&md_ctx, md_value, &md_len))
	{	
		outStr.Format("Digest最终过程错误");
		ret=FALSE;
	}

	
err:
	//使用该函数释放mdctx占用的资源,如果使用_ex系列函数,这是必须调用的。
	if(ret)
	{
		//记录文件
		File.Write(md_value, md_len);
		return md_len;
	}
	else
		return -1;
}

BOOL CEvp::VerifyDigest2(EVP_MD_CTX * mdCtx, const CString strFileName,
			CFile & File, DWORD dBolckLen, CString & outStr)
{
	if(File.m_hFile == CFile::hFileNull)
		return -1;
	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;//完成长度

	unsigned char md_value[MAX_MD_SIZE]="";
	UINT md_len = 0;/*摘要长度*/
	

	if(strFileName.IsEmpty())
	{
		outStr = "未指定输入文件";
		return FALSE;
	}
	
	CFile inSideFile;//内部文件
	if(!inSideFile.Open(strFileName, CFile::modeRead | CFile::typeBinary))
	{
		outStr.Format("文件%s丢失", strFileName);
		return FALSE;
	}


	for(;;)
	{
		len = fread(inbuf, 1, BUFLEN, infd);
		if(len <= 0) break;          
		if(!EVP_DigestUpdate(&md_ctx, inbuf, len))
		{
			outStr.Format("Digest中间过程错误");
			ret=FALSE;
			goto err;
		}
		finishLen+=len;
		DrawProg(finishLen * HUNDRED / fileLen);
	}
	//完成信息摘要计算过程,将完成的摘要信息存储在md_value里面,长度信息存储在md_len里面
	if(!EVP_DigestFinal_ex(&md_ctx, md_value, &md_len))
	{	
		outStr.Format("Digest最终过程错误");
		ret=FALSE;
	}

	
err:
	//使用该函数释放mdctx占用的资源,如果使用_ex系列函数,这是必须调用的。
	if(ret)
	{
		//比较文件摘要与结果是否相同
		if(md_len != dBolckLen)
		{
			outStr.Format("摘要校验错误");
			ret=FALSE;
		}
		else
		{
			char * pmdbuf = new char[dBolckLen + 1];
			File.Read(pmdbuf, dBolckLen);
			if(memcmp(pmdbuf, md_value, dBolckLen) == 0)
			{
				outStr.Format("摘要校验正确");
				ret=TRUE;
			}
			else
			{

⌨️ 快捷键说明

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