openssl3.2 - exp - export RSA pubKey from RSA privKey on memory

文章目录

    • [openssl3.2 - exp - export RSA pubKey from RSA privKey on memory](#openssl3.2 - exp - export RSA pubKey from RSA privKey on memory)
    • 概述
    • 笔记
    • END

openssl3.2 - exp - export RSA pubKey from RSA privKey on memory

概述

官方给的例子(openssl3.2 - 官方demo学习 - encode - rsa_encode.c)是基于文件操作的.

我的工程只需要openssl 操作内存数据, 改了一个操作buffer的版本.

从内存中的RSA私钥数据, 导出RSA公钥来用.

笔记

c 复制代码
/*!
* \file main.cpp
* \note openssl3.2 - exp - export RSA pubKey from RSA privKey on memory
*/

#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_priv_key_for_test[1892];
#include "priv_key_for_test.h"
#include <cassert>

void my_openssl_app();

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

EVP_PKEY* load_key(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
	b_rc = true
	the rsa public key is below:
	0000 - 2d 2d 2d 2d 2d 42 45 47-49 4e 20 52 53 41 20 50   -----BEGIN RSA P
	0010 - 55 42 4c 49 43 20 4b 45-59 2d 2d 2d 2d 2d 0a 4d   UBLIC KEY-----.M
	0020 - 49 49 42 43 67 4b 43 41-51 45 41 6f 6a 62 54 2f   IIBCgKCAQEAojbT/
	0030 - 64 71 79 63 6b 2f 34 58-4a 79 54 45 45 49 34 63   dqyck/4XJyTEEI4c
	0040 - 51 76 77 49 33 6b 66 76-38 46 78 30 46 50 75 6b   QvwI3kfv8Fx0FPuk
	0050 - 53 41 6d 77 71 52 66 44-6b 55 46 57 57 4b 4c 0a   SAmwqRfDkUFWWKL.
	0060 - 7a 67 4a 6b 71 38 66 58-76 65 51 66 31 74 55 32   zgJkq8fXveQf1tU2
	0070 - 32 71 50 70 51 69 6b 30-79 64 6a 75 59 55 35 75   2qPpQik0ydjuYU5u
	0080 - 47 41 45 34 68 36 64 45-36 66 45 75 79 75 7a 6e   GAE4h6dE6fEuyuzn
	0090 - 4a 43 32 4b 4b 51 47 55-76 74 71 52 6c 77 76 49   JC2KKQGUvtqRlwvI
	00a0 - 0a 2b 66 78 77 53 54 4d-45 2f 54 68 48 57 59 71   .+fxwSTME/ThHWYq
	00b0 - 43 41 76 58 5a 2f 49 52-4d 31 32 37 66 67 37 4a   CAvXZ/IRM127fg7J
	00c0 - 37 61 59 37 74 31 65 68-79 79 33 57 59 50 72 71   7aY7t1ehyy3WYPrq
	00d0 - 44 37 45 4c 78 75 37 6c-5a 65 36 4b 54 6f 50 59   D7ELxu7lZe6KToPY
	00e0 - 2b 0a 70 52 58 54 35 62-61 59 37 52 44 66 54 4c   +.pRXT5baY7RDfTL
	00f0 - 78 7a 76 31 54 68 63 4c-30 46 72 4b 32 70 62 6c   xzv1ThcL0FrK2pbl
	0100 - 31 59 48 32 30 31 58 57-67 6c 2b 46 51 62 31 6a   1YH201XWgl+FQb1j
	0110 - 70 41 51 75 4d 53 58 76-79 52 4a 56 79 69 6d 76   pAQuMSXvyRJVyimv
	0120 - 36 2b 0a 48 6e 67 6a 37-35 63 57 74 54 42 30 49   6+.Hngj75cWtTB0I
	0130 - 43 33 68 52 57 55 69 74-77 56 6c 43 4b 6f 76 61   C3hRWUitwVlCKova
	0140 - 57 54 63 43 49 4f 33 48-55 56 55 70 58 4a 78 4f   WTcCIO3HUVUpXJxO
	0150 - 73 51 71 63 34 58 46 2f-70 67 6e 4c 72 79 75 41   sQqc4XF/pgnLryuA
	0160 - 74 34 37 0a 71 56 6a 63-45 61 2f 42 58 68 38 75   t47.qVjcEa/BXh8u
	0170 - 79 6b 49 2b 30 34 6e 4e-58 79 34 66 6d 76 4a 48   ykI+04nNXy4fmvJH
	0180 - 4a 55 54 45 30 51 49 44-41 51 41 42 0a 2d 2d 2d   JUTE0QIDAQAB.---
	0190 - 2d 2d 45 4e 44 20 52 53-41 20 50 55 42 4c 49 43   --END RSA PUBLIC
	01a0 - 20 4b 45 59 2d 2d 2d 2d-2d 0a                      KEY-----.
	free map, g_mem_hook_map.size() = 0
	*/

	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 {
		// PWD_PRIV_KEY 是一个宏 char*, 定义在 priv_key_for_test.h 中, 是私钥数据的口令
		// 一般私钥数据做好时, 都是有口令的
		b_rc = exportRsaPrivKeyToRsaPubKey(ucAry_priv_key_for_test, sizeof(ucAry_priv_key_for_test), PWD_PRIV_KEY, pszPubKey, lenPubKey);
		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 rsa 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* 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(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(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 = 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, "RSA",
		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

相关推荐
Lazy Dave13 天前
gmssl私钥文件格式
网络安全·ssl·openssl
沉在嵌入式的鱼1 个月前
RK3588移植Openssl库
linux·rk3588·openssl
黑屋里的马1 个月前
ssl相关命令生成证书
服务器·网络·ssl·openssl·gmssl
fangeqin2 个月前
ubuntu源码安装python3.13遇到Could not build the ssl module!解决方法
linux·python·ubuntu·openssl
API开发2 个月前
苹果芯片macOS安装版Homebrew(亲测) ,一键安装node、python、vscode等,比绿色软件还干净、无污染
vscode·python·docker·nodejs·openssl·brew·homebrew
码农不惑2 个月前
Rust使用tokio(二)HTTPS相关
https·rust·web·openssl
liulilittle2 个月前
通过高级处理器硬件指令集AES-NI实现AES-256-CFB算法并通过OPENSSL加密验证算法正确性。
linux·服务器·c++·算法·安全·加密·openssl
liulilittle2 个月前
OpenSSL 的 AES-NI 支持机制
linux·运维·服务器·算法·加密·openssl·解密
liulilittle2 个月前
通过高级处理器硬件指令集AES-NI实现AES-256-CFB算法。
linux·服务器·c++·算法·安全·加密·openssl
花花少年2 个月前
Ubuntu系统下交叉编译openssl
openssl·交叉编译