openssl3.2 - 官方demo学习 - encode - ec_encode.c

news2024/10/7 2:19:24

文章目录

    • openssl3.2 - 官方demo学习 - encode - ec_encode.c
    • 概述
    • 笔记
    • 产生ecc私钥
    • 产生ecc公钥
    • 测试工程
    • END

openssl3.2 - 官方demo学习 - encode - ec_encode.c

概述

在这里插入图片描述
官方demos/encode 目录中给了2个例子工程
功能是载入(RSA/ECC)公钥, 然后自己就可以拿内存中的公钥对象干活了.
刚开始过官方demo时, 没明白.
现在回头看, 挺简单的.
昨天已经将rsa_encode.c搞定了.
现在准备做ec_encode.c的实验.

肉眼分辨这2个.c, 区别很小. 用BC4看了一下区别, 主要是算法不同.
在这里插入图片描述
openssl的高级接口封装的真好, 类似的算法使用, 唯一的区别是算法名称不同.

笔记

产生ecc私钥

根据前面的实现(openssl3.2 - exp - 选择最好的内建椭圆曲线), 强度最好的内建椭圆曲线名称为 sect571k1/sect571r1, 2选1都行, 那我选择sect571r1

查看openssl帮助, 可知 openssl ecparam -genkey 可以产生ecc私钥.
查找ecparam -genkey, 在openssl源码中看到了产生ecc私钥的例子.

下面2种命令都行, 区别在将输出是否加密

输出分2段, 前面是EC参数, 后面是私钥
openssl ecparam -genkey -name sect571r1 -out ec_privkey_sect571r1_001.key

输出只有一段, 内容被加密
openssl ecparam -genkey -name sect571r1 -param_enc explicit -out ec_privkey_sect571r1_001.key

对于ECC, 私钥产生和公钥产生是分开的, 并不像RSA那样(私钥里面包含公钥)

产生ecc公钥

openssl ec -in ec_privkey_sect571r1_001.key -pubout -out ec_pubkey_sect571r1_001.key
openssl ec -in ec_privkey_sect571r1_001.key -pubout
执行多次, 看到的公钥都是一样的, 说明ecc公钥包含在ecc私钥里面
跟一下, 看看怎么从ecc私钥中取ecc公钥.

将ec_privkey_sect571r1_001.key转成C数组, 就可以在工程中, 通过buffer来载入公钥了.
既然载入不同类型(RSA/ECC)公钥, 只有算法名称不同. 将测试程序改了一下, 载入私钥时, 参数为密钥文件类型 + buffer + buffer_lenn

测试工程

/*!
* \file main.cpp
* \note openssl3.2 - 官方demo学习 - encode - ec_encode.c
* 对于ecc的pem数据, 只能载入ecc公钥到 EVP_PKEY
* 如果给的是ecc私钥, 无法从私钥中载入公钥 到 EVP_PKEY
* 如果想从ecc私钥中载入公钥, 可以参照 openssl ec -in ec_privkey_sect571r1_001.key -pubout
*/

#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <openssl/decoder.h>
#include <openssl/encoder.h>
#include <openssl/evp.h>

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include "CMemHookRec.h"

// 为了内存操作, 已经将私钥数据文件转成了数组, 嵌入到工程中
//! \ref https://lostspeed.blog.csdn.net/article/details/136486115
//! 数组为 const char ucAry_ecc_priv_key_for_test[472];
#include "ecc_priv_key_for_test.h"
#include "ecc_pub_key_for_test.h" // ucAry_ecc_pub_key_for_test
#include "ec_privkey_sect571r1_pub_priv.h" // ucAry_ec_privkey_sect571r1_pub_priv

#include <cassert>

#define PWD_PRIV_KEY NULL

void my_openssl_app();

// 都是在操作内存, 从内存中的私钥数据, 转出到内存中的公钥数据
bool exportRsaPrivKeyToRsaPubKey(const char* key_type, const char* pBufPrivKey, int lenPrivKey, const char* pBufPrivKeyPwd, char*& pBufPubKey, int& lenPubKey);

EVP_PKEY* load_key(const char* key_type, OSSL_LIB_CTX* libctx, const char* pBufPrivKey, int lenPrivKey, const char* passphrase);
bool export_Key(EVP_PKEY* pkey, const char* passphrase, char*& pBufPubKey, int& lenPubKey);

int main(int argc, char** argv)
{
	setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞
	mem_hook();

	my_openssl_app();

	mem_unhook();

	/*! run result
	*/

	return 0;
}

