一、ECC的简介

椭圆曲线算法可以看作是定义在特殊集合下数的运算,满足一定的规则。椭圆曲线在如下两个域中定义:Fp域和F2m域。

Fp域,素数域,p为素数;

F2m域:特征为2的有限域,称之为二元域或者二进制扩展域。该域中,元素的个数为2m个。

以下只介绍素数域。

一些术语说明:

1)  椭圆曲线的阶(order of a curve)

椭圆曲线所有点的个数,包含无穷远点;

2)  椭圆曲线上点的阶(order of a point)

P为椭圆曲线上的点,nP=无穷远点,n取最小整数,既是P的阶;

3)基点(base point)

椭圆曲线参数之一,用G表示,是椭圆曲线上都一个点;

4)余因子(cofactor)

椭圆曲线的余因子,用h表示,为椭圆曲线点的个数/基点的阶

5)椭圆曲线参数:

素数域:(p,a,b,G,n,h)

其中,p为素数,确定Fp,a和b确定椭圆曲线方程,G为基点,n为G的阶,h为余因子。

二、Openssl对ECC的实现

Openssl实现ECC算法包括三部分:ECC算法(crypto/ec)、椭圆曲线数字签名算法ECDSA(crypto/ecdsa)以及椭圆曲线密钥交换算法ECDH(crypto/ecdh)。

2.1 数据结构

我们首先来看一下密钥的数据结构(定义在crypto/ec/ec_lcl.h):

struct ec_key_st {
int version;//版本号
EC_GROUP *group;//密钥参数
EC_POINT *pub_key;//公钥
BIGNUM *priv_key;//大数私钥
//下面的是其他项
unsigned int enc_flag;
point_conversion_form_t conv_form;
int references;
int flags;
EC_EXTRA_DATA *method_data;
};
     初次学习看到这个一头雾水,但没有关系我们一个个来分析,从源代码中找到源头。

首先让我们疑惑的应该是EC_GROUP结构体(crypto/ec/ec_lcl.h):

struct ec_group_st {
const EC_METHOD *meth; //方法(函数)
EC_POINT *generator; //基向量(基点)
BIGNUM order, cofactor; //基点的阶和余因子
int curve_name; //选择椭圆曲线的名字
BIGNUM a, b;//a和b确定椭圆曲线方程
//其他项此处省去
};
     这里可以看到EC_GROUP结构体包含了一个椭圆曲线的基本参数,是不是感觉到豁然开朗,等等,EC_METHOD结构体又是什么?

别着急,我们再来找一下EC_METHOD在哪里定义。

EC_METHOD结构体定义如下(crypto/ec/ec_lcl.h)

struct ec_method_st {
int flags;
int field_type;
int (*group_init) (EC_GROUP *);
void (*group_finish) (EC_GROUP *);
void (*group_clear_finish) (EC_GROUP *);
int (*group_copy) (EC_GROUP *, const EC_GROUP *);
//其他函数声明此处省去
};
     当打开源代码看到EC_METHOD的结构体时,映入眼帘的是大段大段的函数声明,由此可以想到这个结构体是用来封装椭圆曲线的一些基本操作的,不用着急等我们需要的时候再来一个个看。

最后要介绍的是点的数据结构:

struct ec_point_st {
const EC_METHOD *meth;
BIGNUM X;
BIGNUM Y;
BIGNUM Z;
int Z_is_one;
}
    
    这个数据结构比较简单了定义了三维坐标X,Y,Z和方法。

当看到这里,终于可以松一口气了,回顾一下密钥的数据结构主要包含了私钥(大数)、公钥(向量)、和EC_GROUP结构体。而EC_GROUP结构体包含了椭圆曲线的参数和EC_METHOD结构体,而EC_METHOD结构体是一些椭圆曲线运算操作函数的封装。

这还没完,密钥的数据结构中是不是还有一个BIGNUM结构体我们不认识。新的学习历程又要开始了。

Openssl的大数表示用BIGNUM结构体,定义如下(crypto/bn/bn.h)

struct bignum_st {
BN_ULONG *d;
int top;
int dmax;
int neg;
int flags;
};
      
     d:BN_ULONG数组指针首地址,大数存放在这里面。(BN_ULONG可能是被声明一种基本类型如int的别名,本人没找到在哪被声明的,希望各位给予指正)

top:用来指明大数占多少个BN_ULONG空间。

dmax:d数组的大小。

neg:是否为负数,如果为1,则是负数,为0,则为正数。

flags:用于存放一些标记,用于区别静态分配和动态分配。

读到这终于对密钥结构体有一个全面的认识了。

2.2 密钥生成源代码

接下来我们进入文章的主题-密钥的生成。

