gmssl sm2 将公钥和私钥的十六进制、pem文件和pem base64字符串格式转EC_KEY*


typedef enum 
{
    KEY_TYPE_B64_STRING = 0,
 	KEY_TYPE_HEX_STRING,
    KEY_TYPE_LOCAL_FILE,
}eAsymmKeyForm;

typedef struct
{
	const char *pub_x_hex;
	const char *pub_y_hex;
	const char *pri_hex;
	const char *pub;
	const char *pri;
}KeyFormInfo, *pKeyFormInfo;



EC_KEY *key_b64_create_ec(char *key_b64, int is_public)
{
	EC_KEY *ec_key = NULL;
	BIO *keybio = NULL;
	keybio = BIO_new_mem_buf(key_b64, (int)strlen(key_b64));
	if(keybio == NULL)
	{
		log_e("BIO_new_mem_buf failed");
		return NULL;
	}
 
	if(is_public) 
	{
		ec_key = PEM_read_bio_EC_PUBKEY(keybio, NULL, NULL, NULL);
	}
	else
	{
		ec_key = PEM_read_bio_ECPrivateKey(keybio, NULL, NULL, NULL);
	}
 
	if(ec_key == NULL)
	{
        log_e(" PEM read bio failed");
		return NULL;
	}
 
	return ec_key;
}



EC_KEY *new_ec_key(const char *sk, const char *xP, const char *yP)
{
	log_d("new_ec_key...");
	int ok = 0;
	EC_KEY *ec_key = NULL;
	BIGNUM *d = NULL;
	BIGNUM *x = NULL;
	BIGNUM *y = NULL;
	EC_GROUP *sm2p256 = NULL;

    //sm2p256 = EC_GROP_new_by_curve_name(NID_sm2p256v1); //openssl
    sm2p256 = EC_GROUP_new_by_curve_name(NID_sm2p256v1);

	if(sm2p256 == NULL) {
		log_e("new_ec_group error");
		return NULL;
	}

	if (!(ec_key = EC_KEY_new())) {
		log_e("EC_KEY_new error");
		goto end;
	}
	if (!EC_KEY_set_group(ec_key, sm2p256)) {
		log_e("EC_KEY_set_group error");
		goto end;
	}

	if (sk) {
		if (!BN_hex2bn(&d, sk)) {
			log_e("sk BN_hex2bn error");
			goto end;
		}
		if (!EC_KEY_set_private_key(ec_key, d)) {
			log_e("EC_KEY_set_private_key error");
			goto end;
		}
	}

	if (xP && yP) {
		if (!BN_hex2bn(&x, xP)) {
			log_e("xP BN_hex2bn error");
			goto end;
		}
		if (!BN_hex2bn(&y, yP)) {
			log_e("yP BN_hex2bn error");
			goto end;
		}

		if (!EC_KEY_set_public_key_affine_coordinates(ec_key, x, y)) {
			log_e("EC_KEY_set_public_key_affine_coordinates error");
			goto end;
		}
	}

	ok = 1;
	log_d("new ec key succeed");
	
end:
	if(sm2p256) EC_GROUP_free(sm2p256);
	if (d) BN_free(d);
	if (x) BN_free(x);
	if (y) BN_free(y);
	if (!ok && ec_key) {
		//ERR_print_errors_fp(stderr);
		get_openssL_error("new_ec_key");
		EC_KEY_free(ec_key);
		ec_key = NULL;
	}
	
	return ec_key;
}


