下面是加密的代码,对于输入的字符,每个字符单独进行加密,但是加密之后的位数不一样,是因为没有填充的关系吗,那要如何解决呢
void RSA::Encrypt(const char *filename, const char *output, const char *pub_key_file)
{
char in[1024];
CStringA strN, strE;
FILE *old_file,*new_file,*pub; //源文件、目标文件、公钥文件
__int64 pub_key,len,i,total;
unsigned char cleartext[10005];
pub=fopen(pub_key_file,"rb"); //公钥文件加载公钥
if(pub==NULL)
return;
fscanf(pub, "%s\n", in);
strE = in; //读入e
strcpy(in, "");
fscanf(pub, "%s\n,", in);
strN = in; //读入n
old_file=fopen(filename,"rb");
if(old_file==NULL)
return;
total=0;
len=fread(cleartext,1,10000,old_file);
total = len;
fclose(old_file);
old_file=fopen(filename,"rb");
if(old_file==NULL)
return;
new_file=fopen(output,"wb");
if(new_file==NULL)
return;
fwrite(&total,sizeof(__int64),1,new_file);
CBigInt m, e, n, c; //构造大数对象并初始化为零
CStringA strC;
e.Get(strE, 10);
n.Get(strN, 10);
memset(cleartext,0x0000,sizeof(cleartext));//清零
len=fread(cleartext,1,10000,old_file);
for (i = 0; i < len; i++)
{
m.Mov(cleartext[i]);
c.Mov(m.RsaTrans(e, n)); //c=m^e mod n
c.Put(strC, 10);
char out[1024] = "";
strncpy(out, strC, strC.GetLength());
out[strC.GetLength()] = '\0';
fprintf(new_file, "%s\n", out);
}
fclose(old_file);
fclose(new_file);
}
明文长度小于等于密钥长度(Bytes)-11,这说法本身不太准确,会给人感觉RSA 1024只能加密117字节长度明文。实际上,RSA算法本身要求加密内容也就是明文长度m必须0n,运算就会出错?!那怎么办?且听下文分解。
所以,RSA实际可加密的明文长度最大也是1024bits,但问题就来了:
如果小于这个长度怎么办?就需要进行padding,因为如果没有padding,用户无法确分解密后内容的真实长度,字符串之类的内容问题还不大,以0作为结束符,但对二进制数据就很难理解,因为不确定后面的0是内容还是内容结束符。
只要用到padding,那么就要占用实际的明文长度,于是才有117字节的说法。我们一般使用的padding标准有NoPPadding、OAEPPadding、PKCS1Padding等,其中PKCS#1建议的padding就占用了11个字节。
如果大于这个长度怎么办?很多算法的padding往往是在后边的,但PKCS的padding则是在前面的,此为有意设计,有意的把第一个字节置0以确保m的值小于n。
这样,128字节(1024bits)-减去11字节正好是117字节,但对于RSA加密来讲,padding也是参与加密的,所以,依然按照1024bits去理解,但实际的明文只有117字节了。
关于PKCS#1 padding规范可参考:RFC2313 chapter 8.1,我们在把明文送给RSA加密器前,要确认这个值是不是大于n,也就是如果接近n位长,那么需要先padding再分段加密。除非我们是“定长定量自己可控可理解”的加密不需要padding。