RSA加密算法

title: RSA加密算法
date: 2021-12-31 16:42:34
categories:
tags:
- openssl 
- c/c++

1、RSA加密简介

RSA是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)在1977年一起提出的.PSA对极大整数做因数分解的难度决定了 RSA 算法的可靠性。

RSA是目前应用最广泛地一种非对称秘码体制。

2、生成RSA公钥和私钥

int GeneratorRsaKey::RsaKeyPairGen()
{   
    RSA_KEY_FREE(rsa);
    if (!(Ret = RSA_generate_key_ex(rsa, 2048, bne, NULL)))
    {
        RSA_KEY_FREE(rsa);
        return ERR_GENERATE_KEY;
    }

    FILE* Fp = NULL;
    if (!rsa || !RSAPriKeyFileName) //RSAPriKeyFileName为保存rsa私钥的文件路径
        return ERR_ARGUMENT;
    if (!(Fp = fopen(RSAPriKeyFileName, "wb")))
    {
        return ERR_OPENFILE;
    }
    if (!PEM_write_RSAPrivateKey(Fp, rsa, NULL, NULL, 0, NULL, 0)) //写入私钥
    {
        fclose(Fp);
        return ERR_WRITEPRIVATE;
    }
    fclose(Fp);

    if (!rsa || !RSAPubKeyFileName)
        return ERR_ARGUMENT;
    if (!(Fp = fopen(RSAPubKeyFileName, "wb"))) //RSAPubKeyFileName为保存rsa私钥的文件路径
    {
        return ERR_OPENFILE;
    }

    if (!PEM_write_RSA_PUBKEY(Fp, rsa))  //写入公钥
    {
        fclose(Fp);
        return ERR_WRITEPUBLIC;
    }
    fclose(Fp);


    return 0;
}

3、通过RSA私钥进行签名

其中,from为要进行加密的数据,flen为数据长度,EncryptedStr指向加密后的数据,EncryptedLen为加密后数据长度。

RSA_PKCS1_PADDING为填充模式,有好几种。

int GeneratorRsaKey::PrivateKeyEncrypt(uint8_t* from, int flen)
{
    //---------------从文件中读取私钥并生成rsa------------------------------
    ENGINE* e = NULL;
    EVP_PKEY* pkey = NULL;
    uint8_t pad;
    if (!bio_err) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    pad = RSA_PKCS1_PADDING;
    if (!(pkey = load_key(bio_err, RSAPriKeyFileName, FORMAT_PEM, 0,
        PassWord, e, "Private Key")))
    {
        return ERR_OPENFILE;
    }
    rsa = EVP_PKEY_get1_RSA(pkey);
    EVP_PKEY_free(pkey);


    //---------------RSA加密------------------------------
    //RSA_print_fp(stdout, rsa, 11);
    int Ret = 0;
    if ((int)(EncryptedLen = RSA_private_encrypt(flen, from, EncryptedStr, rsa, RSA_PKCS1_PADDING)) < 0)
    {
        Ret = ERR_PRIVATE_ENCRYPT;
        goto Failed;
    }

    return 0;
Failed:
    EncryptedLen = 0;
    return Ret;
}

4、通过RSA公钥进行验签

其中,from为rsa加密后的数据,flen为数据长度,DecryptedStr指向解密后的数据,DecryptedLen为解密后数据长度。可以通过对比内存中DecryptedStr所指数据与上面步骤3中加密前的数据是否一致来判断解密是否成功

int GeneratorRsaKey::PublicKeyDecrypt(uint8_t* from, int flen)
{
    uint32_t Size = 0;
    int Ret = 0;
    if (!rsa)
        return ERR_ARGUMENT;
    Size = RSA_size(rsa);
    if ((DecryptedLen = RSA_public_decrypt(flen, from, DecryptedStr, rsa, RSA_PKCS1_PADDING)) < 0)
    {
        printf("RSA_public_decrypt\r\n");
        Ret = ERR_DECRYPT;
        goto Failed;
    }
    return 0;
Failed:
    EncryptedLen = 0;
    return Ret;
}

5、RSA加密解密的三种填充模式

其中,本代码中采用用RSA_PKCS1_PADDING填充模式

此填充模式是最常用的填充模式,在此填充模式下输入的长度受加密钥的长度限制,输入的最大长度为加密钥的位数k-11。如果公钥的长度为1024位即128字节,那么输入的长度最多为128-11=117字节。如果长度小于117就需要填充。如果输入T的长度为55字节,填充后的块为EM,则EM格式如下:

  • EM= 0x00 || BT || PS || 0x00 || T

    · 首字节填充0x00,确保加密块的大小小于加密钥(可见第四部分加密要求)

    · BT仅一个字节,并只有三种选项0x00,0x01,0x02。其中0x02表示公钥加密,0x00,0x01表示私钥加密

    · PS表示填充字段,根据BT类型有不同的情况。1.对于公钥加密的情况(即BT=0x02),PS为随机生成的且不含0的数。2.BT=0x00,PS填充的值为0x00(只有输入T不以0x00开头时,BT才为0x00,否则会有歧义)。3.BT=0x01,PS填充0xFF。PS的长度为128-3-len(T)=70字节,所以PS随机数长度至少为8个字节

    · 而后填充0x00用于区分填充字段和输入信息

    · T为实际的输入

其余两种填充方式可查看其他博客中对填充模式的讲解(https://www.jianshu.com/p/0fc6631500e3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值