EC_KEY *key_form_conver(eAsymmKeyForm form, pKeyFormInfo key_info, int is_public)
{
	log_d("key_form_conver, key form: %d", form);
	EC_KEY *ec_key = NULL;
	
	if(KEY_TYPE_LOCAL_FILE == form)
	{
		FILE *fp = NULL;

		if(is_public)
		{
			fp = fopen(key_info->pub, "r");
			if(NULL == fp)
			{
				log_e("fopen %s failed", key_info->pub);
				return NULL;
			}
			
			ec_key = EC_KEY_new();
			if(NULL == ec_key)
			{
				log_e("generate EC key failed");
				fclose(fp);
				return  NULL;
			}
			
			PEM_read_EC_PUBKEY(fp, &ec_key, NULL, NULL);
			if(NULL == ec_key)
			{
				log_e("read EC public key failed: errno=%lu error=%s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
				fclose(fp);
				EC_KEY_free(ec_key);
				return  NULL;
			}

		}
		else
		{
			fp = fopen(key_info->pri, "r");
			if(NULL == fp)
			{
				log_e("fopen %s failed", key_info->pri);
				return NULL;
			}
			
			ec_key = EC_KEY_new();
			if(NULL == ec_key)
			{
				log_e("generate EC key failed");
				fclose(fp);
				return NULL;
			}
			
			PEM_read_ECPrivateKey(fp, &ec_key, NULL, NULL);
			if(NULL == ec_key)
			{
				log_e("read EC private key failed: errno=%lu error=%s", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL));
				fclose(fp);
				EC_KEY_free(ec_key);
				return NULL;
			}

		}
		
	}
	else if(KEY_TYPE_B64_STRING == form)
	{
		if(is_public)
		{
			log_d("public key b64: %s", key_info->pub);
			if(!(ec_key = key_b64_create_ec(key_info->pub, 1)))
			{
				return NULL;
			}
		}
		else
		{
			log_d("private key b64: %s", key_info->pri);
			if(!(ec_key = key_b64_create_ec(key_info->pri, 0)))
			{
				return NULL;
			}
		}

	}
	else if(KEY_TYPE_HEX_STRING == form)
	{
		if(is_public)
		{
			log_d("public, pub_x_hex: %s, pub_y_hex: %s", key_info->pub_x_hex, key_info->pub_y_hex);
			if(!(ec_key = new_ec_key(NULL, key_info->pub_x_hex, key_info->pub_y_hex)))
			{
				return NULL;
			}
		}
		else
		{
			log_d("private, pri_hex: %s", key_info->pri_hex);
		 	if(!(ec_key = new_ec_key(key_info->pri_hex, NULL, NULL)))
			{
			   return NULL;
			}
		}					
	}
	else
	{
		log_e("input param key type illegal");
		return NULL;
	}

	return ec_key;
}

