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

密钥数据结构

密钥数据结构定义在openssl-1.1.0c\crypto\ec\ec_lcl.h文件中。

struct ec_key_st {const EC_KEY_METHOD *meth;ENGINE *engine;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;CRYPTO_EX_DATA ex_data;CRYPTO_RWLOCK *lock;
};

密钥生成

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

签名值数据结构

与 DSA 签名值一样, ECDSA 的签名结果表示为两项。 ECDSA 的签名结果数据结构定义在 crypto\ec\ec_lcl.h 中。

struct ECDSA_SIG_st {BIGNUM *r;BIGNUM *s;
};

签名与验签

crypto/ec/ ecdsa_sign.c 实现了签名算法,
crypto/ec/ ecdsa_vrf.c 实现了验签

密钥交换

crypto/ec/ec dh_ossl.c 实现了密钥交换算法。

主要函数

1) EC_get_builtin_curves
获取椭圆曲线列表。

size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems)
{size_t i, min;if (r == NULL || nitems == 0)return curve_list_length;min = nitems < curve_list_length ? nitems : curve_list_length;for (i = 0; i < min; i++) {r[i].nid = curve_list[i].nid;r[i].comment = curve_list[i].comment;}return curve_list_length;
}

2) EC_GROUP_new_by_curve_name
根据指定的椭圆曲线来生成密钥参数。

EC_GROUP *EC_GROUP_new_by_curve_name(int nid)
{size_t i;EC_GROUP *ret = NULL;if (nid <= 0)return NULL;for (i = 0; i < curve_list_length; i++)if (curve_list[i].nid == nid) {ret = ec_group_new_from_data(curve_list[i]);break;}if (ret == NULL) {ECerr(EC_F_EC_GROUP_NEW_BY_CURVE_NAME, EC_R_UNKNOWN_GROUP);return NULL;}EC_GROUP_set_curve_name(ret, nid);return ret;
}

3) int EC_KEY_generate_key
根据密钥参数生成 ECC 公私钥。

int EC_KEY_generate_key(EC_KEY *eckey)
{if (eckey == NULL || eckey->group == NULL) {ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER);return 0;}if (eckey->meth->keygen != NULL)return eckey->meth->keygen(eckey);ECerr(EC_F_EC_KEY_GENERATE_KEY, EC_R_OPERATION_NOT_SUPPORTED);return 0;
}

4) int EC_KEY_check_key
检查 ECC 密钥。

int EC_KEY_check_key(const EC_KEY *eckey)
{if (eckey == NULL || eckey->group == NULL || eckey->pub_key == NULL) {ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER);return 0;}if (eckey->group->meth->keycheck == NULL) {ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);return 0;}return eckey->group->meth->keycheck(eckey);
}

5) int ECDSA_size
获取 ECC 密钥大小字节数。

int ECDSA_size(const EC_KEY *r)
{int ret, i;ASN1_INTEGER bs;unsigned char buf[4];const EC_GROUP *group;if (r == NULL)return 0;group = EC_KEY_get0_group(r);if (group == NULL)return 0;i = EC_GROUP_order_bits(group);if (i == 0)return 0;bs.length = (i + 7) / 8;bs.data = buf;bs.type = V_ASN1_INTEGER;/* If the top bit is set the asn1 encoding is 1 larger. */buf[0] = 0xff;i = i2d_ASN1_INTEGER(&bs, NULL);i += i;                     /* r and s */ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE);return (ret);
}

6) ECDSA_sign
签名,返回 1 表示成功。

int ECDSA_sign(int type, const unsigned char *dgst, int dlen, unsigned char*sig, unsigned int *siglen, EC_KEY *eckey)
{return ECDSA_sign_ex(type, dgst, dlen, sig, siglen, NULL, NULL, eckey);
}int ECDSA_sign_ex(int type, const unsigned char *dgst, int dlen,unsigned char *sig, unsigned int *siglen, const BIGNUM *kinv,const BIGNUM *r, EC_KEY *eckey)
{if (eckey->meth->sign != NULL)return eckey->meth->sign(type, dgst, dlen, sig, siglen, kinv, r, eckey);ECerr(EC_F_ECDSA_SIGN_EX, EC_R_OPERATION_NOT_SUPPORTED);return 0;
}

7) ECDSA_verify
验签,返回 1 表示合法。

/*-* returns*      1: correct signature*      0: incorrect signature*     -1: error*/
int ECDSA_verify(int type, const unsigned char *dgst, int dgst_len,const unsigned char *sigbuf, int sig_len, EC_KEY *eckey)
{if (eckey->meth->verify != NULL)return eckey->meth->verify(type, dgst, dgst_len, sigbuf, sig_len,eckey);ECerr(EC_F_ECDSA_VERIFY, EC_R_OPERATION_NOT_SUPPORTED);return 0;
}

8) EC_KEY_get0_public_key
获取公钥。