椭圆曲线的密钥生成实现在crytpo/ec/ec_key.c中。在Openssl中,椭圆曲线密钥生成时,首先用户需要选取一种椭圆曲线(openssl的crypto/ec_curve.c中内置实现了67种,调用EC_get_builtin_curves获取该列表),然后根据选择的椭圆曲线计算密钥生成参数group,最后根据密钥参数group来生公私钥。

我们先来找到密钥生成的源代码,在执行这段函数之前已经选择好椭圆曲线,并生成完密钥生产参数group,并且将group赋值给了密钥结构eckey了,我把我所能理解的内容尽量注释在每行代码之后。

int EC_KEY_generate_key(EC_KEY *eckey)
{
int ok = 0;//判断是否成功
BN_CTX *ctx = NULL;// BN_CTX是在大数那部分定义的一个上下文情景函数,用来存储计算中的中间过程。
//初始化参数
BIGNUM *priv_key = NULL, *order = NULL;
EC_POINT *pub_key = NULL;

#ifdef OPENSSL_FIPS//如果宏定义了OPENSSL_FIPS 则执行下述语句
if (FIPS_mode())
return FIPS_ec_key_generate_key(eckey);
#endif
//判断密钥以密钥生产参数是否为空
if (!eckey || !eckey->group) {
ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
// 分配空间初始化
if ((order = BN_new()) == NULL)
goto err;
if ((ctx = BN_CTX_new()) == NULL)
goto err;
//给priv_key赋初值
if (eckey->priv_key == NULL) {
priv_key = BN_new();
if (priv_key == NULL)
goto err;
} else
priv_key = eckey->priv_key;
//此函数的作用是从group参数中提取椭圆曲线的阶
if (!EC_GROUP_get_order(eckey->group, order, ctx))
goto err;
//为priv_key选取随机数,随机数的范围是两者之间。
do
if (!BN_rand_range(priv_key, order))
goto err;
while (BN_is_zero(priv_key)) ;

//给pub_key分配存储空间
if (eckey->pub_key == NULL) {
pub_key = EC_POINT_new(eckey->group);
if (pub_key == NULL)
goto err;
} else
pub_key = eckey->pub_key;
//这个函数的用途是用来计算点乘,输入的参数依次是椭圆曲线生产参数、运算结果保存处pub_key、大数私钥、null、null和上下文情景函数。
if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx))
goto err;

eckey->priv_key = priv_key;
eckey->pub_key = pub_key;

ok = 1;
//错误处理
err:
if (order)
BN_free(order);
if (pub_key != NULL && eckey->pub_key == NULL)
EC_POINT_free(pub_key);
if (priv_key != NULL && eckey->priv_key == NULL)
BN_free(priv_key);
if (ctx != NULL)
BN_CTX_free(ctx);
return (ok);
}
    读到这是否感觉其实椭圆曲线生产密钥的源代码很简单?等等,我们好像错过了一个重要函数的实现---- EC_POINT_mul(eckey->group, pub_key, priv_key, NULL,NULL,ctx);  
       这个函数定义在crytpo/ec/ec_lib.c中

int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx)
{
const EC_POINT *points[1];
const BIGNUM *scalars[1];
points[0] = point;
scalars[0] = p_scalar;
return EC_POINTs_mul(group, r, g_scalar, (point != NULL
&& p_scalar != NULL), points, scalars, ctx);
}
     我们先从函数的参数来看,只有r和ctx参数没有被const所限制,其他值在此函数运算中不能被改变。ctx好理解,就是相当于一个记录日志。而r就是此函数运算的结果。用函数表示为:

r = g_scalar * G + p_scalar * point

G为此椭圆曲线的基向量,从曲线参数group中获取。

此函数调用了多点相乘函数EC_POINTs_mul(…),这个函数被定义在相同文件下

*scalar,size_t num, const EC_POINT *points[],const BIGNUM *scalars[], BN_CTX *ctx)
{
if (group->meth->mul == 0)//判断是多点还是单点
return ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx);
return group->meth->mul(group, r, scalar, num, points, scalars, ctx);
}
    
    这个函数输入的几个参数与前一个函数差不多,只是从单个点变成了多个点。

我想从简单的两对单点乘来分析,但是找不到源代码在哪,若哪位专业人士知道在哪,恳请留下路径,谢谢谢谢。

历时四天,还处于openssl的初级阶段,是个小白,使用环境为macOS 10.13.1,初次使用时连crypto、demos等目录都找不到,发现编译后就变成了libcrypto.a(静态链接库文件),只能用很笨的方法,在编译过程中终止操作,就保留了crypto、demos等目录,从这里的源代码开始学习。以后的学习方法也要慢慢改进。初次记录学习openssl的点滴,希望大家多批评指正
————————————————
版权声明:本文为CSDN博主「artree_hao」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/nanshenyaohaohaode/article/details/79033644

