VC++网络安全编程范例(8)-摘要签名和验证编程实现

是将任意长度的消息变成固定长度的短消息,它类似于一个自变量是消息的函数,  数字摘要
也就是Hash函数。   数字摘要就是采用单项Hash函数将需要加密的明文“摘要”成一串固定长度(128位)的密文这一串密文又称为数字指纹,它有固定的长度,而且不同的明文摘要成密文,其结果总是不同的,儿同样的明文其摘要必定一致。   一个Hash函数的好坏是由发生碰撞的概率决定的。如果攻击者能够轻易地构造出两个消息具有相同的Hash值,那么这样的Hash函数是很危险的。一般来说,安全Hash标准的输出长度为160位,这样才能保证它足够的安全。 这一加密方法亦称安全Hash编码法(SHA:Secure Hash Algorithm)或MD5(MD Standards for Message Digest),由Ron Rivest所设计。该编码法采用单向Hash函数将需加密的明文“摘要”成一串128bit的密文,这一串密文亦称为数字指纹(Finger Print),它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这摘要便可成为验证明文是否是“真身”的“指纹”了。

基本原理
  (1) 被发送文件用SHA编码加密产生128bit的数字摘要(见上节)。

 
(2) 发送方用自己的私用密钥对摘要再加密,这就形成了数字签名。   

(3) 将原文和加密的摘要同时传给对方。   

(4) 对方用发送方的公共密钥对摘要解密,同时对收到的文件用SHA编码加密产生又一摘要。

  (5) 将解密后的摘要和收到的文件在接收方重新加密产生的摘要相互对比。如两者一致,则说明传送过程中信息没有被破坏或篡改过。否则不然。

 

代码实现如下

 

 #include <stdio.h>
 #include <string.h>
 #include <openssl/evp.h>
 #include <openssl/dsa.h>
 #include <openssl/rsa.h>
 #include <openssl/err.h>

void print(const char *promptStr,unsigned char *data,int len)
{
    int i;
    printf("\n===%s[长度=%d]======\n",promptStr,len);
    for(i = 0; i < len; i++) printf("%02x", data[i]);
    printf("\n=======================\n");
}

void print_errors()
{
    /*
    int flags, line;
    char *data, *file;
    unsigned long code;
    code = ERR_get_error_line_data(&file, &line, &data, &flags);
    while (code)
    {
        printf("error code: %lu in %s line %d.\n", code, file, line);
        if (data && (flags & ERR_TXT_STRING))
            printf("error data: %s\n", data);
        code = ERR_get_error_line_data(&file, &line, &data, &flags);
    }
    */
}
//如果成功返回EVP_PKEY,否则返回NULL

EVP_PKEY* getDSA()
{
    EVP_PKEY* pkey=NULL;
    int ret=0;
    DSA* dsa=DSA_generate_parameters(1024,NULL,0,NULL,NULL,NULL,NULL);
    if(NULL==dsa)
    {
        printf("生成DSA参数失败\n");
        return NULL;
    }
	printf("\nDSA 参数成功产生\n");
    ret=DSA_generate_key(dsa);
    if(ret==0)
    {
        printf("DSA_generate_key 失败\n");
        goto err;
    }
	printf("\nDSA 钥对成功产生\n");


    pkey=EVP_PKEY_new();
    if(NULL==pkey)
    {
        printf("EVP_PKEY_new 失败\n");
        goto err;
    }

    EVP_PKEY_assign_DSA(pkey,dsa);
    return pkey;

err:
    DSA_free(dsa);
    return NULL;
}
//如果成功返回EVP_PKEY,否则返回NULL
EVP_PKEY* getRSA()
{
    EVP_PKEY* pkey=NULL;
    RSA* rsa=RSA_generate_key(1024,RSA_3,NULL,NULL);
    if(NULL==rsa)
    {
        printf("生成RSA 密钥对失败\n");
        return NULL;
    }
	// 盲化rsa 密钥以抵御时间攻击
    RSA_blinding_on(rsa,NULL);
    printf("\n生成RSA 密钥对成功\n");
    pkey=EVP_PKEY_new();
    if(NULL==pkey)
    {
        printf("EVP_PKEY_new 失败\n");
        RSA_free(rsa);
        return NULL;
    }

    EVP_PKEY_assign_RSA(pkey,rsa);
    return pkey;
}