void my_openssl_app()
{
	bool b_rc = false;
	char* pszPubKey = NULL;
	int lenPubKey = 0;
	BIO* bio_out = BIO_new_fp(stdout, 0);
	assert(NULL != bio_out);

	do {
		// 载入公钥
		// 这个函数只能载入公钥, 如果像ecc私钥, 是无法载入公钥的
		// 但是 openssl ec -in ec_privkey_sect571r1_001.key -pubout -out ec_pubkey_sect571r1_001.key 可以, 一会跟一下
		// 执行上面这个命令多次, 看到的公钥都是一样的, 说明 ecc私钥中包含ecc公钥数据

		// 载入公钥数组(单独的ecc公钥文件转换来的) ok
		b_rc = exportRsaPrivKeyToRsaPubKey("EC", ucAry_ecc_pub_key_for_test, sizeof(ucAry_ecc_pub_key_for_test), PWD_PRIV_KEY, pszPubKey, lenPubKey); // ok

		// 载入私钥数组(单独的ecc私钥文件转换来的) err
		// b_rc = exportRsaPrivKeyToRsaPubKey("EC", ucAry_ecc_priv_key_for_test, sizeof(ucAry_ecc_priv_key_for_test), PWD_PRIV_KEY, pszPubKey, lenPubKey); // err
		
		// 载入公钥和私钥数组(自己手工拼的, 前面是ecc私钥文件, 后面呢是ecc公钥文件), err
		// b_rc = exportRsaPrivKeyToRsaPubKey("EC", ucAry_ec_privkey_sect571r1_pub_priv, sizeof(ucAry_ec_privkey_sect571r1_pub_priv), PWD_PRIV_KEY, pszPubKey, lenPubKey); // err

		// 结论 - 这个官方例子, 只能单独载入ecc公钥文件, 得到公钥数据
		// 对于rsa这种(私钥中包含公钥), 可以直接从私钥中得到公钥
		// 对于ecc这样(私钥中也包含公钥), 却不可以直接从私钥中得到公钥, 一会看看 openssl ec -in ec_privkey_sect571r1_001.key -pubout 咋实现的

		BIO_printf(bio_out, "b_rc = %s\n", (b_rc ? "true" : "false"));

		if (!b_rc)
		{
			assert(false);
			break;
		}

		// now can use pszPubKey
		BIO_printf(bio_out, "the EC public key is below:\n");
		BIO_dump_fp(stdout, pszPubKey, lenPubKey);
	} while (false);

	if (NULL != pszPubKey)
	{
		OPENSSL_free(pszPubKey);
		pszPubKey = NULL;
	}

	if (NULL != bio_out)
	{
		BIO_free(bio_out);
		bio_out = NULL;
	}
}

bool exportRsaPrivKeyToRsaPubKey(const char* key_type, const char* pBufPrivKey, int lenPrivKey, const char* pBufPrivKeyPwd, char*& pBufPubKey, int& lenPubKey)
{
	bool b_rc = false;
	EVP_PKEY* pubKey = NULL;

	do {
		// 如果ras私钥是没有口令保护的, 可以不给口令
		if ((NULL == pBufPrivKey) || (lenPrivKey <= 0))
		{
			break;
		}

		pubKey = load_key("EC", NULL, pBufPrivKey, lenPrivKey, pBufPrivKeyPwd);
		if (NULL == pubKey)
		{
			break;
		}

		if (!export_Key(pubKey, NULL, pBufPubKey, lenPubKey))
		{
			break;
		}

		b_rc = true;
	} while (false);

	if (NULL != pubKey)
	{
		EVP_PKEY_free(pubKey);
		pubKey = NULL;
	}

	return b_rc;
}

