#include
#include
#include
#include
#include
void sign_test()
{
unsigned char sign_value[1024]; //保存签名值的数组
int sign_len; //签名的长度
EVP_MD_CTX mdctx; //摘要算法上下文变量
char mess1[]="Text Message"; //签名的信息
RSA *rsa=NULL; //RSA结构体变量
EVP_PKEY *evpKey=NULL; //EVPKEY 结构体变量
int i;
printf("正在产生RSA密钥....");
rsa=RSA_generate_key(1024,RSA_F4,NULL,NULL); //产生一个1024 位的RSA密钥
if (rsa==NULL)
{
printf("gen rsa err\n");
return;
}
printf("成功。\n");
//The EVP_PKEY_new() function allocates an empty EVP_PKEY structure which is used by OpenSSL to store private keys.
evpKey=EVP_PKEY_new();//新建一个EVP_PKEY 变量
if (evpKey==NULL)
{
printf("EVP_PKEY_new err\n");
RSA_free(rsa);
return;
}
if (EVP_PKEY_set1_RSA(evpKey,rsa) !=1) //保存RSA结构体到EVP_PKEY 结构体
{
printf("EVP_PKEY_set1_RSA err\n");
RSA_free(rsa);
EVP_PKEY_free(evpKey);
return;
}
EVP_MD_CTX_init(&mdctx); //初始化摘要上下文
//该函数是一个宏定义函数#define EVP_SignInit_ex(a,b,c) EVP_DigestInit_ex(a,b,c)
// int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
//EVP_DigestInit_ex() sets up digest context ctx to use a digest type from ENGINE impl.
//ctx must be initialized before calling this function. type will typically be supplied by a functionsuch as EVP_sha1().
//If impl is NULL then the default implementation of digest type is used.
if (!EVP_SignInit_ex(&mdctx,EVP_md5(),NULL))
{
printf("Init err\n");
EVP_PKEY_free(evpKey);
RSA_free(rsa);
return;
}
//int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
//EVP_DigestUpdate() hashes cnt bytes of data at d into the digest context ctx.
//This function can be called several times on the same ctx to hash additional data.
if (!EVP_SignUpdate(&mdctx,mess1,strlen(mess1))) //计算签名(摘要)Update
{
printf("EVP_SignUpdate err\n");
EVP_PKEY_free(evpKey);
RSA_free(rsa);
return;
}
//int EVP_SignFinal(EVP_MD_CTX *ctx,unsigned char *sig,unsigned int *s, EVP_PKEY *pkey);
//这是签名系列函数跟信息摘要函数开始不同的地方,其实,该函数是将签名操作的信息摘要结构ctx拷贝一份,
//然后调用EVP_DigestFinal_ex完成信息摘要工作,然后开始对摘要信息用私钥pkey进行签名,并将签名信息保存在参数sig里面。
//如果参数s不为NULL,那么就会将签名信息数据的长度(单位字节)保存在该参数中,通常写入的数据是EVP_PKEY_size(key)。
//因为操作的时候是拷贝了一份ctx,所以,原来的ctx结构还可以继续使用EVP_SignUpdate和EVP_SignFinal函数来完成更多信息的签名工作。
//不过,最后一定要使用EVP_MD_CTX_cleanup函数清除和释放ctx结构,否则就会造成内存泄漏。
if(!EVP_SignFinal(&mdctx,sign_value,(unsigned int *)(&sign_len),evpKey))//签名输出
{
printf("EVP_SignFinal err \n");
EVP_PKEY_free(evpKey);
RSA_free(rsa);
return;
}
printf("消息\"%s\"的签名值是:\n",mess1);
for(i=0;i
{
if (i%6==0)
printf("\n%08xH:",i);
printf("%02x ",sign_value[i]);
}
printf("\n");
EVP_MD_CTX_cleanup(&mdctx);
printf("\n 正在验证签名......\n");
//以下为验证代码
if (!EVP_VerifyInit_ex(&mdctx,EVP_md5(),NULL))
{
printf("EVP_VerifyInit_ex err\n");
EVP_PKEY_free(evpKey);
RSA_free(rsa);
return;
}
if (!EVP_VerifyUpdate(&mdctx,mess1,strlen(mess1)))
{
printf ("EVP_VerifyUpdate err \n");
EVP_PKEY_free(evpKey);
RSA_free(rsa);
return;
}
if (!EVP_VerifyFinal(&mdctx,sign_value,sign_len,evpKey))
{
printf("EVP_VerifyFinal err \n");
EVP_PKEY_free(evpKey);
RSA_free(rsa);
return;
}
else
{
printf ("验证签名正确..\n");
}
EVP_PKEY_free(evpKey);
RSA_free(rsa);
EVP_MD_CTX_cleanup(&mdctx);
printf ("--------------------------------------\n");
return;
}