openssl生成椭圆曲线的私钥是如何做到每次不同的?

2023-11-04

目录

 

例子

排查

随机算法

小结


例子

生成一个私钥只需要3步

1. 获得指定曲线的group (如比特币的secp256k1)

2. group和key绑定

3. 用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;
    }    
    
    group1 = EC_GROUP_new_by_curve_name(NID_secp256k1);
    if(group1==NULL) {
      printf("EC_GROUP_new_by_curve_name err!\n");
      return -1;
    }
    group2=EC_GROUP_new_by_curve_name(NID_secp256k1);
    if(group2==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;
    }

可以看出来,相同方法获得的key,相同的方法获得的group,相同的方法生成私钥,但是最后生成的私钥是不同的。

那是什么造成的不一样呢,是哪一步的输入造成了不同呢。openssl是不是有取当前时间作为种子输入呢? 还是有别的随机数? 还是有读取系统某些信息?

排查

经过仔细排查

1. 获得的key只有一个读写锁的地址不同,其他相同。排除

2. group里面参数众多,参与到计算的比如order, a,b 都相同,这些参数只和具体算法有关、

3. 问题肯定还是在生成函数中

Group里的data主要参数

static const struct {
    EC_CURVE_DATA h;
    unsigned char data[0 + 32 * 6];
} _EC_SECG_PRIME_256K1 = {
    {
        NID_X9_62_prime_field, 0, 32, 1
    },
    {
        /* no seed */
        /* p */
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F,
        /* a */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        /* b */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
        /* x */
        0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95,
        0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9,
        0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98,
        /* y */
        0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc,
        0x0e, 0x11, 0x08, 0xa8, 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19,
        0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8,
        /* order */
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
        0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
    }
};

生成私钥的函数实际为

ec_key_simple_generate_key