EVP_PKEY* load_key(const char* key_type, OSSL_LIB_CTX* libctx, const char* pBufPrivKey, int lenPrivKey, const char* passphrase)
{
	int ret = 0;
	EVP_PKEY* pkey = NULL;
	OSSL_DECODER_CTX* dctx = NULL;
	int selection = 0;
	int i_tmp = 0;
	BIO* bio_privKey = NULL;

	if (NULL == key_type)
	{
		goto cleanup;
	}

	bio_privKey = BIO_new(BIO_s_mem());
	if (NULL == bio_privKey)
	{
		goto cleanup;
	}

	i_tmp = BIO_write(bio_privKey, pBufPrivKey, lenPrivKey);
	if (i_tmp != lenPrivKey)
	{
		goto cleanup;
	}

	/*
	 * Create PEM decoder context expecting an RSA key.
	 *
	 * For raw (non-PEM-encoded) keys, change "PEM" to "DER".
	 *
	 * The selection argument here specifies whether we are willing to accept a
	 * public key, private key, or either. If it is set to zero, either will be
	 * accepted. If set to EVP_PKEY_KEYPAIR, a private key will be required, and
	 * if set to EVP_PKEY_PUBLIC_KEY, a public key will be required.
	 */
	dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "PEM", NULL, key_type,
		selection,
		libctx, NULL);
	if (dctx == NULL) {
		// fprintf(stderr, "OSSL_DECODER_CTX_new_for_pkey() failed\n");
		goto cleanup;
	}

	/*
	 * Set passphrase if provided; needed to decrypt encrypted PEM files.
	 * If the input is not encrypted, any passphrase provided is ignored.
	 *
	 * Alternative methods for specifying passphrases exist, such as a callback
	 * (see OSSL_DECODER_CTX_set_passphrase_cb(3)), which may be more useful for
	 * interactive applications which do not know if a passphrase should be
	 * prompted for in advance, or for GUI applications.
	 */
	if (passphrase != NULL) {
		if (OSSL_DECODER_CTX_set_passphrase(dctx,
			(const unsigned char*)passphrase,
			strlen(passphrase)) == 0) {
			// fprintf(stderr, "OSSL_DECODER_CTX_set_passphrase() failed\n");
			goto cleanup;
		}
	}

	/* Do the decode, reading from file. */
	if (OSSL_DECODER_from_bio(dctx, bio_privKey) == 0) { // 如果f是stdin, 就需要自己输入私钥内容, 所以函数入参的f必须是一个实际文件的FILE*
		// fprintf(stderr, "OSSL_DECODER_from_fp() failed\n");
		goto cleanup;
	}

	ret = 1;
cleanup:
	OSSL_DECODER_CTX_free(dctx);

	/*
	 * pkey is created by OSSL_DECODER_CTX_new_for_pkey, but we
	 * might fail subsequently, so ensure it's properly freed
	 * in this case.
	 */
	if (ret == 0) {
		EVP_PKEY_free(pkey);
		pkey = NULL;
	}

	if (NULL != bio_privKey)
	{
		BIO_free(bio_privKey);
		bio_privKey = NULL;
	}

	return pkey;
}

bool export_Key(EVP_PKEY* pkey, const char* passphrase, char*& pBufPubKey, int& lenPubKey)
{
	int ret = 0;
	int selection;
	OSSL_ENCODER_CTX* ectx = NULL;

	unsigned char* pdata = NULL;
	size_t sz_len_data = 0;

	/*
	 * Create a PEM encoder context.
	 *
	 * For raw (non-PEM-encoded) output, change "PEM" to "DER".
	 *
	 * The selection argument controls whether the private key is exported
	 * (EVP_PKEY_KEYPAIR), or only the public key (EVP_PKEY_PUBLIC_KEY). The
	 * former will fail if we only have a public key.
	 *
	 * Note that unlike the decode API, you cannot specify zero here.
	 *
	 * Purely for the sake of demonstration, here we choose to export the whole
	 * key if a passphrase is provided and the public key otherwise.
	 */

	 // 如果给出口令, 就导出公私钥对;
	 // 如果不给口令, 就只导出公钥
	 // 实际应用中, 我们就只有导出公钥的需求
	selection = (passphrase != NULL)
		? EVP_PKEY_KEYPAIR
		: EVP_PKEY_PUBLIC_KEY;

	ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "PEM", NULL, NULL);
	if (ectx == NULL) {
		// fprintf(stderr, "OSSL_ENCODER_CTX_new_for_pkey() failed\n");
		goto cleanup;
	}

	/*
	 * Set passphrase if provided; the encoded output will then be encrypted
	 * using the passphrase.
	 *
	 * Alternative methods for specifying passphrases exist, such as a callback
	 * (see OSSL_ENCODER_CTX_set_passphrase_cb(3), just as for OSSL_DECODER_CTX;
	 * however you are less likely to need them as you presumably know whether
	 * encryption is desired in advance.
	 *
	 * Note that specifying a passphrase alone is not enough to cause the
	 * key to be encrypted. You must set both a cipher and a passphrase.
	 */
	if (passphrase != NULL) {
		/* Set cipher. AES-128-CBC is a reasonable default. */
		if (OSSL_ENCODER_CTX_set_cipher(ectx, "AES-128-CBC", NULL) == 0) {
			// fprintf(stderr, "OSSL_ENCODER_CTX_set_cipher() failed\n");
			goto cleanup;
		}

		/* Set passphrase. */
		if (OSSL_ENCODER_CTX_set_passphrase(ectx,
			(const unsigned char*)passphrase,
			strlen(passphrase)) == 0) {
			// fprintf(stderr, "OSSL_ENCODER_CTX_set_passphrase() failed\n");
			goto cleanup;
		}
	}

	/* Do the encode, writing to the given file. */
	if (OSSL_ENCODER_to_data(ectx, &pdata, &sz_len_data) == 0) {
		// fprintf(stderr, "OSSL_ENCODER_to_fp() failed\n");
		goto cleanup;
	}

	pBufPubKey = (char*)pdata;
	lenPubKey = (int)sz_len_data;

	ret = 1;
