在开发过程中,发现iOS端经过RSA加密的密文传到服务端之后, 服务端无法解析,本来想通过比较同一段明文的加密结果,来判断服务端和iOS端加密方式的区别,结果发现加密结果一直不一样。然后服务端尝试多次加密同一段明文,得到的结果也不一样。 

然后就很震惊。学过密码学的我也知道RSA的原理, 类似:

1)、密文 = 明文^e mod n

2)、明文 = 密文^d mod n

3)、那么 publickKey = (e,n),privateKey = (d,n)

经过研究,发现目前的RSA算法其实都会在加密的过程中加入一个随机值,所以每次加密的结果都会不一样。那么既然每次加密的结果都不一样, 那怎么解密呢, 具体方案如下:

1)、 密文 =( random+明文) ^e mod n  //publicKey  加密

2)、(random+明文) = 密文^d mod n   // 服务器端利用privateKey 解密

3)、 明文 = (random+明文) - random //服务器端解码出random

 解决了这个疑问之后,有回到第一个问题,iOS加密的结果为何会解不出来呢。 答案是RSA算法添加随机数的方式也有很多种,因为iOS设定的padding方式和服务端的padding方式(即添加随机数的方式)不一样,导致服务端解析不出来密文。

 RSA加密常用的填充方式有下面3种:

1.RSA_PKCS1_PADDING 填充模式,最常用的模式 要求:

输入:必须 比 RSA 钥模长(modulus) 短至少11个字节, 也就是 RSA_size(rsa) – 11 如果输入的明文过长,必须切割, 然后填充

输出:和modulus一样长 根据这个要求,对于512bit的密钥, block length = 5128 – 11 = 53 字节

2.RSA_PKCS1_OAEP_PADDING

输入:RSA_size(rsa) – 41 输出:和modulus一样长

3.RSA_NO_PADDING  不填充

输入:可以和RSA钥模长一样长,如果输入的明文过长,必须切割, 然后填充 输出:和modulus一样长

用python实现RSA_PKCS1_PADDING填充的RSA代码如下:


import cgi, base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Hash import SHA
from Crypto import Random
 
# 私钥文件
priKey = '''-----BEGIN RSA PRIVATE KEY-----
xxxx
-----END RSA PRIVATE KEY-----'''
 
# 公钥文件
pubKey = '''-----BEGIN PUBLIC KEY-----
xxxx
-----END PUBLIC KEY-----'''
 
# 伪随机数生成器
random_generator = Random.new().read
 
 
'''*RSA加密
* data待加密数据
* 最后的加密结果,需要用base64编码
* return 加密结果
'''
 
 
def rsa_encrypt(data):
    key = RSA.importKey(pubKey)
    cipher = PKCS1_v1_5.new(key)
    cipher_text = base64.b64encode(cipher.encrypt(data))
    return cipher_text
 
 
'''*RSA解密
* encrypt_text待解密数据
* 解密用私钥
* return 解密的结果
'''
 
 
def rsa_decode(encrypt_text):
    key = RSA.importKey(priKey)
    cipher = PKCS1_v1_5.new(key)
    text = cipher.decrypt(base64.b64decode(encrypt_text), random_generator)
    return text