学习ECC及Openssl下ECC生成密钥的部分源代码心得的更多相关文章

  1. 1.Linux下生成密钥

    1.Linux下生成密钥 ssh-keygen的命令手册,通过”man ssh-keygen“命令: 通过命令”ssh-keygen -t rsa“ 生成之后会在用户的根目录生成一个 “.ssh”的文 ...

  2. 用openssl为EAP-TLS生成证书(CA证书,服务器证书,用户证书)

    用openssl为EAP-TLS生成证书(CA证书,服务器证书,用户证书) 来源: https://www.cnblogs.com/osnosn/p/10597897.html 来自osnosn的博客 ...

  3. 【Unity Shaders】学习笔记——SurfaceShader(八)生成立方图

    [Unity Shaders]学习笔记——SurfaceShader(八)生成立方图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5630261.html ...

  4. ssh生成密钥(供git使用)

    我们在使用git远程更新时候,需要设置好远程密钥,以使我们能够远程更新代码到代码库中.现在我们就来做一下这件事情(ssh模式下) ssh-keygen  -t rsa -c “hcu5555@hotm ...

  5. android安卓生成密钥keystore(命令控制)

    android安卓生成密钥keystore(命令控制) • 配置JDK 详细教程 https://blog.csdn.net/u012934325/article/details/73441617/ ...

  6. 用OpenSSL命令行生成证书文件

    用OpenSSL命令行生成证书文件 1.首先要生成服务器端的私钥(key文件): openssl genrsa -des3 -out server.key 1024 运行时会提示输入密码,此密码用于加 ...

  7. aes加密在linux下会生成随机key的解决办法

    直接贴代码了: package com.segerp.tygl.weixin.common; import java.io.UnsupportedEncodingException; import j ...

  8. ssh-key生成密钥及SSH无密码登录的配置

    文章作者:foochane  原文链接:https://foochane.cn/article/2019061601.html 1 ssh-keygen命令 ssh-keygen命令说明: -t :指 ...

  9. Jmeter配置联机负载生成密钥失败的问题解决

    在配置负载联机时, 控制机上需要生成密钥供负载机使用. 在bin目录下双击create-rmi-keystore.bat时, 弹出错误提示: 'XXXX'不是内部或外部命令, 这种典型的错误一看就环境 ...

随机推荐

  1. UE手游如何应对CPU帧率瓶颈和卡顿?

    如何高效准确详细的对性能进行剖析?腾讯游戏学院专家Leonn将归纳总结在UE下对每一性能指标的剖析方法,本文重点讲解如何应对CPU帧率瓶颈和卡顿? CPU上帧率低和卡顿是性能优化中最易出现的一部分,尤 ...

  2. 201903-2 二十四点 Java

    思路: 数据结构中,栈可以解决运算的问题.利用压栈和弹栈操作实现(这里用队列模拟).具体的: 遇到乘除号,弹出栈顶元素,将计算结果压入栈中.遇到加减号,将后面的数一起压入栈中. 注意: substri ...

  3. spring boot 环境配置(profile)切换

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  4. web系统能力培养计划

    服务器知识掌握如下 01购买linux服务器 客户端工具:https://mobaxterm.mobatek.net/download.html 02linux常用命令 https://www.run ...

  5. StringBuffer类、StringBuilder类详解

    StringBuffer是一个字符串缓冲区,是一个容器,而且长度可变,可以直接操作多个数据类型, 最终会通过toString()方法变成字符串. 容器的功能有: 1.存储 public StringB ...

  6. Mybatis 持久化,持久层

    持久化 持久化是将程序数据在持久状态和瞬时状态间转换的机制. 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘).持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中.X ...

  7. HTTP协议(三):状态码

    前言 作者说:在上一节的内容中,HTTP大佬介绍了他是怎么让服务器和用户达成信息交互的,详细的说明了连接建立过程中用到的一些基本的技术原理,包括请求报文响应报文.建立持久化连接用的Cookie技术等内 ...

  8. 创建简单spring boot项目

    简介 使用spring boot可以轻松创建独立的,基于Spring框架的生产级别应用程序.Spring boot应用程序只需要很少的spring配置 特点 创建独立的Spring应用程序 直接嵌入t ...

  9. 技术沙龙|京东云区块链进校园-京东云&深圳大学线下沙龙分享回顾

    在刚刚结束的京东云&深圳大学技术沙龙活动中,多位京东云的技术大咖针对京东云BDS产品技术细节.开源计划,与深圳大学的同学和参会者进行了深入探讨,干货满满反响深刻,获得了在场同学与参会者的一致好 ...

  10. mybatis-地区三表生成地区树

    package com.dhht.manager.vo.area; import lombok.Data; import java.io.Serializable;import java.util.L ...