cleanup:
	OSSL_ENCODER_CTX_free(ectx);
	return ret;
}

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1507648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Uber/Google Golang编码标准深度分析

良好的代码风格对于开发优秀的产品至关重要&#xff0c;本文通过分析比较三部流传甚广的Golang代码风格指南&#xff0c;介绍了Go代码风格要点&#xff0c;并介绍了通过工具实现代码检查的方式。原文: Mastering Go: In-Depth Analysis of Uber and Google’s Coding Standards…

算法50:动态规划专练(力扣514题:自由之路-----4种写法)

题目: 力扣514 &#xff1a; 自由之路 . - 力扣&#xff08;LeetCode&#xff09; 题目的详细描述&#xff0c;直接打开力扣看就是了&#xff0c;下面说一下我对题目的理解: 事例1&#xff1a; 输入: ring "godding", key "gd" 输出: 4. 1. ring的第…

【网络原理】TCP 协议中比较重要的一些特性(一)

目录 1、TCP 协议 2、确认应答 2.1、确认序号 3、超时重传 4、连接管理 4.1、建立连接&#xff08;三次握手&#xff09; 4.2、断开连接&#xff08;四次挥手&#xff09; 1、TCP 协议 TCP 是工作中最常用到的协议&#xff0c;也是面试中最常考的协议&#xff0c;具有面…

spring-data-elasticsearch官方文档解读(部分)

Spring Data Elasticsearch 这里主要学习的是4.4.16版本的文档 1. 版本 下表显示了 Spring Data 发行版系列使用的 Elasticsearch 版本和其中包含的 Spring Data Elasticsearch 版本&#xff0c;以及引用该特定 Spring Data 发行版系列的 Spring Boot 版本。给出的 Elastics…

关于yolov8的DFL模块(pytorch以及tensorrt)

可以参考我改的项目&#xff0c;不过目前推理结果不对&#xff0c;还在修复&#xff1a; https://github.com/lindsayshuo/yolov8-cls-tensorrtx先看代码 class DFL(nn.Module):"""Integral module of Distribution Focal Loss (DFL).Proposed in Generalized…

视频占用内存太大了怎么办 如何快速又无损的压缩视频 快来学习吧

视频文件太大是很多人在使用电脑或移动设备时经常遇到的问题。如果视频文件过大&#xff0c;不仅会占用过多的存储空间&#xff0c;还会让播放和传输变得困难。为了解决这个问题&#xff0c;我们需要学会如何缩小视频文件大小。那么如何缩小储存视频的大小呢&#xff1f;下面给…

【JAVA】CSS2:样式、选择器、伪类、颜色、字体、边框、列表、背景、盒子、布局、浮动

本文介绍了CSS样式、选择器、伪类、像素、颜色、字体、边框、列表、表格属性、背景、盒子、布局与浮动 1.样式 1.1 行内样式 <h1 style"color: aqua;font-size: large;">123</h1> 1.2 内部样式 <style>h1{color: red;font: 100;}</style>…

高速电路顶级会议DesignCon 2019年会议总结和论文资料分享

会议基本介绍 DesignCon 2019年是一场专注于电子设计和信号完整性的国际会议&#xff0c;于在美国加利福尼亚州举行。 主题丰富&#xff1a;DesignCon 2019年聚焦于电子设计和信号完整性的多个领域&#xff0c;包括高速串行链接、射频和微波设计、功率完整性、模拟设计、信号…

Unity3d Shader篇(十三)— 透明度混合(AlphaBlend)

文章目录 前言一、什么是透明度混合&#xff1f;1. 透明度混合原理2. 透明度混合优缺点优点&#xff1a;缺点&#xff1a; 3. 纹理图 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数 三、效果四、总结 前言 在计…

