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

文章目录

    • [openssl3.2 - 官方demo学习 - encode - rsa_encode.c](#openssl3.2 - 官方demo学习 - encode - rsa_encode.c)
    • 概述
    • 笔记
    • END

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

概述

上次学习官方demo - rsa_encode.c 时, 程序要在UI上输入东西, 不知道输入啥, 就先放着.

现在需要非对称加解密的例子, rsa_encode.c就是相关的demo, 必须搞懂啊.

现在回过头来再看, 挺简单的.

估计当时几百个demo摆在哪里, 太着急了. 内心必须平静才能将事情做好:P

功能 :

从RSA私钥数据中导出RSA公钥.

如果给出输出的口令, 可以导出公私钥对.

不过, 谁也不会直接导出私钥(知道可以从私钥数据中导出私钥, 有这么回事就行).

官方demo设计是在linux下用的, 用管道来输入要操作的私钥数据.

在windows下运行, 还是用文件方便一些. 改了一下, 用命令行来输入私钥数据文件名.

试了一下, 好使, 可以从私钥数据中导出公钥数据.

笔记

c 复制代码
/*!
\file rsa_encode.c
\note openssl3.2 - 官方demo学习 - encode - rsa_encode.c

命令行参数 - THE_EXE priv_key.pem pwd_for_the_pem
功能 - 导出公钥并打印到UI(stdout)
备注 - 官方程序原来是在linux下用管道输入的私钥数据, 现在改为从文件输入.
*/

/*-
 * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

#include <string.h>
#include <openssl/decoder.h>
#include <openssl/encoder.h>
#include <openssl/evp.h>

#include "my_openSSL_lib.h"

 /*
  * Example showing the encoding and decoding of RSA public and private keys. A
  * PEM-encoded RSA key is read in from stdin, decoded, and then re-encoded and
  * output for demonstration purposes. Both public and private keys are accepted.
  *
  * This can be used to load RSA keys from a file or save RSA keys to a file.
  */

  /* A property query used for selecting algorithm implementations. */
static const char* propq = NULL;

/*
 * Load a PEM-encoded RSA key from a file, optionally decrypting it with a
 * supplied passphrase.
 */
static EVP_PKEY* load_key(OSSL_LIB_CTX* libctx, FILE* f, const char* passphrase)
{
	int ret = 0;
	EVP_PKEY* pkey = NULL;
	OSSL_DECODER_CTX* dctx = NULL;
	int selection = 0;

	/*
	 * 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, propq);
	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_fp(dctx, f) == 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;
	}

	return pkey;
}

/*
 * Store an RSA public or private key to a file using PEM encoding.
 *
 * If a passphrase is supplied, the file is encrypted, otherwise
 * it is unencrypted.
 */
static int store_key(EVP_PKEY* pkey, FILE* f, const char* passphrase)
{
	int ret = 0;
	int selection;
	OSSL_ENCODER_CTX* ectx = NULL;

	/*
	 * 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, propq);
	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", propq) == 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_fp(ectx, f) == 0) {
		fprintf(stderr, "OSSL_ENCODER_to_fp() failed\n");
		goto cleanup;
	}

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

int main(int argc, char** argv)
{
	int ret = EXIT_FAILURE;
	OSSL_LIB_CTX* _ossl_lib_ctx = NULL;
	EVP_PKEY* _evp_pkey = NULL;
	const char* passphrase_in = NULL, * passphrase_out = NULL;

	const char* pszFilePathName = NULL;
	FILE* fp = NULL;

	/* usage: rsa_encode rsa_priv_key.PEM <passphrase-in> <passphrase-out> */
	if (argc > 1)
	{
		pszFilePathName = argv[1];
		fp = fopen(pszFilePathName, "rb");
		if (NULL == fp)
		{
			goto cleanup;
		}
	}

	if (argc > 2 && argv[2][0])
		passphrase_in = argv[2];

	if (argc > 3 && argv[3][0])
		passphrase_out = argv[3];

	/* Decode PEM key from stdin and then PEM encode it to stdout. */
	_evp_pkey = load_key(_ossl_lib_ctx, fp, passphrase_in);
	if (_evp_pkey == NULL) {
		fprintf(stderr, "Failed to decode key\n");
		goto cleanup;
	}

	if (store_key(_evp_pkey, stdout, passphrase_out) == 0) {
		fprintf(stderr, "Failed to encode key\n");
		goto cleanup;
	}

	ret = EXIT_SUCCESS;
cleanup:
	if (NULL != fp)
	{
		fclose(fp);
		fp = NULL;
	}

	EVP_PKEY_free(_evp_pkey);
	OSSL_LIB_CTX_free(_ossl_lib_ctx);
	return ret;
}

END

相关推荐
Lazy Dave10 天前
gmssl私钥文件格式
网络安全·ssl·openssl
沉在嵌入式的鱼1 个月前
RK3588移植Openssl库
linux·rk3588·openssl
黑屋里的马1 个月前
ssl相关命令生成证书
服务器·网络·ssl·openssl·gmssl
fangeqin1 个月前
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·交叉编译