添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

最近要使用paho mqtt+tls,由于paho不支持从内存中加载私钥,但是支持加载经过加密后的私钥文件,而我们的私钥是存储在内存中的,所以需要写代码,将内存中的明文私钥调用openssl的api进行加密,之后落盘提供给mqtt。

gdb跟踪了下openssl的rsa命令,摘了部分代码出来,实现如下,仅供参考。
注1:本实现写死了使用3DES加密,实际可以根据需要进行配置。
注2:代码中的私钥是使用openssl自行生成的,仅用于示例

#include <stdio.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
const char* g_key =
    "-----BEGIN RSA PRIVATE KEY-----\n" \
    "MIIEpAIBAAKCAQEAsVV+dJhw5F8kWuFkQFg4ysKvq2KTZeivMhCxdbAhuUah5yfh\n" \
    "N2bLhhECzO2JnIWrldII8c3v7kNOyNwWeawdtWoc/aS0fpP1/sNfB2Os3RPOLcuL\n" \
    "739rVMq94RHcUj1G4ws60R9oC6wjTc6VmRDyFK8Kp54ok8iTp1g1fLlD5URKTzjn\n" \
    "mF6DWbEmYOvhVteYrsbvfD9uR8x+5B++YsxtRNfIfp1SCrPeLXn+cY9FTJyOwicP\n" \
    "f1az/dqLQ7XNqQGnMXgDfxXflTaYWPR47P/kcN2guO+Y7YvUbTc8vXrgbteKCB4p\n" \
    "liln2X9s3Ccds/k4s6hgAPvpE7SePPu9gX4B2QIDAQABAoIBAHUfh17Q1DcxU5ym\n" \
    "owUQf6oDfe0PNVUoopXJiru1MgDh0ssOfuSNgzyv/Y6GEM6NRq+0Qm4aWy6dy+pD\n" \
    "2qBP+ms4g59O6ltztBSoyxnhTmnRy+pZNrpfCO++3DxMBJ1YlXodj6JRQPH8pnCc\n" \
    "Uhf/pjPdDId6oUhCQKtVSjZvUpWYM3m/nQYcPnf/U0Yg2QDmjAg/a8nNcAlwONMK\n" \
    "8bO4PNJuxwr5O9eue+ZJZFGshT79ZP6zCr3/mdXWia5ieqf11fNzl6oCvQZHmdKK\n" \
    "MdX08/R8Rskh13Nq4oSocRtljfm33/sMvBMFkU4dwcLbihcqee7d5PJUxbOZj/eb\n" \
    "Zzcj2EUCgYEA6ReNrsPZJ89coeAANtsy8kH+IX5roBfnrRT0yJ9g41FjMA7liFnA\n" \
    "tjOSZCc1dlmjUoZsg+nH3+OeIK9t9oz3JMB5qGAO4ZwSsQrWaPRTcVxl4kDMG8o7\n" \
    "jBNd3BspJ4LkpkhjXI03ZJ428OiXlLfVYWgQsMTzSUXnTuvRc4Ll3lcCgYEAwsMa\n" \
    "hLfROoN3AhQ6H8bShY95lSFV3hRa+UMMP6WKm/3U3AnHEMgOFh3L+rj3eleZ9kvZ\n" \
    "z72AQbcfRIPrtpEHWI3//NN81YZ4Zn88ScDKb3zFUfUZEf/CxZU0hiM0lhvKVMuM\n" \
    "Ud2K4huF5h18PLE889Xqu+tYwbngDIIcEnfLo08CgYEAtwkm2fCy6n7756Vlpa31\n" \
    "UKUfsR971ihPZevJ2GzHAVocwFVCSxLnsGvI7dqYMcpr5NboCaIfsSElP9diSzQg\n" \
    "snxuTBi6NtF/IAU5nwsVJzR+UO+/F6dzoShoEPpHE97GPAkl9TxzHhDbZcvPlBnT\n" \
    "dnzodlcCECzTWXb2b3V/mlsCgYAR/DpirybfJGzFAGEttgqS0uEDaISpcW/FPO/Q\n" \
    "oNTf+tzBRRXg8th6Kl4/1Pzli1loaTDAAlvptaNpjFUkEth+0P4mttD8VuKfdHh4\n" \
    "xxjqmrcODng2NUwjOtgS2wVsJzzT/8gBd1fv8WK4EVj7sdJTIhn/KIiVuzh5bzpw\n" \
    "aief+QKBgQDY+a0DgS+Ons6iVK1F+2ZyqL99dB/ficwnYYIr95F/SBumi/bBo1mx\n" \
    "6b2vjpyIMz4zy3M3Doc9hfciWySZjruTqzWU/5yF2b9sBofvD1T92KfVvl8+WUhp\n" \
    "wcIjsBWU0yS7Hamn1OULe/R1lHVkpdtTiBkgfu1HAORa5X77c9kzCQ==\n" \
    "-----END RSA PRIVATE KEY-----";