ArmSoM Rockchip系列产品 通用教程 之 PCIe 使用

1. PCIe 简介​ PCIe&#xff08;Peripheral Component Interconnect Express&#xff09;是一种用于连接主板和外部设备的高速串行接口标准。它是 PCI 技术的后继者&#xff0c;旨在提供更高的带宽和更好的性能。 高速传输&#xff1a; PCIe接口提供了高速的数据传输通道&am…

【STA】SRAM / DDR SDRAM 接口时序约束学习记录

1. SRAM接口 相比于DDR SDRAM&#xff0c;SRAM接口数据与控制信号共享同一时钟。在用户逻辑&#xff08;这里记作DUA&#xff08;Design Under Analysis&#xff09;&#xff09;将数据写到SRAM中去的写周期中&#xff0c;数据和地址从DUA传送到SRAM中&#xff0c;并都在有效时…

使用QEMU来模拟运行Linux系统

第一步&#xff1a;安装 执行命令 假设我们呢开发板需要arm64架构的Ubuntu 得通过apt-file去找&#xff0c;可以找到qemu-system-arm 所以直接按照qemu-system-arm就行了 apt-file list会列举这个软件包里所有的文件 这个命令可以列举出所有安装好的包名&#xff0c;有点像pip…

什么是PLC远程控制模块?

随着工业自动化的不断发展&#xff0c;可编程逻辑控制器&#xff08;PLC&#xff09;已成为现代工业设备中不可或缺的核心组件。然而&#xff0c;传统的PLC管理方式往往受限于现场操作和维护&#xff0c;难以满足日益复杂的工业需求。在这一背景下&#xff0c;PLC远程控制模块应…

【数据库系统概论】第2章:关系数据库

文章目录 0. 前言2.1 关系数据结构及形式化定义2.1.1关系2.1.2 关系模式 2.2 关系操作2.3 关系的完整性2.4 关系代数 0. 前言 关系数据库系统是支持关系模型的数据库系统。第一章初步介绍了关系模型及其基本术语。本章将深入介绍关系模型。 按照数据模型的三个要素&#xff0c;…

基础刷题50之五(重复的子字符串)

文章目录 前言一、题目二、力扣官方解释1、枚举2、字符串匹配 三、文心一言解释1、枚举2、字符串匹配 总结 前言 刚上研一&#xff0c;有人劝我好好学C&#xff0c;当时用的不多就没学&#xff0c;现在毕业上班了。在此亡羊补牢了 在此感谢力扣和文心一言 一、题目 给定一个…

Python图像处理【22】基于卷积神经网络的图像去雾

基于卷积神经网络的图像去雾 0. 前言1. 渐进特征融合网络2. 图像去雾2.1 网络构建2.2 模型测试 小结系列链接 0. 前言 单图像去雾 (dehazing) 是一个具有挑战性的图像恢复问题。为了解决这个问题&#xff0c;大多数算法都采用经典的大气散射模型&#xff0c;该模型是一种基于单…

ECharts饼图图例消失踩的坑

在使用Echarts的饼图时&#xff0c;当时做法是在图例数小于8时显示全部的图例&#xff0c;在大于8的时候显示前8个图例。于是用了两种不同的方式处理。导致出现切换时间后图例不显示的情况。 错误过程&#xff1a; 在进行图例生成时采用了两种不同的方式&#xff1a; ①如果…

Redis底层源码分析系列(前提准备)

文章目录 一、 面试题二、 源码分析1. 源码导入2. 源码核心部分 一、 面试题 1. redis跳跃列表了解吗&#xff1f;这个数据结构有什么缺点&#xff1f; 2. redis项目里面怎么用&#xff1f; redis的数据结构都了解哪些&#xff1f; 3. redis的zset底层实现&#xff1f; redi…

深入理解Servlet

目录&#xff1a; ServletWeb开发历史Servlet简介Servlet技术特点Servlet在应用程序中的位置Tomcat运行过程Servlet继承结构Servlet生命周期Servlet处理请求的原理Servlet的作用HttpServletRequest对象HttpServletResponse对象ServletContext对象ServletConfig对象Cookie对象与…

Constrained Iterative LQR 自动驾驶中使用的经典控制算法

Motion planning 运动规划在自动驾驶领域是一个比较有挑战的部分。它既要接受来自上层的行为理解和决策的输出,也要考虑一个包含道路结构和感知所检测到的所有障碍物状态的动态世界模型。最终生成一个满足安全性和可行性约束并且具有理想驾驶体验的轨迹。 通常,motion plann…