📄 evp.cpp
字号:
// 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 + -