Openssl库之RSA格式解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Openssl库之RSA格式解析相关的知识,希望对你有一定的参考价值。

参考技术A Abstract Syntax Notation dot one,抽象语法标记,描述了一种对数据进行表示、传输和解码的数据格式。它提供了一整套正规的格式用于描述对象的结构。它包含两部分:一部分描述信息内数据,数据类型及序列格式;另一部分描述如何将各部分组成消息。而不管语言上如何执行及这些数据的具体指代,也不用去管到底是什么样的应用程序;

ASN1有很多实现版本,Openssl主要采用DER格式,ASN1相关的头文件参见Openssl的源码 asn1.h、asn1t.h,如下所示:

ANS1字段含义:
length —— 管理的数据长度。
type —— 管理的数据类型。
data —— 数据指针。
flags —— 标志位,跟具体数据类型有关

TLV结构即:Type类型, Lenght长度,Value值;它是一种可变格式;Type和Length的长度固定,一般那是2、4个字节;Value的长度由Length指定;

在一段TLV结构描述的数据中例如RSA密钥:

接下来按照TLV格式来分析Openssl所生成的der格式的2048位私钥,这里先说明一下pem格式的密钥和der格式的密钥的区别仅仅在于将der格式的密钥进行base64编码之后加上表头和结尾即为pem格式;

可见私钥当中包含了n、e、d值,所以理论上可以使用私钥进行加密和解密,而在一些加密锁的厂家为了节省内存,会对私钥进行删减,仅仅保留相关解密的参数;

私钥的二进制数据按照TLV结构排列如下:

Openssl查看密钥参数如下:

这里我们大致可以看出TLV结构中的Value和上述过程中的各个参数一致,但是需要说明的是Openssl在查看密钥参数时,已经做了处理保证了modulus、p、q之类有符号位的大数不为负数;所以当我们自己根据这各个参数进行拼接der格式时,具体的方法应当参见上述TLV结构说明;

30 :Type
04A2: 下面内容总长度,超过了0xFF,所以用两个字节描述,所以第二个字节为82,如果下面总长度没有超过0xFF,只用一个字节可以描述,则为81

02:表示asn1_string_st中的type
81:表示长度大于0x80,同时只用一个字节就可以描述
81:参数长度

02:表示asn1_string_st中的type
82:表示长度大于0xFF,需要用两个字节描述
0100:参数长度

02:表示asn1_string_st中的type
03:表示长度是3,小于0x80

OpenSSL笔记-生成RSA公私密钥以PEM格式到char*中(非保存为文件)

OpenSSL笔记-生成RSA公私密钥以PEM格式到char*中(非保存为文件)

不多说,直接上关键代码:

    int ret = 0;
    RSA *r = RSA_new();
    BIGNUM *bne = BN_new();
    int bits = 2048;
    unsigned long e = RSA_F4;

    bne = BN_new();
    ret = BN_set_word(bne, e);

    if(!ret)

        qDebug() << "BN_set_word() error";
        RSA_free(r);
        BN_free(bne);
        return;
    

    ret = RSA_generate_key_ex(r, bits, bne, nullptr);
    if(!ret)

        qDebug() << "RSA_generate_key() error";
        RSA_free(r);
        BN_free(bne);
        return;
    

    BIO *bp_public = BIO_new(BIO_s_mem());;
    BIO *bp_private = BIO_new(BIO_s_mem());
    ret =PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
    if(!ret)

        qDebug() << "PEM_write_bio_RSAPrivateKey() error";
        BIO_free_all(bp_private);
        RSA_free(r);
        BN_free(bne);
        return;
    

    ret = PEM_write_bio_RSAPublicKey(bp_public, r);
    if(!ret)

        qDebug() << "PEM_write_bio_RSAPublicKey() error";
        BIO_free_all(bp_public);
        BIO_free_all(bp_private);
        RSA_free(r);
        BN_free(bne);
        return;
    

    //存储到Map中
    size_t nPriKeyLen = BIO_pending(bp_private);
    size_t nPubKeyLen = BIO_pending(bp_public);

    //密钥对读取到字符串
    char* pPriKey = new char[nPriKeyLen];
    char* pPubKey = new char[nPubKeyLen];
    BIO_read(bp_private, pPriKey, nPriKeyLen);
    BIO_read(bp_public, pPubKey, nPubKeyLen);

    RSAStu rsaStu;
    rsaStu.privateKey = pPriKey;
    rsaStu.publicKey = pPubKey;

这个RSAStu是我自己写的结构体。

打印下:

这里包含的头文件为:

#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>

以上是关于Openssl库之RSA格式解析的主要内容,如果未能解决你的问题,请参考以下文章

使用 openssl 以特定格式创建 RSA 密钥

openssl 怎样生成公钥和密钥 x509格式

openssl RSA非对称加密解密

openssl -- RSA秘钥格式 PEM/PKCS#8

openssl生成RSA格式及pkcs1与pkcs8格式互相转换

openssl生成RSA格式及pkcs1与pkcs8格式互相转换