int ec_key_simple_generate_key(EC_KEY *eckey)
{
    int ok = 0;
    BN_CTX *ctx = NULL;
    BIGNUM *priv_key = NULL;
    const BIGNUM *order = NULL;
    EC_POINT *pub_key = NULL;

    if ((ctx = BN_CTX_new()) == NULL)
        goto err;

    if (eckey->priv_key == NULL) {
        priv_key = BN_new();            //会执行到这里,一个值为0的大数
        if (priv_key == NULL)
            goto err;
    } else
        priv_key = eckey->priv_key;

    order = EC_GROUP_get0_order(eckey->group);  // 获取group的order,固定值大数
    if (order == NULL)
        goto err;

    do
        if (!BN_priv_rand_range(priv_key, order))  // 关键就在这里了,生成随机数,值小于order.
            goto err;
    while (BN_is_zero(priv_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;

    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 (eckey->pub_key == NULL)
        EC_POINT_free(pub_key);
    if (eckey->priv_key != priv_key)
        BN_free(priv_key);
    BN_CTX_free(ctx);
    return ok;
}

到了随机数这里了,那这个随机数的算法就一定每次不冲突吗?

随机算法

这里的随机算法是NIST SP 800-90A DRBG标准算法,计算依赖一个DRBG对象

DRBG里得有一个seed

seed由三部分合成:

Entropy, Nonce, Personalization string.

从代码上来看,Entropy的生成暂时还是看不明白的 =。=

size_t rand_drbg_get_entropy(RAND_DRBG *drbg,
                             unsigned char **pout,
                             int entropy, size_t min_len, size_t max_len,
                             int prediction_resistance)

 Nonce的生成由drbg对象本身和一个计数器合成

size_t rand_drbg_get_nonce(RAND_DRBG *drbg,
                           unsigned char **pout,
                           int entropy, size_t min_len, size_t max_len)

Personalization string 默认是一个固定字符串,用户也可以自己去设定

/* NIST SP 800-90A DRBG recommends the use of a personalization string. */
static const char ossl_pers_string[] = "OpenSSL NIST SP 800-90A DRBG";

在初始化drbg对象的时候,以上三个输入都已经设定好了,seed就确定了。

那么在确定seed的情况下,后续生成的随机数应该是一个固定的序列(按照通常的random()来理解)

DRBG算法还有一个额外参数addtional data,在每次执行Generate的时候都不一样。

这个addtional data由 进程号,线程号和当前时间构成

int rand_pool_add_additional_data(RAND_POOL *pool)
{
    struct {
        int fork_id;
        CRYPTO_THREAD_ID tid;
        uint64_t time;
    } data = { 0 };

    /*
     * Add some noise from the thread id and a high resolution timer.
     * The fork_id adds some extra fork-safety.
     * The thread id adds a little randomness if the drbg is accessed
     * concurrently (which is the case for the <master> drbg).
     */
    data.fork_id = openssl_get_fork_id();
    data.tid = CRYPTO_THREAD_get_current_id();
    data.time = get_timer_bits();

    return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
}

小结

综上,Entropy+Nonce +perstring 构成seed ;

每次生成 再加上 进程号+线程号+当前时间作为参数。

 

所以不需要再去额外添加时间去确保随机数的唯一性;

如果有需要的话,可以去修改personalization string。

随机数到此为止,不再花时间深入研究了,水太深。

下一步研究一下椭圆曲线的加密解密的使用方法。

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

openssl生成椭圆曲线的私钥是如何做到每次不同的? 的相关文章

  • 区块链技术对金融行业有什么冲击?

    区块链技术在经过了长达十年的发展 被越来越多的行业关注 特别是一些大型企业 对区块链技术还进行了深入的研究 区块链技术也在更多的领域被应用 区块链技术的热度虽然很高 但目前的发展还处在初级阶段 其过多的应用场景也是没有得到更大的发展 区块链

随机推荐

  • 蓝桥杯练习系统入门水题

    好几天没写代码了 上蓝桥杯的练习系统看了一下 做了四道巨水题之后发现有些题还要vip 无语 问题描述 Fibonacci数列的递推公式为 Fn Fn 1 Fn 2 其中F1 F2 1 当n比较大时 F
  • (计算机组成原理)指令的寻址方式

    指令寻址方式是指指令或者操作数有效地址的寻找方式 主要分为数据寻址和指令寻址 指令的地址码字段往往并不是操作数的真实地址 而是形式地址 用A表示 A 即操作数形式地址所指向的存储介质的数值 用形式地址结合指令的寻址方式可以计算出操作数的真实
  • 快速调整毕业论文格式:调整参考文献的引用样式和段落格式

    在撰写毕业论文的过程 我们需要参考并引用大量的参考文献 之前有介绍了如何在Word中使用Endnote插入参考文献 但是从Endnote样式网站下载的样式可能和学校要求的参考文献的引用格式和段落样式有些出入 我们需要根据需求在下载样式上进行
  • 二叉树 Binary Tree

    二叉树 二叉树的基本概念 1 什么是二叉树 2 二叉树的优点和缺点 3 二叉树的基本名词 4 二叉树的性质 5 特别的二叉树 满二叉树 Full Binary Tree 完全二叉树 Complete Binary Tree 平衡二叉树 Ba
  • 【C++】多态

    文章目录 1 多态的基本概念 2 动态联编和静态联编 2 多态的原理剖析 3 计算器案例 4 抽象类与纯虚函数 5 虚析构和纯虚析构函数 6 向上类型转换和向下类型转换 1 多态的基本概念 多态性提法接口和具体实现之间的另一层隔离 多态改善
  • 计算机硬件结构简略介绍

    前言 计算机硬件结构简略介绍 一 计算机硬件 从软件开发者的角度来看 计算机硬件有三个部件最为关键 分别是中央处理器CPU 内存 I O控制芯片 二 早期 早期计算机 CPU的核心频率不高 和内存的频率一样 他们都是直接连接在同一个总线 b
  • 面试之设计模式(简单工厂模式)

    案例 在面试时 面试官让你通过面对对象语言 用Java实现计算器控制台程序 要求输入两个数和运算符号 得出结果 大家可能想到是如下 public static void main String args Scanner scanner ne
  • GDB print 详解

    GDB print 详解 分类 Linux GDB 2013 04 08 11 07 145人阅读 评论 0 收藏 举报 Linux GDB 察看变量 目录 print命令的格式是 print xxx p xxx 1 print 操作符 是
  • 请说出三种减少页面加载时间的方法

    1 尽量减少页面中重复的HTTP请求数量 2 服务器开启gzip压缩 3 css样式的定义放置在文件头部 4 Javascript脚本放在文件末尾 5 压缩合并Javascript CSS代码 6 使用多域名负载网页内的多个文件 图片
  • 在Windows 11 中安装和使用 WSL 2

    文章目录 列出可安装的发行版 分发 安装WSL 2 常用命令 显示帮助 启动分发 从powershell中退出分发 关闭正在运行的分发 立即终止所有正在运行的分发和 WSL 2轻型虚拟机 更新wsl 使用VSCode连接WSL 设置代理 换
  • QEMU-从buildroot里面编译kernel(7)

    上面是我的微信和QQ群 欢迎新朋友的加入 下载交叉编译工具 https snapshots linaro org gnu toolchain 选一个最新的 选择压缩包 解压 sudo apt get install g sudo mv gc
  • 网狐棋牌:数据库

    jeefwtwo 账号数据库 QPAccountsDB 账号账号数据库 QPGamescoreDB 游戏积分数据库 QPGameMatchDB 比赛数据库 QPPlatformDB 平台数据库 QPRecordDB 记录数据库 QPTrea
  • vue-video-player基本使用

    下载 npm install vue video player 如果不使用vue的话 可以直接去官网 或者cdn获取对应js即可 在vue中的基本使用 main js中 全局 import Vue from vue import VueVi
  • 线程与进程的对比、互斥锁和条件变量的使用-多线程编程

    线程与进程的对比 线程的概念是共享CPU的需要 进程概念是共享内存的需要 一个进程里代码段 数据段 堆是共享的 但是进程中的每个线程中的栈 寄存器内容独立 进程都是独立的 通常的IPC 管道 共享内存都可以通讯 处于一个线程的代码觉得它拥有
  • Redis基础知识(二):事务机制

    文章目录 一 什么是事务机制 二 Redis模式下如何实现事务机制 2 1 显式开启一个事务 2 2 将命令入队列Queue 2 3 执行事务或丢弃 2 4 EXEC命令执行示例 2 5 DISCARD命令 放弃事务 2 6 因为命令错误导
  • RabbitMQ用途及问题

    转自 https blog csdn net u013871100 column info 27053 1 用途 1 解耦 系统A在代码中直接调用系统B和系统C的代码 如果将来D系统接入 系统A还需要修改代码 过于麻烦 2 异步 将消息写入
  • ROS学习笔记(五)---话题发布

    1 话题通信是什么 在ROS 机器人操作系统 中 话题通信是一种常用的通信机制 用于在不同的ROS节点之间传递消息 话题通信基于发布者 订阅者模式 其中一个节点 发布者 发布消息到一个特定的话题 而其他节点 订阅者 可以订阅该话题以接收消息
  • 一篇文章让你深入了解RGB数据格式和互转(YUV数据组成)

    我们日常看到的图片 视频由RGB或YUV数据组成 说明 1 RGB分为RGB16 RGB24 RGB32 RGB RGB16 RGB24 RGB32 一 RGB分RGB16 RGB24 RGB32 1 RGB16格式分为RGB565 RGB
  • 某市财政收入预测分析:GM模型+神经网络

    from numpy random import seed seed 1 import tensorflow tensorflow random set seed 2 import numpy as np import pandas as
  • openssl生成椭圆曲线的私钥是如何做到每次不同的?

    目录 例子 排查 随机算法 小结 例子 生成一个私钥只需要3步 1 获得指定曲线的group 如比特币的secp256k1 2 group和key绑定 3 用key来生成私钥 先上一段代码例子 key1 EC KEY new if key1