一、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. Codeforces 437D 贪心+并查集

    这个题目让我想起了上次在湘潭赛的那道跪死了的题.也是最值问题,这个也是,有n个动物园 每个都有权值 然后被m条路径相连接,保证图是连通的,然后求所有的p[i][j]之和.i,j为任意两个zoo,pij ...

  2. ArchLinux安装(UEFI)

    ArchLinux安装(UEFI) 一.连接网络 1.连接 # wifi-menu 2.检查是否联通 (ctrl+c停止) # ping www.baidu.com 3.远程安装 注:连接上网络之后可 ...

  3. textare限制拖动;提示文字(点击消失,不输入恢复提示信息)

    1.在textarea添加一个样式:style="resize:none;" 2.提示文字(鼠标点击的时候消失,不输入恢复提示信息): <input name="t ...

  4. JZOJ-2019-11-5 B组

    T1 给出一二维01矩阵\(f_{i,j}\), 定义点\((x_a, y_a), (x_b, y_b)\)的「距离」为\(max\{|x_a-x_b|, |y_a-y_b|\}\) 求出一矩阵\(w ...

  5. 将list等分成n份

    public static <T> Map<Integer, List<T>> spiltList(List<T> list, int num) { M ...

  6. 实用的VMware虚拟机使用技巧十一例

    同时安装多个操作系统的方法有很多,例如Linux Grub引导.WindowsNT OS Loader引导.System Commander引导.Partition Magic改变激活分区等,但总是比 ...

  7. 设计模式讲解5:FlyWeight模式源码

    声明:迁移自本人CSDN博客https://blog.csdn.net/u013365635 FlyWeight模式即享元模式.很多文本编辑器中都使用了FlyWeight模式.FlyWeight单词含 ...

  8. hdu2457(最少替换多少个字符使主串不包含模式串)ac自动机+dp

    题:http://acm.hdu.edu.cn/showproblem.php?pid=2457 题意:给定n个模式串,给定一个主串,问最替换掉多少个字符使主串不包含模式串或输出“-1”表示没有可行的 ...

  9. A - Shortest path of the king (棋盘)

    The king is left alone on the chessboard. In spite of this loneliness, he doesn't lose heart, becaus ...

  10. JDK的安装与环境变量配置

    1.下载JDK后安装,此处安装的是JDK8 2.安装后的路径如下图所示,JDK与JRE在同一个文件夹中 3.安装完JDK后配置环境变量  计算机→属性→高级系统设置→高级→环境变量 4.系统变量→新建 ...