<think>我们将分别介绍两种转换: 1. 将SM2公钥PEM格式转换为DER格式 2. 将SM2公钥DER格式转换PEM格式 使用GmSSL库(基于OpenSSL)可以通过命令行工具完成,也可以通过编程实现。这里我们主要展示命令行方法,因为通常转换格式使用命令行工具更为方便。同时,我们也会提供C语言的编程实现方法。 注意:GmSSL 3.1.2版本支持标准的PEMDER格式。 一、命令行方式: 1. PEMDER: gmssl pkey -pubin -in sm2_pub.pem -outform DER -out sm2_pub.der 2. DERPEMgmssl pkey -pubin -inform DER -in sm2_pub.der -outform PEM -out sm2_pub.pem 二、编程实现(C语言): 我们将编写两个程序: 1. pem_to_der.c: 读取PEM格式公钥文件,输出DER格式。 2. der_to_pem.c: 读取DER格式公钥文件,输出PEM格式。 由于两个程序非常相似,我们分别给出。 程序1:PEMDER ```c #include <stdio.h> #include <openssl/evp.h> #include <openssl/pem.h> int main() { const char *pem_file = "sm2_pub.pem"; const char *der_file = "sm2_pub.der"; FILE *fp_pem = fopen(pem_file, "r"); if (!fp_pem) { perror("Failed to open PEM file"); return 1; } // 读取PEM格式公钥 EVP_PKEY *pkey = PEM_read_PUBKEY(fp_pem, NULL, NULL, NULL); fclose(fp_pem); if (!pkey) { fprintf(stderr, "Failed to read public key from PEM\n"); return 1; } // 将公钥写入DER格式 FILE *fp_der = fopen(der_file, "wb"); if (!fp_der) { perror("Failed to open DER file for writing"); EVP_PKEY_free(pkey); return 1; } // 获取DER编码的长度 int der_len = i2d_PUBKEY(pkey, NULL); if (der_len <= 0) { fprintf(stderr, "Failed to get DER length\n"); fclose(fp_der); EVP_PKEY_free(pkey); return 1; } unsigned char *der_buf = malloc(der_len); if (!der_buf) { fprintf(stderr, "Memory allocation failed\n"); fclose(fp_der); EVP_PKEY_free(pkey); return 1; } unsigned char *p = der_buf; int len = i2d_PUBKEY(pkey, &p); if (len != der_len) { fprintf(stderr, "DER encoding length mismatch\n"); free(der_buf); fclose(fp_der); EVP_PKEY_free(pkey); return 1; } // 写入文件 size_t written = fwrite(der_buf, 1, der_len, fp_der); fclose(fp_der); if (written != der_len) { fprintf(stderr, "Failed to write entire DER file\n"); free(der_buf); EVP_PKEY_free(pkey); return 1; } free(der_buf); EVP_PKEY_free(pkey); printf("Successfully converted PEM to DER: %s\n", der_file); return 0; } ``` 程序2:DERPEM ```c #include <stdio.h> #include <openssl/evp.h> #include <openssl/pem.h> int main() { const char *der_file = "sm2_pub.der"; const char *pem_file = "sm2_pub.pem"; FILE *fp_der = fopen(der_file, "rb"); if (!fp_der) { perror("Failed to open DER file"); return 1; } // 获取文件长度 fseek(fp_der, 0, SEEK_END); long der_len = ftell(fp_der); fseek(fp_der, 0, SEEK_SET); unsigned char *der_buf = malloc(der_len); if (!der_buf) { fprintf(stderr, "Memory allocation failed\n"); fclose(fp_der); return 1; } size_t read_len = fread(der_buf, 1, der_len, fp_der); fclose(fp_der); if (read_len != der_len) { fprintf(stderr, "Failed to read entire DER file\n"); free(der_buf); return 1; } const unsigned char *p = der_buf; EVP_PKEY *pkey = d2i_PUBKEY(NULL, &p, der_len); if (!pkey) { fprintf(stderr, "Failed to parse DER public key\n"); free(der_buf); return 1; } FILE *fp_pem = fopen(pem_file, "w"); if (!fp_pem) { perror("Failed to open PEM file for writing"); EVP_PKEY_free(pkey); free(der_buf); return 1; } if (!PEM_write_PUBKEY(fp_pem, pkey)) { fprintf(stderr, "Failed to write PEM file\n"); fclose(fp_pem); EVP_PKEY_free(pkey); free(der_buf); return 1; } fclose(fp_pem); EVP_PKEY_free(pkey); free(der_buf); printf("Successfully converted DER to PEM: %s\n", pem_file); return 0; } ``` ### 编译说明: 使用以下命令编译(需要安装GmSSL/OpenSSL开发库): ```bash gcc pem_to_der.c -o pem_to_der -lcrypto gcc der_to_pem.c -o der_to_pem -lcrypto ``` ### 代码解释: 1. **PEMDER**: - 使用 `PEM_read_PUBKEY` 读取PEM格式公钥。 - 使用 `i2d_PUBKEY` 将公钥转换为DER格式(先获取长度,再编码)。 - 将DER编码写入文件。 2. **DERPEM**: - 读取DER文件内容到缓冲区。 - 使用 `d2i_PUBKEY` 解析DER格式公钥。 - 使用 `PEM_write_PUBKEY` 将公钥写入PEM格式文件。 3. **内存管理**: - 注意释放分配的内存EVP_PKEY对象。 - 错误处理确保资源被正确释放。 ### 注意事项: - 这些程序假设公钥SM2类型,但同样适用于其他类型的公钥,因为使用了通用的EVP_PKEY接口。 - 确保输入文件格式正确,否则解析会失败。 &sect;&sect;相关问题&sect;&sect;: 1. 如何将SM2私钥PEMDER格式之间转换? 2. GmSSL支持哪些其他国密算法的密钥格式转换? 3. 在C语言中,如何判断一个PEM文件的内容是公钥还是私钥? 4. 如何使用命令行工具验证PEM或DER格式公钥是否正确?</think># SM2 公钥格式转换PEM ↔ DER 我将详细介绍如何使用 GmSSL 进行 SM2 公钥PEM DER 格式之间的相互转换,包括命令行工具编程实现两种方法。 ## 一、命令行工具转换 ### 1. PEM DER 格式 ```bash # 使用 GmSSLPEM 格式公钥转换为 DER 格式 gmssl pkey -pubin -in sm2_pubkey.pem -outform DER -out sm2_pubkey.der # 验证转换结果(查看 DER 文件内容) gmssl asn1parse -inform DER -in sm2_pubkey.der ``` ### 2. DER PEM 格式 ```bash # 使用 GmSSL 将 DER 格式公钥转换PEM 格式 gmssl pkey -pubin -inform DER -in sm2_pubkey.der -outform PEM -out sm2_pubkey.pem # 查看生成的 PEM 文件内容 cat sm2_pubkey.pem ``` ## 二、C 语言编程实现 ### 1. PEM DER 实现 ```c #include <stdio.h> #include <openssl/evp.h> #include <openssl/pem.h> int main() { const char *pem_file = "sm2_pubkey.pem"; const char *der_file = "sm2_pubkey.der"; // 1. 读取PEM格式公钥 FILE *fp_pem = fopen(pem_file, "r"); if (!fp_pem) { perror("Failed to open PEM file"); return 1; } EVP_PKEY *pkey = PEM_read_PUBKEY(fp_pem, NULL, NULL, NULL); fclose(fp_pem); if (!pkey) { fprintf(stderr, "Failed to read PEM public key\n"); return 1; } // 2. 创建DER输出文件 FILE *fp_der = fopen(der_file, "wb"); if (!fp_der) { perror("Failed to create DER file"); EVP_PKEY_free(pkey); return 1; } // 3. 转换为DER格式并写入文件 if (!i2d_PUBKEY_fp(fp_der, pkey)) { fprintf(stderr, "Failed to convert PEM to DER\n"); fclose(fp_der); EVP_PKEY_free(pkey); return 1; } // 4. 清理资源 fclose(fp_der); EVP_PKEY_free(pkey); printf("Successfully converted PEM to DER: %s\n", der_file); return 0; } ``` ### 2. DER PEM 实现 ```c #include <stdio.h> #include <openssl/evp.h> #include <openssl/pem.h> int main() { const char *der_file = "sm2_pubkey.der"; const char *pem_file = "sm2_pubkey.pem"; // 1. 读取DER格式公钥 FILE *fp_der = fopen(der_file, "rb"); if (!fp_der) { perror("Failed to open DER file"); return 1; } EVP_PKEY *pkey = d2i_PUBKEY_fp(fp_der, NULL); fclose(fp_der); if (!pkey) { fprintf(stderr, "Failed to read DER public key\n"); return 1; } // 2. 创建PEM输出文件 FILE *fp_pem = fopen(pem_file, "w"); if (!fp_pem) { perror("Failed to create PEM file"); EVP_PKEY_free(pkey); return 1; } // 3. 转换PEM格式并写入文件 if (!PEM_write_PUBKEY(fp_pem, pkey)) { fprintf(stderr, "Failed to convert DER to PEM\n"); fclose(fp_pem); EVP_PKEY_free(pkey); return 1; } // 4. 清理资源 fclose(fp_pem); EVP_PKEY_free(pkey); printf("Successfully converted DER to PEM: %s\n", pem_file); return 0; } ``` ### 编译说明: ```bash # 安装依赖 sudo apt-get install libssl-dev # 编译PEMDER程序 gcc pem_to_der.c -o pem_to_der -lcrypto # 编译DERPEM程序 gcc der_to_pem.c -o der_to_pem -lcrypto # 运行程序 ./pem_to_der ./der_to_pem ``` ## 三、格式转换原理 ### PEM 格式特点: - Base64 编码的 DER 数据 - 包含 `-----BEGIN PUBLIC KEY-----` `-----END PUBLIC KEY-----` 头尾标记 - 可读性强,适合文本传输存储 ### DER 格式特点: - 二进制格式的 ASN.1 编码 - 没有头尾标记 - 文件大小比 PEM 小约 27% - 适合网络传输嵌入式系统 ### 转换过程: 1. **PEM → DER**: - 移除头尾标记 - Base64 解码 - 保留原始 ASN.1 结构 2. **DER → PEM**: - Base64 编码 - 添加标准头尾标记 - 每行 64 字符格式化 ## 四、格式验证方法 ### 1. 验证 PEM 文件: ```bash gmssl pkey -pubin -in sm2_pubkey.pem -text -noout ``` ### 2. 验证 DER 文件: ```bash gmssl pkey -pubin -inform DER -in sm2_pubkey.der -text -noout ``` ### 3. 查看 ASN.1 结构: ```bash # PEM 文件 gmssl asn1parse -in sm2_pubkey.pem # DER 文件 gmssl asn1parse -inform DER -in sm2_pubkey.der ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值