const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key)
{return key->pub_key;
}int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key)
{if (key->meth->set_public != NULL&& key->meth->set_public(key, pub_key) == 0)return 0;EC_POINT_free(key->pub_key);key->pub_key = EC_POINT_dup(pub_key, key->group);return (key->pub_key == NULL) ? 0 : 1;
}

9)EC_KEY_get0_private_key
获取私钥。

const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key)
{return key->priv_key;
}int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key)
{if (key->group == NULL || key->group->meth == NULL)return 0;if (key->group->meth->set_private != NULL&& key->group->meth->set_private(key, priv_key) == 0)return 0;if (key->meth->set_private != NULL&& key->meth->set_private(key, priv_key) == 0)return 0;BN_clear_free(key->priv_key);key->priv_key = BN_dup(priv_key);return (key->priv_key == NULL) ? 0 : 1;
}
  1. ECDH_compute_key
    生成共享密钥
int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,const EC_KEY *eckey,void *(*KDF) (const void *in, size_t inlen, void *out,size_t *outlen))
{unsigned char *sec = NULL;size_t seclen;if (eckey->meth->compute_key == NULL) {ECerr(EC_F_ECDH_COMPUTE_KEY, EC_R_OPERATION_NOT_SUPPORTED);return 0;}if (outlen > INT_MAX) {ECerr(EC_F_ECDH_COMPUTE_KEY, EC_R_INVALID_OUTPUT_LENGTH);return 0;}if (!eckey->meth->compute_key(&sec, &seclen, pub_key, eckey))return 0;if (KDF != NULL) {KDF(sec, seclen, out, &outlen);} else {if (outlen > seclen)outlen = seclen;memcpy(out, sec, outlen);}OPENSSL_clear_free(sec, seclen);return outlen;
}

编程示例


#include <string.h>
#include <stdio.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/objects.h>
#include <openssl/err.h>
int main()
{EC_KEY *key1,*key2;const EC_POINT *pubkey1,*pubkey2;EC_GROUP *group1,*group2;unsigned int ret,nid,size,i,sig_len;unsigned char *signature,digest[20];BIO *berr;EC_builtin_curve *curves;int crv_len;char shareKey1[128],shareKey2[128];int len1,len2;/* 构造 EC_KEY 数据结构 */key1=EC_KEY_new();if(key1==NULL){printf("EC_KEY_new err!\n");return -1;}key2=EC_KEY_new();if(key2==NULL){printf("EC_KEY_new err!\n");return -1;}/* 获取实现的椭圆曲线个数 */crv_len = EC_get_builtin_curves(NULL, 0);curves = (EC_builtin_curve *)malloc(sizeof(EC_builtin_curve) * crv_len);/* 获取椭圆曲线列表 */EC_get_builtin_curves(curves, crv_len);/*nid=curves[0].nid;会有错误,原因是密钥太短*//* 选取一种椭圆曲线 */nid=curves[25].nid;/* 根据选择的椭圆曲线生成密钥参数 group */group1=EC_GROUP_new_by_curve_name(nid);if(group1==NULL){printf("EC_GROUP_new_by_curve_name err!\n");return -1;}group2=EC_GROUP_new_by_curve_name(nid);if(group1==NULL){printf("EC_GROUP_new_by_curve_name err!\n");return -1;}/* 设置密钥参数 */ret=EC_KEY_set_group(key1,group1);if(ret!=1){printf("EC_KEY_set_group err.\n");return -1;}ret=EC_KEY_set_group(key2,group2);if(ret!=1){printf("EC_KEY_set_group err.\n");return -1;}/* 生成密钥 */ret=EC_KEY_generate_key(key1);if(ret!=1){printf("EC_KEY_generate_key err.\n");return -1;}ret=EC_KEY_generate_key(key2);if(ret!=1){printf("EC_KEY_generate_key err.\n");return -1;}/* 检查密钥 */ret=EC_KEY_check_key(key1);if(ret!=1){printf("check key err.\n");return -1;}/* 获取密钥大小 */size=ECDSA_size(key1);printf("size %d \n",size);for(i=0;i<20;i++)memset(&digest[i],i+1,1);signature= (unsigned char*)malloc(size);ERR_load_crypto_strings();berr=BIO_new(BIO_s_file());//BIO_set_fp(berr,stdout,BIO_NOCLOSE);/* 签名数据,本例未做摘要,可将 digest 中的数据看作是 sha1 摘要结果 */ret=ECDSA_sign(0,digest,20,signature,&sig_len,key1);if(ret!=1){ERR_print_errors(berr);printf("sign err!\n");return -1;}/* 验证签名 */ret=ECDSA_verify(0,digest,20,signature,sig_len,key1);if(ret!=1){ERR_print_errors(berr);printf("ECDSA_verify err!\n");return -1;}/* 获取对方公钥,不能直接引用 */pubkey2 = EC_KEY_get0_public_key(key2);/* 生成一方的共享密钥 */len1= ECDH_compute_key(shareKey1, 128, pubkey2, key1, NULL);pubkey1 = EC_KEY_get0_public_key(key1);/* 生成另一方共享密钥 */len2= ECDH_compute_key(shareKey2, 128, pubkey1, key2, NULL);if(len1!=len2){printf("err\n");}else{ret=memcmp(shareKey1,shareKey2,len1);if(ret==0)printf("生成共享密钥成功\n");elseprintf("生成共享密钥失败\n");}printf("test ok!\n");BIO_free(berr);EC_KEY_free(key1);EC_KEY_free(key2);free(signature);free(curves);return 0;
}