void main(int argc, char *argv[])
{
    EVP_MD_CTX mdctx;
    const EVP_MD *md;

    char msgs[][64]={"It's just for test",
        "Author: Jian Shen","Hello World from openssl"};
	//确切的说,我们应该从 EVP_PKEY_size()获得
	//应该注意不要使用EVP_MAX_MD_SIZE,它太小了
    unsigned char sig_value[1024];

    char mdName[]="dss1";//dss1是唯一被DSA支持的信息摘要算法
    //char mdName[]="sha1";
    
    unsigned int sig_len;
    int i;

    DSA* dsa=NULL;
    EVP_PKEY* pkey=NULL;

    OpenSSL_add_all_digests();
	//不要遗漏下面的步骤否则EVP_SignFinal会出错!!
    OpenSSL_add_all_ciphers();

    md = EVP_get_digestbyname(mdName);

    if(!md) {
        printf("错误的摘要算法名称 %s\n", mdName);
        exit(1);
    }

    pkey=getDSA(); //获取DSA对象
    //pkey=getRSA();
    if(pkey==NULL)
    {
        exit(-1);
    }

	EVP_MD_CTX_init(&mdctx);//初始化摘要计算上下文
    EVP_SignInit(&mdctx, md);//初始化签名算法
    //EVP_SignInit_ex(&mdctx, md,NULL);

    for( i=0;i<sizeof(msgs)/sizeof(msgs[0]);i++ )
    {
      EVP_SignUpdate(&mdctx, msgs[i], strlen(msgs[i]));
    }
	//计算签名:实际上该步先计算出摘要值,然后对该值用私钥签名
    i=EVP_SignFinal(
		&mdctx,//摘要计算上下文对象
		sig_value,//输出的签名值
		&sig_len,//签名值长度
		pkey //签名所用私钥
		);
    //i=EVP_DigestFinal(&mdctx,sig_value,&sig_len);//successfully
    if(i==0)
    {
        printf("计算签名失败");
        exit(1);
    }
    EVP_MD_CTX_cleanup(&mdctx);//释放摘要上下文对象
    EVP_PKEY_free(pkey);//释放公钥对象

    print("签名值是: ",sig_value,sig_len);

    printf("\n click any key to continue.");
	//相当于“暂停”,以便观察运行结果
    getchar();
}


 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
面向工程应用:市面上的一些密码学课程和密码学的书籍,很多都是从考证出发,讲解算法原理并不面向工程应用,而我们现在缺少的是工程应用相关的知识,本课程从工程应用出发,每种技术都主要讲解其在工程中的使用,并演示工程应用的代码。 从零实现部分算法: 课程中实现了base16编解码 ,XOR对称加解密算法,PKCS7 pading数据填充算法,通过对一些简单算法的实现,从而加深对密码学的理解。理论与实践结合: 课程如果只是讲代码,同学并不能理解接口背后的原理,在项目设计中就会留下隐患,出现错误也不容易排查出问题。如果只讲理论,比如对密码学的一些研究,对于大部分从事工程应用的同学并没有必要,而是理论与实践结合,一切为了工程实践。代码现场打出: 代码不放在ppt而是现场打出,更好的让学员理解代码编写的逻辑,老师现场敲出代码正是展示出了工程项目的思考,每个步骤为什么要这么做,考虑了哪些异常,易学不枯燥: 课程为了确保大部分人开发者都学得会,理解算法原理(才能真正理解算法特性),学会工程应用(接口调用,但不局限接口调用,理解接口背后的机制,并能解决工程中会出现的问题),阅读算法源码但不实现密码算法,,并能将密码学投入到实际工程中,如果是想学习具体的加密算法实现,请关注我后面的课程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值