关于RSAES-OAEP和RSASSA-PSS编码的介绍及C语言实现

本文介绍了RSA的OAEP和PSS加密机制在最优实践中的应用,重点讲解了这两种算法在openssl中的实现,并提供了一段C代码示例,适合在嵌入式芯片固件中的简化编码解码部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先介绍下OAEP和PSS的英文缩写:

OAEP= Optimal Asymmetric Encryption Padding, 翻译为中文是最优非对称加密填充。

PSS = Probabilistic Signature Scheme,翻译为中文就是概率签名方案。

RSA的加密机制有两种方案:一个是RSAES-OAEP,另一种是RSAES-PKCS1-v1_5。RSAES前缀的意思是RSA ENCRYPTION SCHEME。PKCS#1推荐在新的应用中使用RSAES-OAEP,因为其安全性更高,规范保留对RSAES-PKCS#1-v1_5的支持是为了跟老的应用保持兼容。它们两的区别仅仅在于加密前编码的方式不同。而加密前的编码是为了提供了抵抗各种活动的敌对攻击的安全机制。

PKCS#1的签名机制也有种方案:RSASSA-PSS和RSASSA-PKCS1-v1_5。RSASSA前缀的意思是SIGNATURE SCHEMES WITH APPENDIX。同样,推荐RSASSA-PSS用于新的应用,而RSASSA-PKCS1-v1_5只用于兼容老的应用。

两种填充算法在openssl中都有实现,但是如果希望在嵌入式芯片中实现这部分内容就比较困难了,本文参考openssl代码实现了一份可在嵌入式固件中使用的纯C代码,供大家参考。为了简单,只实现编码解码部分内容,不涉及加密解密、签名验签的完整功能。

工程文件如下图所示:

rsa_oaep.h文件内容:

#ifndef __RSA_OAEP_H
#define __RSA_OAEP_H

#ifndef IN
#define IN
#endif

#ifdef __cplusplus
extern "C" {
#endif


/*
// Prototype:int RSA_padding_add_PKCS1_OAEP(int hash_alg,
//    unsigned char *to, int tlen,
//    const unsigned char *from, int flen,
//    const unsigned char *label, int lable_len);
// Parameters:
//    hash_alg: Hash alogorithm, could be the following value:
//        HASH_ALG_SHA1: SHA-1;
//        HASH_ALG_SHA256: SHA-256;
//    to: The buffer which is used to store the target data after padding.
//    tlen: The expected length of data after padding.
//    from: Original data.
//    flen: The length of original data.
//    label: Optional label to be associated with the message; if not provided, is the empty string.
//    label_len: The length of label, if not provided, should be set to 0.
// return:
//    1: Succeed;
//    0: Fail;
// remarks: This function is used to pad the original data according to PKCS#1 OAEP rules.
*/
int RSA_padding_add_PKCS1_OAEP(IN int hash_alg,
    OUT unsigned char *to, IN int tlen,
    IN const unsigned char *from, IN int flen,
    IN const unsigned char *label, IN int lable_len);

/*
// int RSA_padding_check_PKCS1_OAEP(int hash_alg, unsigned char *to, int tlen,
//    IN unsigned char *from, int flen, int num,
//    IN unsigned char *param, int plen);
// Parameters:
//    hash_alg: Hash alogorithm, could be the following value:
//        HASH_ALG_SHA1: SHA-1;
//        HASH_ALG_SHA256: SHA-256;
//    to: The buffer which is used to store the original data after decoding.
//    tlen: The buffer length of "to".
//    from: The data buffer for decoding.
//    flen: The buffer length of "from".
//    num: The length of RSA modulus.
//    param: Optional label to be associated with the message; if not provided, is the empty string.
//    plen: The length of label, if not provided, should be set to 0.
// return:
//    >0: Succeed, return the length of original data (before padding).
//    Other values: Fail;
// remarks: This function is used to check the format of PKCS #1 OAEP padding.
*/
int RSA_padding_check_PKCS1_OAEP(IN int hash_alg, OUT unsigned char *to, IN int tlen,
    IN unsigned char *from, IN int flen, IN int num,
    IN unsigned char *param, IN int plen);

#ifdef __cplusplus
}
#endif

#endif // __RSA_OAEP_H

rsa_pss.h文件内容:

#ifndef __RSA_PSS_H
#define __RSA_PSS_H

#ifndef IN
#define IN
#endif

#ifdef __cplusplus
extern "C" {
#endif

/*
// Prototype:int RSA_padding_add_PKCS1_PSS(int rsaLen, unsigned char *EM,
//    IN unsigned char *mHash,
//    int hash_alg, int sLen);
// Parameters:
//    rsaLen: The length of RSA modulus in bits;
//    EM: Encoded message after padding.
//    mHash: The digest value.
//    hash_alg: Hash alogorithm, could be the following value:
//        HASH_ALG_SHA1: SHA-1;
//        HASH_ALG_SHA256: SHA-256;
//    sLen: The length of salt data. If it's set to -1, it will be set to the length of digest internally.
// return:
//    1: Succeed;
//    0: Fail;
// remarks: This function is used to pad the original data according to EMSA-PSS encoding rules.
*/
int RSA_padding_add_PKCS1_PSS(IN int rsaLen, OUT unsigned char *EM,
    IN unsigned char *mHash,
    IN int hash_alg, IN int sLen);

/*
// Prototype:int RSA_verify_PKCS1_PSS(int rsaLen, unsigned char *mHash,
//    int hash_alg, IN unsigned char *EM, int sLen);
// Parameters:
//    rsaLen: The length of RSA modulus in bits;
//    mHash: The digest value.
//    hash_alg: Hash alogorithm, could be the following value:
//        HASH_ALG_SHA1: SHA-1;
//        HASH_ALG_SHA256: SHA-256;
//    EM: Encoded message.
//    sLen: The length of salt data.
// return:
//    1: Succeed;
//    0: Fail;
// remarks: This function is used to check the format of EMSA-PSS padding.
*/
int RSA_verify_PKCS1_PSS(IN int rsaLen, IN unsigned char *mHash,
    IN int hash_alg, IN unsigned char *EM, IN int sLen);



#ifdef __cplusplus
}
#endif


