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)