• 国密算法--Openssl 实现国密算法(基础介绍和产生秘钥对)


    国密非对称加密算法

    又称sm2,它是采取了ECC(曲线加密算法)中的一条固定的曲线,实际上就是ECC算法。 因为openssl里面不包含sm2算法,所以就要重新进行封装…. …


    对于ECC算法我就不介绍了,网上关于它的介绍一抓一大把,丢给你们一个链接ECC算法介绍。

    现在对ECC加密算法做个大致的介绍:

    所有非对称加密算法都有公钥和私钥,它们都可以用下面这个公式概括:

    A = k * G
    
    公钥:A , G 
    私钥:k , G
    

    在ECC加密中 G是基准点,k是小于n(基准点的阶)的一个素数, A是加密曲线上的一个点

    ECC的加密曲线是不固定的,选择一条好的加密曲线是很重要的,而且无论是加密还是解密我们都需要用到这条曲线,固定一条ECC加密曲线需要六个参数:

    P(参数范围) 
    a,b(曲线参数) 
    (Gx,Gy)(基准点) 
    n(基准点的阶) 
    h(余因子, h = #E(Fq)/n,其中n是基点G的阶,这个是可选参数。) 
    

    相比到这我们已经有些头大了,这么多参数要设置?别慌这些在sm2算法里面都是固定的

    /*Sm2 中指定的参数 确定下y2 = x3 + ax + b 曲线*/
    #define _P  "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"
    
    #define _a  "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"
    
    #define _b  "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"
    
    #define _n  "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
    
    #define _Gx "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
    
    #define _Gy "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
    

    我们所做的一切都是基于sm2中的那条曲线,以上就是理论知识的介绍。


    下面我们将如何利用openssl中的ECC算法去实现sm2,这里不得不说,openssl这个东西…有点难用啊。这个大家做好心理准备,要写很多期的,我们今天先说如何生成sm2的key;

    首先我们要先得到国密这条曲线,直接贴代码有点太不负责任了,我先给大家先说一写基本的东西:

    先讲几个结构体

    //BN_CTX openssl中加密算法结构体,里面包含各种加密算法的函数指针
    typedef struct bignum_ctx BN_CTX;
    
    //EC_GROUP ecc算法中的组结构体,里面包含着曲线信息
    typedef struct ec_group_st
        /*
         EC_METHOD *meth;
         -- field definition
         -- curve coefficients
         -- optional generator with associated information (order, cofactor)
         -- optional extra data (precomputed table for fast computation of multiples of generator)
         -- ASN1 stuff
        */
        EC_GROUP;
    
    //EC_POINT ecc算法中的点结构体,里面有x,y,z三个值来确地曲线上的一个点
    typedef struct ec_point_st EC_POINT;
    
    //EC_KEY ecc算法中的秘钥结构体,里面包含私钥、公钥、曲线信息
    typedef struct ec_key_st EC_KEY;
    

    然后我说一下生成key的过程:

    //1.先要获取sm2曲线
    //先实例化一个 组对象
      EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
    //说明:生成二进制域上的椭圆曲线,输入参数为p,a和b
    
    //传入曲线参数
    int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
    //说明:设置素数域椭圆曲线参数;
    
    //设置基准坐标点
     int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
    //说明:设置素数域椭圆曲线上点point的几何坐标;
    
    //将基准座标传入组对象
     int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor)
    //说明:设置椭圆曲线的基G;generator、order和cofactor为输入参数;
    
    //2.生成秘钥对
    //在sm2曲线上生成秘钥对
    int EC_KEY_generate_key(EC_KEY *eckey)
    //说明:生成椭圆曲线公私钥;
    
    //获取公钥坐标点
    const EC_POINT* EC_KEY_get0_public_key(EC_KEY *eckey)
    //说明:获取公钥。
    
    //获取私钥素数
    const BIGNUM* EC_KEY_get0_private_key(EC_KEY *eckey) 
    //说明:获取私钥
    

    好了 ,下面到了最重要的一步,贴代码:

    include <openssl/bn.h>
    #include <openssl/ec.h>
    #include <openssl/ebcdic.h>
    #include <openssl/ecdsa.h>
    
    /*Sm2 中指定的参数 确定下y2 = x3 + ax + b 曲线*/
    #define _P  "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"
    
    #define _a  "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"
    
    #define _b  "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"
    
    #define _n  "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
    
    #define _Gx "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
    
    #define _Gy "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
    ....
    int sm2_gen_key(PSM2_KEY sm2key)
    {
        int ret = -1;
        EC_KEY* key = NULL;
        BN_CTX *ctx = NULL;
        EC_GROUP* group = NULL;
        EC_POINT* point_p = NULL;
        const EC_POINT *point_q = NULL;
        BIGNUM *p, *a, *b, *gx, *gy, *z;
    
        assert(sm2key);
    
        p = BN_new();  
        a = BN_new();  
        b = BN_new();  
    
        gx = BN_new();
        gy = BN_new();
        z = BN_new();
    
        //初始化一个空算法组
        group = EC_GROUP_new(EC_GFp_mont_method());  
    
        //将国密算法的参数转为大数
        BN_hex2bn(&p, _P);  
        BN_hex2bn(&a, _a);  
        BN_hex2bn(&b, _b);
        BN_hex2bn(&gx, _Gx);
        BN_hex2bn(&gy, _Gy);
        BN_hex2bn(&z, _n); //素数P的阶
    
        ctx = BN_CTX_new();
    
        //先确定sm2曲线
        //传入a,b参数
        if (!EC_GROUP_set_curve_GFp(group, p, a, b,ctx))  
        {  
            goto err_process;  
        }  
    
        //取曲线上的三个点
        point_p = EC_POINT_new(group);   
    
        //设置基点坐标
        if (!EC_POINT_set_affine_coordinates_GFp(group, point_p, gx, gy, ctx))
        {
            goto err_process;
        }
        //
        ////确定P点事否在曲线上
        if (!EC_POINT_is_on_curve(group, point_p, ctx))
        {
            ret = -2;
            goto err_process;
        }
    
        //设置椭圆曲线的基G,完成了国密曲线
        if(!EC_GROUP_set_generator(group, point_p, z, BN_value_one()))  
        {  
            ret = -3;
            goto err_process;  
        }  
    
        //生成国密Key
        key = EC_KEY_new();
        if (!EC_KEY_set_group(key, group))
        {
            ret = -4;
            goto err_process;
        }
    
        if(!EC_KEY_generate_key(key))
        {
            ret = -5;
            goto err_process;
        }
    
        printf("gen key success:
     the prv is %s
    ", 
            BN_bn2hex(EC_KEY_get0_private_key(key)));
        sm2key->prv_key.bytes = BN_bn2bin(EC_KEY_get0_private_key(key), sm2key->prv_key.k);
    
        point_q = EC_KEY_get0_public_key(key);
        if(!EC_POINT_get_affine_coordinates_GFp(group, point_q, gx, gy , NULL))
        {
            goto err_process;
        }
    
        sm2key->pub_key.bytes = BN_bn2bin(gx, sm2key->pub_key.x);
        BN_bn2bin(gy, sm2key->pub_key.y);
        ret = 0;
    
    err_process:
    
        if (point_p != NULL)
        {
            EC_POINT_free(point_p);
        }
    
        if (group != NULL)
        {
            EC_GROUP_free(group);
        }
    
        if (ctx != NULL)
        {
            BN_CTX_free(ctx);
        }
    
        if (key != NULL)
        {
            EC_KEY_free(key);
        }
    
        return ret;
    }
    
    
  • 相关阅读:
    刷题的 vscodeleetcode
    一个简单的小程序演示Unity的三种依赖注入方式
    WCF服务端运行时架构体系详解[上篇]
    通过WCF扩展实现消息压缩
    通过“四大行为”对WCF的扩展[原理篇]
    [WCF权限控制]利用WCF自定义授权模式提供当前Principal[原理篇]
    [WCF权限控制]ASP.NET Roles授权[下篇]
    [WCF权限控制]通过扩展自行实现服务授权[提供源码下载]
    通过自定义ServiceHost实现对WCF的扩展[实例篇]
    [WCF权限控制]WCF自定义授权体系详解[实例篇]
  • 原文地址:https://www.cnblogs.com/cnblogs-wangzhipeng/p/9933562.html
Copyright © 2020-2023  润新知