static void free_rsa(RSA* rsa) {
    if (NULL != rsa) {
        RSA_free(rsa);
static void free_bio(BIO* bio) {
    if (NULL != bio) {
        BIO_free(bio);
int encrypt_privatekey_pem(const char* password, const char* privatekey_plain, 
        char** privatekey_cipher, uint32_t* cipher_length) {
    const char* cipher_name = "des-ede3-cbc";
    const EVP_CIPHER* enc = EVP_get_cipherbyname(cipher_name);
    if (enc == NULL) {
        printf("get enc method failed failed\n");
        return -1;
    BIO* ibio = BIO_new_mem_buf(g_key, -1);
    if (NULL == ibio) {
        printf("read rsa from key bio failed\n");
        return -2;
    RSA* rsa = PEM_read_bio_RSAPrivateKey(ibio, NULL, 0, NULL);
    BIO* obio = NULL;
    int rtn = 0;
    do {
        if (rsa == NULL) {
            printf("read rsa from key bio failed\n");
            rtn = -3;
            break;
        obio = BIO_new(BIO_s_mem());
        if (NULL == obio) {
            printf("read rsa from key bio failed\n");
            rtn = -4;
            break;
        int i = PEM_write_bio_RSAPrivateKey(obio, rsa, enc, NULL, 0, NULL, (void*)password);
        if (i <= 0) {
            printf("bio write rsa key failed\n");
            rtn = -5;
            break;
        char* buf = NULL;
        long size = BIO_get_mem_data(obio, &buf);
        if (size == 0) {
            printf("bio read failed\n");
            rtn = -6;
            break;
        *privatekey_cipher = malloc(size);
        memcpy(*privatekey_cipher, buf, size);
        *cipher_length = size;
        rtn = 0;
    } while (0);
    free_rsa(rsa);
    free_bio(ibio);
    free_bio(obio);
    return rtn;            
int main() {
    const char* password = "12345678";
    char* cipher = NULL;
    uint32_t cipher_size = 0; 
    int rtn = encrypt_privatekey_pem(password, g_key, &cipher, &cipher_size);
    if (rtn != 0) {
        printf("failed, rtn is %d\n", rtn);
        return -1;
    } else {
        printf("--successfully!\n");
    free(cipher);
    return 0;

改代码对应的openssl命令:

openssl  rsa -des-ede3-cbc -in key.key -out key_enc.key -passout pass:12345678

我用的openssl版本是1.1.0-stable

openssl  rsa -des-ede3-cbc -in key.key -out key_enc.key -passout pass:12345678

该命令生成的私钥文件依然是PEM格式的,但是里面的扩展字段是OpenSsl自定义的,而不是标准格式。虽然像mbedtls也支持openssl自定义的这种格式,但是最好还是使用像PKCS#8这种标准格式。

附一篇讨论openssl加密私钥格式的帖子: https://security.stackexchange.com/questions/39279/stronger-encryption-for-ssh-keys

通过对文件的每个字节执行异或操作,我们可以将文件内容与一个密钥进行混合,从而生成加密后的文件。正如您所看到的,这个文件加密程序非常简单,仅仅使用了C语言的基本操作和算法。然而,它提供了一种简单的加密方法,可以用于对敏感文件进行保护。请记住,这只是一个简单的示例程序,实际的加密需求可能需要更加复杂和安全的算法。该程序可以将指定的文件内容进行加密,并生成一个加密后的文件副本。函数负责打开输入文件和输出文件,并对输入文件的每个字节执行异或操作。的文件,其包含了加密后的文件内容。,并将加密后的文件命名为。 RSA键是对称的,您可以使用任何一个作为私钥或公钥,只是您选择的一个问题(但DSA键不对称).下面的程序生成两个2048位长的RSA密钥,然后将它们保存到文件并将它们读回到内存.这应该给你的想法如何做到这一点.#include #include #include #include #include #include #include #include #include const char* ...         OpenSSL是一套开放源代码的SSL套件,其函数库是以C语言所写成,实现了基本的传输层数据加密功能。此软件是以两个加拿大人Eric A. Young 和Tim J. Hudson所写的... 一、openssl 命令 openssl rsautl [-in file] [-out file] [-inkey file] [-pubin] [-certin] [-passin arg] [-sign] [-verify] [-encrypt] [-decrypt] [-hexdump] -in file:指定输入文件 -out file:指定输出文件 -inkey file:指定密钥输入文件,默认是私钥文件,指定了"-pubin"则表示为公钥文件,使用 项目需要对TLS报文SNI和证书部分进行过滤,并且之前并没有接触过这方面的内容,为了解决这一需求,期间学习了不少知识,也走了不少弯路。就写下这篇博客记录分享一下。项目背景:项目是一个类似防火墙的软件,可以过滤特定的TLS流量。实现原理就是通过对TLS数据包流量进行解析,得到想要过滤的字段数据,根据过滤规则决定是否放行该TLS流量。本次需要过滤的TLS数据包主要针对SNI和证书,TLS报文的版本为1.2。使用版本为1.0.2k的openssl库进行C编程。 一、opensslRSA加解密、 使用接口生成秘钥 命令行的方式生成证书: https://blog.csdn.net/gengxiaoming7/article/details/78505107 参考文章:https://blog.csdn.net/qq_30667875/arti.. 使用MD5加密   我们以一个字符串为例,新建一个文件filename.txt,在文件内写入hello ,然后在Linux下可以使用命令md5sum filename.txt计算md5值 ==> b1946ac92492d2347c6235b4d2611184  。虽然写入的是hello这5个字符,但是我们使用命令xxd filename.txt后可以看出文件结尾处会有个0x0a这个回车符。所以 unsigned char key[EVP_MAX_KEY_LENGTH]; //密钥 unsigned char iv[EVP_MAX_KEY_LENGTH];//初始化向量 EVP_CIPHER_CTX ctx;//EVP算法上下文 unsigned cha