首先介绍下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;
}
}
因为CSDN上传附件比较麻烦, PKCS#1 V2.2规范及完整代码请到我的主页下载:
www.sec007.com