RSA

作者: 非你不可_a036 | 来源:发表于2019-10-15 18:38 被阅读0次

    一、RSA的使用

    RSA属于非对称加密,采用一对密钥进行加密(公钥和私钥),一个用来加密、另一个用来解密,非对称加密运算速率慢(需要采用大量的数学运算,一般用于少量信息加密)

    1.RSA三要素

    RSA加密需要三个值:n,e1, e2。

    n是两个质数的乘积,n的值越大,加密越安全,一般处于公开状态。

    e1是公钥中的e(指数),与n形成公钥,用于加密,一般处于公开状态。

    e2是私钥中的e(指数),与n形成私钥,用于解密,处于保密状态(不公开)。

    2.Python使用rsa包加密

    首先导入rsa包,把n和e转化为10进制。通过rsa.PublicKey(e=e, n=n)生成公钥。

    然后使用rsa.encrypt("8helkyme0ludtdw0".encode(), pub_key=key)进行加密,其中8helkyme0ludtdw0为加密的明文,由于rsa是对字节流进行加密,所以enode()。

    加密后的内容感觉乱七八糟的,一般在这时候使用hex(),把每个字节转化为两位16进制数(字节转变字符串),因此加密结果长度增加一倍。如图1所示。

    图1

    二、RSA原理

    假设a为明文,b为密文。

    加密:b=pow(a, e1, n)

    解密:a=pow(b, e2, n)

    1.n的来源

    n是通过两个质数相乘得到的,n的二进制长度就是密钥长度。RSA的密钥一般是1024位,少数是2048位。如图1中的modulus就是1024位。

    例:x和y是两个不同的质数:11和13,则n=11*13=143(加密内容不能超过143)。143的二进制是:10001111,为8位。则密钥为8位。

    2.e1的来源

    获取e1需要使用欧拉函数,再选取与φ(n)互质的一个数。

    φ(n)=(x-1)*(y-1)=10*12=120

    则:1<e1<120,且e1与120互质,如:e1=13,一般来说e1为65537。

    例:2与3只有公因数1,则2和3互质。

    3.e2的来源

    e2泄露则代表加密被破解,在rsa加密中的6个数字中,x,y,n,φ(n),e1,e2,n=x*y,φ(n)=(x-1)*(y-1),也就是说x,y一定不能泄露,否则6个数字已知晓了4个数字,再加上e1是公开的,所以e2就能被推算出来了。

    e1*e2 mod φ(n) = 1 即:e1*e2 = k * φ(n) + 1 —>  13*e2 = k*120 +1,这个使用“扩展欧几里得算法”求解。python实现方式如图2所示。

    图2

    由于“扩展欧几里得算法”中的方程式是13*e2 + k*120= 1,因此k是负数,最后得出:e2=37, k=-4。

    4.尝试加密解密

    从上文叙述已知:e1=13, e2=37, n=143,即公钥是(13,143),私钥是(37, 143)

    这里用数字9进行测试,即明文a=9,加密:b=pow(a, e1, n)=9^13%143=113

    明文9加密后得到密文b:113,解密:a=pow(b, e2, n) = 113^37%143=9

    三、RSA加密源码

    从图1中已知,使用rsa包就两步,首先传入e,n生成公钥,key=rsa.PublicKey(e=e, n=n)

    然后传入明文和公钥key,输出加密结果,h=rsa.encrypt("8helkyme0ludtdw0".encode(), pub_key=key)

    在encrypt()中就几步,首先看源码:

    def encrypt(message, pub_key):

    keylength = common.byte_size(pub_key.n)

    padded = _pad_for_encryption(message, keylength)

    payload = transform.bytes2int(padded)

    encrypted = core.encrypt_int(payload, pub_key.e, pub_key.n)

    block = transform.int2bytes(encrypted, keylength)

    return block

    从源码中可以看到需要两个参数,message是明文,pub_key是公钥。

    第一步:common.byte_size(pub_key.n)目的是计算n的二进制长度(位),然后除以8(字节),得到支持的最大加密长度。

    第二步:_pad_for_encryption(message, keylength)目的是对明文进行填充,右侧补全,填充值是使用os.urandom()随机生成的,因此每次填充结果不一样。

    第三步:transform.bytes2int(padded)目的是把每个字节转化为两位16进制来表示,再转化为10进制。

    第四步:core.encrypt_int(payload, pub_key.e, pub_key.n),对明文进行加密。

    第五步:transform.int2bytes(encrypted, keylength)目的是舍弃左侧的0,在右侧进行0补全,最后每64位进行一次封装。

    四、自己实现RSA加密

    import os

    import math

    import copy

    from structimport pack

    k ="8helkyme0ludtdw1".encode()

    modulus ="00A2FD668D79120D41EFFA26B0F5A5A43D6139D46893F7559CC2BA0C704BDA19A9420F97D113E32EF4E462C49F95B9DC487E2963F0FBE9C9C79DBD128D26C244D062BA69F9E7961D646193B8EF36814C7BB17053AB2418E1C8671781827D4BF3C6AA3D8B581FDF4F60210900EBD4AF34C5B51B77C73FB707448C527A56541B142B"

    e =int("010001", 16)

    n =int(modulus, 16)

    # 计算n的二进制长度,获取证书位数(1024和2048)

    key_length = math.ceil(n.bit_length() /8)

    # 预留11个字节,获取加密时支持的最大字节数

    max_msglength = key_length -11

    msg_length =len(k)

    if msg_length > max_msglength:

    raise OverflowError("超出可支持的最大加密长度,支持:[{}]字节,目前:[{}]字节".format(max_msglength, msg_length))

    padding_length = key_length - msg_length -3

    new_padding = os.urandom(int(padding_length) +5).replace(b'\x00', b'')

    padding = new_padding[:padding_length]

    padded =b''.join([b'\x00\x02', padding, b'\x00', k])

    # 原方法使用hexlify(),目的:每个字节的数据转换成相应的 2 位十六进制表示。因此产生的字符串是原数据的两倍长度

    # padded.hex()在python3.5以前的实现:''.join(['%02x' % b for b in a_bytes])

    # padded.hex()在python3.5以后的实现:a_bytes.hex()

    payload =int(padded.hex(), 16)

    # RSA加密

    encrypted =pow(payload, e, n)

    raw_bytes =b''

    num = copy.deepcopy(encrypted)

    # 加密内容进行包装

    while num >0:

    raw_bytes = pack(">Q", num &0xffffffffffffffff) + raw_bytes

    num >>=64

    # 获取左侧为0的长度

    leading =0

    for xin raw_bytes:

    if x ==0:

    leading +=1

        else:

    break

    # 舍弃左侧为0的数据,进行右侧补全

    if leading:

    raw_bytes = raw_bytes[leading:]

    raw_bytes = raw_bytes.rjust(int(key_length), b'\x00')

    result = raw_bytes.hex()

    这是对1024位密钥加密的实现,存在部分局限性。

    号外:

    RSA解密:

    解密原理与加密原理相同,不过多赘述,在使用python中的RSA包的时候,有一个坑,生成私钥需要传5个参数e,d,n,p,q。我们知道解密不需要e,p,q。从生成私钥源码中发现存在对p,q的检查,但是只是检查p,q是否互质。也就是说p,q传值2,3也可以。

    相关文章

      网友评论

          本文标题:RSA

          本文链接:https://www.haomeiwen.com/subject/fmtemctx.html