质数, 素数,这两个名词很多人在数学习课本里都听过,好像在中学的数学课本里就有了,它们表示同一个东西,只是两种不同叫法,那什么是质数?
任意一个数如果只能被1和它本身整除,这个数就是质数。
那什么是互质关系呢?如果两个正整数,除了1以外,没有其他公因子,那这两个数就是互质关系。
通过互质关系的概念,不难发现两个质数肯定是互质关系,但不一定互质关系的两个数一定都是是质数,比如15与32。以下是别人关于互质关系的总结:
a. 任意两个质数构成互质关系,比如13和61。
b. 一个数是质数,另一个数只要不是前者的倍数,两者就构成互质关系,比如3和10。
c. 如果两个数之中,较大的那个数是质数,则两者构成互质关系,比如97和57。
d. 1和任意一个自然数是都是互质关系,比如1和99。
e. p是大于1的整数,则p和p-1构成互质关系,比如57和56。
f. p是大于1的奇数,则p和p-2构成互质关系,比如17和15。
跟DES,AES一样, RSA也是一个块加密算法( block cipher algorithm),总是在一个固定长度的块上进行操作。但跟AES等不同的是, block length是跟key length 以及所使用的填充模式 有关的。
RSA的填充方式,目前通常有三种:
1) RSA_PKCS1_PADDING
输入必须 比 RSA 钥模长(modulus) 短至少11个字节, 也就是 RSA_size(rsa) – 11
如果输入的明文过长,必须切割, 然后填充。
2)RSA_PKCS1_OAEP_PADDING
输入必须 比 RSA 钥模长(modulus) 短至少41个字节, 也就是RSA_size(rsa) – 41
3)RSA_NO_PADDING
这个是不做填充,输入可以和RSA钥模长一样长,如果输入的明文过长,必须切割, 然后填充,这里填充通常是在明文的前面填充零,解密后的明文也会包括前面填充的零。
这里要说一下,RSA加减密有“裸”与“国际范”两种,下面分别从这两个方面作介绍:
1)“裸”
这里的“裸”就是针对有没有padding而言的,有时我们经常遇到,自己写的算法,加密或签名后,对方那边解不开或验证失败,原因都是因为双方padding的方式不同导致的。
2)“国际范”,很多编程言语,比如java,c#等等,都有对应的加密包,我们直接调用里面的函数就可以实现各种加解密,签名验证,证书生成等各种功能,它们都是标准的算法,所以对加密都是严格按照要求来的,也就是明文块不够模长度时,要用padding的方式进行填充,一般默认的padding都是PKCS#1。
另外“国际范”还有严格的文档规范,比如PKCS #1 v1.5规范中有这样的要求:
”[RFC2313] PKCS #1: RSA Encryption Version 1.5“的”8.1 Encryption-block formatting“节提供了详细的说明,原文如下:
“`
8.1 Encryption-block formatting
A block type BT, a padding string PS, and the data D shall be
formatted into an octet string EB, the encryption block.
EB = 00 || BT || PS || 00 || D . (1)
The block type BT shall be a single octet indicating the structure of
the encryption block. For this version of the document it shall have
value 00, 01, or 02. For a private- key operation, the block type
shall be 00 or 01. For a public-key operation, it shall be 02.
The padding string PS shall consist of k-3-||D|| octets. For block
type 00, the octets shall have value 00; for block type 01, they
shall have value FF; and for block type 02, they shall be
pseudorandomly generated and nonzero. This makes the length of the
encryption block EB equal to k.
“`
简单说来,PKCS #1 v1.5规定的填充格式为:
EB = 00 || BT || PS || 00 || D
D: data (指待处理数据,即填充前的原始数据)
PS: padding string (填充字符串)
BT: block type (数据块类型)
EB: encryption block (待加密的数据块,经过填充后结果)
||: 表示连接操作 (X||Y表示将X和Y的内容连接到一起)
“填充块类型”BT决定了紧挨着的”填充字符串”PS的内容。
BT的可能取值包括00, 01和02:
A)针对私钥处理的数据,BT取值为00或01;
* BT取值为00时,PS为全00的字符串
* BT取值为01时,PS为全FF的字符串,通过填充得到的整数会足够大,可以阻止某些攻击,因此也是推荐的填充方式.
B)针对公钥处理的数据,BT取值为02;
* 使用伪随机的16进制字符串填充PS,而且每次操作进行填充的伪随机书都是独立的。
重点来了,针对公钥处理的数据,其填充内容为伪随机的16进制字符串,每次操作的填充内容都不一样。这就是为什么每次使用公钥加密数据得到的结果都不一样了。
另外,注意到D前面还有一个00,这个00与开头的那个00都是标记,通过00可以知道那里是实际的data,那里是padding,这也说明了一点,我们padding的内容中除了全是00,其他情况里不能再含有00的随机数,什么意思,比如针对公钥处理的数据,PS是随机数,那么随机数中不能含有00的数据,否则就没法判断那里开始是data,所以,一切反动派都是纸老虎嘛,加密就是最初那些人定义的一套游戏规则。
好了,上面说了加密时要按规则padding,那解密呢,自然也是按规则去解密,也就是说先对module长度的密文解密,解出module长度的明文,然后再根据那些标记把PS和标记去除,剩下的就是我们实际的明文。