zoukankan      html  css  js  c++  java
  • 基于OpenSSL简单实现Shamir基于身份的数字签名算法

    1. 基于身份认证协议简介

    一般基于公钥密码体质的签名认证方案,像RSA都需要用户交换私钥或公钥,一般的认证过程如图1所示:

    1. B要验证消息m是否是A发送的,首先要获得A的公钥09-10-Shamir-01
    2. A先计算m的摘要,再用自己的私钥对摘要进行加密生成对m的个人签名。
    3. A将m和签名一起发送给B。
    4. B验证A的签名,先用A的公钥进行解密,得到A对m计算所得的摘要。
    5. B计算m的摘要与解密出的摘要进行比对,相同则可以确定m是A发送的。

    RSASignature
    图1 基于RSA算法签名认证过程

    Shamir基于身份签名方案不需要通信双方用户间交换密钥,无需保存密钥簿、无须使用第三方服务就可进行安全通信和相互验证签名。虽然该方案任然是一种类公钥密码方案,但它不是去直接生成一对随机的公钥和私钥,而是用户选择他的名字或其它个人唯一信息作为公钥,密钥中心以用户提交的个人身份信息生成用户的私钥。用户与其它用户通信就只需知道对方的名字就行了。用户A给用户B发送一个消息m时,用自己的私钥对m签名。B收到消息m时用A的名字作为密钥对签名进行验证。

    Shamir方案其密钥参数的产生与RSA算法一样,安全性都是依赖于大数分解问题。具体方案如下:

    参数生成:n是两个大素数的乘积,e是一个满足的整数,d是满足的整数,h是一个单向Hash函数。系统的密钥中心的秘密密钥是d,公开的系统参数是(n,e,h),系统中所有用户都知道此公开参数且都一样。

    用户密钥生成:假设i表示用户A的惟一可识别的身份。密钥中心将为其生成私钥如下:

    签名生成:对消息m,用户A随机选择一个数r,计算:

    A对消息m的签名为(t, s)

    签名验证:接收方收到发送的消息m和签名(t,s),通过下式来验证签名是否是身份为i即用户A对m的签名:

    验证式证明过程:(//后的是解释)

    其中最后一步的推导是依据Euler定理

    2. 利用OpenSSL密码算法库实现

    从对Shamir方案的分析过程可知,其中最主要的操作就是对大数的操作包括乘法,幂运算及模运算。好在OpenSSL提供了一些列大数操作函数,所以此方案实现也不是很困难。其中用到的大数操作函数介绍可以查看此页面,更详细的介绍可以查看赵春平老师对于OpenSSL的介绍文档Openssl编程

    // Shamir基于身份认证
        int ShamirTest(){
            BIGNUM    *p,*q;//两个大素数
            BIGNUM    *n; //n = p*q
            BIGNUM    *g;//与用户身份对应的秘密密钥
            BIGNUM    *r;//随机选择数
            BIGNUM    *t,*s;//签名 t = r^e mod n
            BIGNUM    *e;//大素数
            BIGNUM    *d;
            BIGNUM    *i;//用户身份
            BIGNUM    *f;
            BIGNUM    *exp,*left,*right,*tmp;
            BN_CTX    *ctx;
            BN_GENCB    *cb = NULL;
            char u[30],*buf = NULL;
            char *sANDt = NULL;
            char m[20];//消息
            char fHash[1024]= {0};//摘要信息f(t,m)
            int ret,len,bitsp,bitsq,bits=512;
    
    
            ctx = BN_CTX_new();
            BN_CTX_start(ctx);
            exp = BN_CTX_get(ctx);
            tmp = BN_CTX_get(ctx);
            left = BN_CTX_get(ctx);
            right = BN_CTX_get(ctx);
            bitsp = (bits+1)/2;
            bitsq = bits-bitsp;
    
            //生成n,e
            e = BN_new();
            p = BN_new();
            q = BN_new();
            n = BN_new();
            ret = BN_hex2bn(&e,"1L");
    
            for (;;)
            {
                if(!BN_generate_prime_ex(p, bitsp, 0, NULL, NULL, cb))
                    printf("Error -- p\n");
                if (!BN_sub(tmp,p,BN_value_one())) 
                    printf("Error -- p-1\n");
                if (!BN_gcd(left,right,e,ctx)) 
                    printf("Error -- gcd(p-1,e)\n");
                if (BN_is_one(left)) break;
            }
            for (;;)
            {
                if(!BN_generate_prime_ex(q, bitsq, 0, NULL, NULL, cb))
                    printf("Error -- q\n");
                if (!BN_sub(tmp,q,BN_value_one())) 
                    printf("Error -- q-1\n");
                if (!BN_gcd(left,right,e,ctx)) 
                    printf("Error -- gcd(q-1,e)\n");
                if (BN_is_one(left)) break;
            }
            if (!BN_mul(n,p,q,ctx))
                printf("Error -- n\n");
    
            BN_sub_word(p,1);//p=p-1
            BN_sub_word(q,1);//q=q-1;
            ret = BN_mul(exp,p,q,ctx);
            d = BN_new();
            if (!BN_mod_inverse(d,e,exp,ctx)) 
                printf("Error -- d\n");
    
            //设置用户身份i和秘密密钥g
            i = BN_new();
            strcpy(u,"23");
            ret = BN_hex2bn(&i,u);
            g = BN_new();
            ret = BN_mod_exp(g,i,d,n,ctx);
            BN_mod_mul(tmp,d,e,left,ctx);
            //设置随机数r
            r = BN_new();
            ret = BN_rand(r,512,0,0);
    
            //计算t
            t = BN_new();
            ret = BN_mod_exp(t,r,e,n,ctx);
    
            //计算f(t,m)
            strcpy(m,"hello");
            len = sizeof(m)+BN_num_bytes(t)+10;
            sANDt = malloc(len);
            memset(sANDt,0,len);
            BN_bn2bin(t,sANDt);
            strcat(sANDt,m);
            CreateHash(fHash,&ret,sANDt,len,HASH_MD5);
            f = BN_new();
            BN_bin2bn(fHash,ret,f);
            //计算s
            ret = BN_mod_exp(exp,r,f,n,ctx);
            s = BN_new();
            ret = BN_mod_mul(s,g,exp,n,ctx);
            //接收方进行验证
    
            ret = BN_mod_exp(exp,t,f,n,ctx);
            ret = BN_mod_mul(right,i,exp,n,ctx);
    
            ret = BN_mod_exp(left,s,e,n,ctx);
            printf("cmp: %d\n", BN_cmp(left,right));
    
    
            free(sANDt);
            BN_free(left);
            BN_free(right); 
            BN_free(tmp);
            BN_free(exp);
            BN_free(f);
            BN_free(i);
            BN_free(e);
            BN_free(t);
            BN_free(s);
            BN_free(r);
            BN_free(d);
            BN_free(g); 
            BN_free(n); 
            BN_free(p);
            BN_free(q);  
            BN_CTX_free(ctx); 
            return 0;
        }

    因为Shamir方案参数产生与RSA算法一样,所以可以利用Openssl中RSA相关函数更方便的生成参数n,e和d。

    1 rsa = RSA_generate_key(bits,RSA_3,NULL,NULL);
    2 d = BN_new();
    3 n = BN_new();
    4 e = BN_new();
    5 BN_copy(d,rsa->d);
    6 BN_copy(n,rsa->n);
    7 BN_copy(e,rsa->e);

    本文示例程序完整代码:下载

    参考资料

    作者:Ljhero
    出处:http://ljhero.cnblogs.com/
    本作品采用署名-非商业性使用 3.0协议进行许可。欢迎转载,演绎,但是必须保留本文的署名Ljhero,且不能用于商业目的。

  • 相关阅读:
    CUBRID学习笔记 4 端口和win7下连接数据库cubrid教程
    CUBRID学习笔记 3 net连接数据库并使用cubrid教程示例
    CUBRID学习笔记 2 安装教程
    CUBRID学习笔记 1 简介 cubrid教程
    vs无法打开项目的解决方案
    迷你sql profile,给缺少sql跟踪的朋友们
    EntityFramework 开始小试
    网站安全扫描工具--Netsparker的使用
    ServiceStack.OrmLite 笔记10-group having 分页orderby等
    pyqt5 笔记(四)cx_Freeze 实现代码打包exe
  • 原文地址:https://www.cnblogs.com/ljhero/p/2683254.html
Copyright © 2011-2022 走看看