运行结果:

OpenSSL ECC 算法相关推荐

  1. Openssl ECC椭圆曲线算法 - 密钥/签名/验签/加密/解密/SM2密文 - 序列化反序列化导出导入 - C源码

    . . . . 废话不多说,本代码继承自另外一位讲解Openssl ECC椭圆曲线算法大佬的源代码:https://blog.csdn.net/scuyxi/article/details/59182 ...

  2. 数字签名验签 — ECC算法

    前言 ​ 前段时间,项目上有需求对于重要文件的传输接收时,接收端需要对文件进行安全校验,采用数字签名的方式确保数据来源的安全性以及数据完整性.之前未接触过密码安全方面的知识,现将实施过程中所遇所学记录 ...

  3. ECC算法原理的认识

    公开密钥算法总是要基于一个数学上的难题.比如RSA 依据的是:给定两个素数p.q 很容易相乘得到n,而对n进行因式分解却相对困难.RSA 算法原理具体如下: 找出两个"很大"的质数 ...

  4. php使用ecc算法进行签名,密码之ECC算法原理的认识

    转:https://blog.csdn.net/sszgg2006/article/details/41945163 公开密钥算法总是要基于一个数学上的难题.比如RSA 依据的是:给定两个素数p.q ...

  5. OpenCV实现图像对齐ECC算法(附完整代码)

    OpenCV实现图像对齐ECC算法 OpenCV实现图像对齐ECC算法 OpenCV实现图像对齐ECC算法 #include <opencv2/imgcodecs.hpp> #includ ...

  6. 基于ECC算法的秘钥协商

    基于ECC算法的衍生算法 ECDH(ECC+DH) RSA ECDHE(ECC+DHE) ECDH密钥协商(ECC+DH) 椭圆曲线密码学是属于非对称密码学的,其私钥的计算公式如下: 私钥是一个随机数 ...

  7. 奇妙的安全旅行之ECC算法

    hi,大家好,我是开发者FTD.今天我们来介绍一下非对称加密算法的ECC算法. ECC 算法简介 ECC 是 Elliptic Curves Cryptography 的缩写,意为椭圆曲线密码编码学. ...

  8. ECC算法的详细说明

    今天本来是想写NAND的读写来着,可是这个东东要用到ECC的算法,就深入进来了,从网上找了些资料,不是很好,直到找到这个,郑重感谢Linux时代网站的wwxbei    (旺旺) ,在黑暗中点亮了指明 ...

  9. ecc 算法 PHP实现,ECC算法的详细说明

    ECC算法的详细说明 今天本来是想写NAND的读写来着,可是这个东东要用到ECC的算法,就深入进来了,从网上找了些资料,不是很好,直到找到这个,郑重感谢Linux时代网站的wwxbei (旺旺) ,在 ...

最新文章

  1. 使用大batch优化深度学习:训练BERT仅需76分钟 | ICLR 2020
  2. 场景几何约束在视觉定位中的探索
  3. mysql获取当前时间_MYSQL proxysql 在深入 信息获取和信息输出
  4. linux无文件渗透执行elf
  5. 职场宝典:63种能力让你职场步步高升
  6. Android 开机自动运行和添加删除桌面快捷方式
  7. 如何使用SAP事务码SAT进行UI应用的性能分析
  8. 阿里云超算集谛优化GPU异构并行性能:GROMACS
  9. 集合中的遍历以及删除元素
  10. 实时事理学习与搜索平台DemoV1.0正式对外发布
  11. 又一高校学生私自返校受处分,这回连辅导员、院领导均受牵连
  12. Linux中运行c程序,与系统打交道
  13. iOS使用Instruments的工具
  14. Linux配置java环境变量
  15. G120XA与S7-1200的Modubus通信(一)
  16. unity商店里下载的资源保存路径
  17. MySQL语句-查看当前数据库有哪些表(SHOW TABLES)
  18. ubuntu安装pr_[原创]Dapr入门教程之二:Dapr的安装
  19. 共阳、共阳数码管编码表
  20. 问题解决:Could not get a databaseId from dataSource

热门文章

  1. Android基础——适配安卓6.0新权限系统
  2. windows文件系统权限
  3. ThinkPHP 5 框架实现多语言 实例讲解
  4. php 后台 PHPCMS 多语言网站解决方案
  5. js onmouseup消息被屏蔽
  6. 让我们一起进入haXe的奇幻世界吧
  7. Mobx与Redux的异同
  8. 如何做好软件项目的质量管理?
  9. oracle查询语句出现问号,plsql查询数据库-中文显示问号问题
  10. 《把信送给加西亚》的哈伯德商业信条