#endif // __RSA_PSS_H

测试代码:

void TestRsaOaepEncoding()
{
    BYTE pbData[256];
    BYTE pbTo[256];

    int i;
    int ret;

    char *szOrigData = "151515151515151551515151515151511515151515151515";
    BYTE pbOrigData[256];
    WORD wOrigDataLen = (WORD)strlen(szOrigData) / 2;
    utlStrToHex(pbOrigData, szOrigData, wOrigDataLen);

    ret = RSA_padding_add_PKCS1_OAEP(HASH_ALG_SHA256, pbData, 256,
        pbOrigData, wOrigDataLen,
        //NULL, 0);
        (const BYTE *)"Hello", 5);
    if (!ret)
    {
        printf("RSA_padding_add_PKCS1_OAEP failed!");
        return;
    }

    ret = RSA_padding_check_PKCS1_OAEP(HASH_ALG_SHA256, 
        pbTo, 256,    //Used to store original data
        pbData, 256, //The data used for decoding
        256,    //Rsa modulus len
        //NULL, 0);
        (BYTE*)"Hello", 5);    //Optional label
    if (!ret)
    {
        printf("RSA_padding_check_PKCS1_OAEP failed!");
        return;
    }
}


void TestRsaPssEncoding()
{
    unsigned char mHash[32];
    unsigned char EM[256];

    for (int i = 0; i < 32; i++)
    {
        mHash[i] = i;
    }

    int ret = RSA_padding_add_PKCS1_PSS(2048, //RSA len, in bits
        EM,        //Buffer to store encoded message
        mHash,    //Digest of Hash, if we use SHA-1, only the first 20 bytes are used.
        HASH_ALG_SHA256, //Hash algorithm
        13);    //Salt data length
    if (!ret)
    {
        printf("RSA_padding_add_PKCS1_PSS failed!");
        return;
    }

    ret = RSA_verify_PKCS1_PSS(2048, //RSA len, in bits
        mHash,    //Digest of hash
        HASH_ALG_SHA256, //Hash algorithm
        EM, //Encoded message
        13);    //Salt data length
    if (!ret)
    {
        printf("RSA_verify_PKCS1_PSS failed!");
        return;
    }
}

因为优快云上传附件比较麻烦, PKCS#1 V2.2规范及完整代码请到我的主页下载:

www.sec007.com

《PKCS #1 v2.1 RSA算法详解与标准规范》将为你提供关于PKCS #1 v2.1标准的深入理解,尤其是RSA加密签名机制的实现细节。当你需要在应用程序中实现安全的数据加密与解密操作时,本资源将是你的首选参考。 参考资源链接:[PKCS #1 v2.1 RSA算法详解与标准规范](https://wenku.youkuaiyun.com/doc/2ssizyjpdj?spm=1055.2569.3001.10343) 具体来说,要根据PKCS #1 v2.1标准在应用中实现RSA加密签名,你需要执行以下步骤: 1. **密钥生成**:首先,生成一对RSA密钥(公钥私钥)。可以使用各种密码学库,如OpenSSL、Bouncy Castle等,通过RSA算法生成指定长度的密钥对。 2. **RSAES-OAEP加密**:使用RSAES-OAEP算法对数据进行加密。这个算法包含两个步骤:首先是将数据编码成一个摘要,然后使用公钥对这个摘要进行加密。编码过程中,会使用到一个称为“标签”(Label)的字符串一个随机数作为输入,这个过程提高了加密的安全性。 3. **RSASSA-PSS签名**:使用RSASSA-PSS算法进行签名。该算法会对数据的摘要进行加密,生成签名。加密过程中,除了数据摘要外,还会使用到一个随机数,这个随机数被称作“盐”(Salt)。这个“盐”增加了签名过程的不可预测性,从而提高了安全性。 在编程实现时,你需要调用相应库提供的API来执行这些操作,比如在Java中可以使用Bouncy Castle库: ```java import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.Cipher; import org.bouncycastle.crypto.engines.RSAEngine; import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.signers.PSSSigner; import org.bouncycastle.crypto.util.DefaultCryptoServicesRegistrar; import java.security.SecureRandom; // 密钥生成 RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( new BigInteger( 参考资源链接:[PKCS #1 v2.1 RSA算法详解与标准规范](https://wenku.youkuaiyun.com/doc/2ssizyjpdj?spm=1055.2569.3001.10343)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

l_z_h

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值