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