一、RSA_NO_PADDING模式,顾名思义,无填充;
测试运行时,也遇到几个问题,需要注意(以下举例均以模数1024bit,128字节):
1、加密数不能大于模数
否则,会报错:“data too large for modulus”,这个是正常的,否则大于模数解密时会出问题,因为加解密都是取模的。
因此,在读取文件加密时,每次读取128字节时,有可能大于模数,因此需要判断;大于模数时,读取127字节。
但问题也出来了:解密出来怎么判断第一个00是真实数据,还是需要去掉的呢?
PS:其他加密模式通过填充均避免了这种情况。
2、加密长度必须为keysize字节
如果不等于,则报错:“data too large /too small for key size”,因为无填充,所以你的输入必须满(特别是最后一个数,不足时需要自己填充了)!
善用RSA报错处理:
char err[256];
int ret = RSA_public_encrypt(keysize_y/8,buf,pEncode,rsaK,RSA_NO_PADDING);
if(ret==-1)
{
// ERR_load_RSA_strings();
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
printf("%s\n",err);
return;
}
二、RSA_PKCS1_PADDING 模式
/*
RFC 2313 - PKCS #1: RSA Encryption Version 1.5
EB = 00 || BT || PS || 00 || D
EB - Encryption Block
BT - Block Type :: 00 or 01 for private-key operation; 02 for public-key operation
PS - Padding String :: length = k-3-||D||
BT 00: all 00
BT 01: all FF
BT 02: pseudorandomly generated and nonzero
D - Data
k - length of modulus in octets
*/
1、填充规则如上(其实看英文理解的更好,翻译的有词不达意的),
(1)EB为填充完毕后的加密块,EB = 00 || BT || PS || 00 || D
(2)BT块类型,00/01为私钥操作;02为公钥操作(即公钥加密时置02.......)
(3)PS为填充数组,长度=模长-3-输入明文长度,BT=00时:填充全00;BT=01时填充全FF;BT=02时填充非零随机数(实测:只要非零即可)
(4)D为要加密的明文数据
2、注意
填充PS,至少8字节,所以,输入明文最多(模长-11)字节;
只要按以上规则填充加密,你就可以与openSSL互相加解密。
(填充完毕后,其实就是按照无填充模式加密了)填充第一字节为00,保证了输入小于模数,肯定可以加密成功。
去填充也很简单,根据填充格式去掉即可,主要是00....00,后面的就是真实明文了。
三、RSA_PKCS1_OAEP_PADDING模式
据说是最安全的一种填充。
参考:
与OpenSSL源码对照看,能看的更明白。
(1)其hash函数用的是sha1,输出是20字节;所以加密输入不能大于(模长-42)字节;42字节为2个20字节、2个1字节(00、01,PS可以没有);
(2)经测试,seed可以是任何数,全0、随机均可;
(3)利用源码和GMP库,自写加密,然后OpenSSL解密通过;需要注意的是:加密后的GMP大数在写入数组给OpenSSL解密时,要写入到模数大小的数组里,比如1024bit、256字节,要前面置0,而不是后面置0;即整个大数放到数组里应该就是原来的样子,如果只有255字节大小,应该第一个字节为0;而我在测试时直接从位置0开始写入的导入最后一个字节为0,是错误的。其他模式同理。
(4)利用源码和GMP库,自加密后,自解密时,先x^e mod n为pading后的数据EM(上图中的),此数据应该小于等于127字节(1024模数的话),因为EM第一字节为0(EM为大数时第一字节0实际不存在的),进行padding_check时,输入的数据就是这127字节的数据。(而不能是128字节带着第一字节0)