python中rsa非对称算法(包含分段加解密分析)

import base64

from Crypto import Random
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.PublicKey import RSA


class RsaCode:


    def encrypt(self, msg):
        msg = msg.encode('utf-8')
        rsa_public_key = open('conf/public.pem').read()
        rsakey = RSA.importKey(rsa_public_key)
        cipher = Cipher_pkcs1_v1_5.new(rsakey)
        cipher_text = base64.b64encode(cipher.encrypt(msg))
        return cipher_text

    def decrypt(self, cipher_text):
        rsa_private_key = open('conf/private.pem').read()
        rsakey = RSA.importKey(rsa_private_key)
        cipher = Cipher_pkcs1_v1_5.new(rsakey)
        random_generator = Random.new().read
        text = cipher.decrypt(base64.b64decode(cipher_text), random_generator)
        return text.decode('utf8')

    def long_encrypt(self, msg):
        msg = msg.encode('utf-8')
        length = len(msg)
        default_length = 117
        # 公钥加密
        rsa_public_key = open('conf/public.pem').read()
        pubobj = Cipher_pkcs1_v1_5.new(RSA.importKey(rsa_public_key))
        # 长度不用分段
        if length < default_length:
            return base64.b64encode(pubobj.encrypt(msg))
        # 需要分段
        offset = 0
        res = []
        while length - offset > 0:
            if length - offset > default_length:
                res.append(pubobj.encrypt(msg[offset:offset + default_length]))
            else:
                res.append(pubobj.encrypt(msg[offset:]))
            offset += default_length
        byte_data = b''.join(res)
        return base64.b64encode(byte_data)

    def long_decrypt(self, msg):
        msg = base64.b64decode(msg)
        length = len(msg)
        default_length = 128
        # 私钥解密
        rsa_private_key = open('conf/private.pem').read()
        priobj = Cipher_pkcs1_v1_5.new(RSA.importKey(rsa_private_key))
        # 长度不用分段
        if length < default_length:
            return b''.join(priobj.decrypt(msg, b'xyz'))
        # 需要分段
        offset = 0
        res = []
        while length - offset > 0:
            if length - offset > default_length:
                res.append(priobj.decrypt(msg[offset:offset + default_length], b'xyz'))
            else:
                res.append(priobj.decrypt(msg[offset:], b'xyz'))
            offset += default_length

        return b''.join(res).decode('utf8')


message = '''{"userId":"2088002933729603","transLongitude":"55.755831","transLatitude":"37.617673","merNo":"M000178103","terminalNo":"mini202007030908154720106107","terminalLongitude":"65.755831","terminalLatitude":"77.617673","createTime":"1514561699","tradeType":"WX","orderId":"202207102377965187OR012471381501"}'''

test = RsaCode()
res_en = test.long_encrypt(message)
print('res_en', res_en)
res_de = test.long_decrypt(res_en)
print('res_de', res_de)
res_ren = 'sFXiDF+vDIKoIcOg/h9awIqYi0bOHAMXgmeYH4SBKolNXXUuYJAZhJpOh1MvIDxddxE5vvnHF9wUHbMPSB6wLfh+q+u5r6yBY1a5WP3mGETCxRDxThSxhAzKWzuSL2cwK3Teqz6cfL3qfXIEZp6s4iUeKv4HbBbGaVwyoLcrbfKCbBjNb+e4B3xHqesoab89icPT03N8KTqOll44gTMAMhiB13ABmp0EzEVu0ZYsqET73vyhh2hyPQQVb8ap9cKyiilNHVU42I4ET+5mBL31yOZOpC34ESIHcQKKgFhAndsHlUCwavRdZyobanTuYI7Pn0fEBnNqF5wdpVAp8evie82Lu0E52bmok8Ys3mty91yLvHmWkro7yqQz7iSVf40/QaB5Qjyu7jwucJGlBvF+Pc2/cgLvlocks7y+dE72wwEmWx3GgZBNS7OeQl6a34/OU0Uv34klxe94T8+c6/Q7roXSzTS3W6/EZjefIryWc+DUAqjkQYwhWo+ObT88Zq2X'
res_den = test.long_decrypt(res_ren)
print('res_den', res_den)

 

生产公钥私钥的脚本方法

from Crypto import Random
from Crypto.PublicKey import RSA
# 伪随机数生成器
random_gen = Random.new().read
# 生成秘钥对实例对象:1024是秘钥的长度
rsa = RSA.generate(1024, random_gen)
# 获取公钥,保存到文件
private_pem = rsa.exportKey()
with open('conf/private.pem', 'wb') as f:
    f.write(private_pem)
# 获取私钥保存到文件
public_pem = rsa.publickey().exportKey()
with open('conf/public.pem', 'wb') as f:
    f.write(public_pem)

 

  一、总结

  1)加密使用的是公钥对数据进行加密,而且当你使用一把1024bit的rsa公钥的时候,你一次只能加密最多117byte的数据:

  单次加密串的长度最大为(key_size/8 - 11)

  即加密的 plaintext 最大长度是 证书key位数/8 - 11, 例如1024 bit的证书,被加密的串最长 1024/8 - 11=117。

  至于key的个数,是通过监测Crypto模块中计算key位数的代码来查看的,print(len(key))来查看key的位数这种方式得到的结果是错误的。

 

  2)加密之后进行的字符串拼接:

  不可以用byte类型进行拼接,其实''.join(res)是将列表中的各个字符串元素拼接成一个字符串,但是这里加密后

  返回的结果类型是byte类型的,不是str,所以才报错了。解决方法就是做bytes拼接,在''.join(res)前加b就可以了,修改

  后的为b''.join(res)【此处b 指的是bytes类型】。

  3)关于解密:

  decrypt方法,这个方法有两个参数,第一个参数是解密的内容,第二个参数是解密错误后返回的结果,这个结

  果也需要转换成byte类型。

  4)关于公钥私钥:

  建议一定使用自动生成的.pem文件,避免读取产生问题。

  二、其他

  OverflowError: 458 bytes needed for message, but there is only space for 117

  【由于RSA的特性,一个1024位的密钥只能加密117位字节数据,当数据量超过117位字节的时候,程序就会抛出异常。】

  解决方式如下:(包含处理不规则公钥格式方法 handle_pub_key(key))

import rsa
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
#rsa加密,通常对加密结果进行base64编码

def handle_pub_key(key):
    """
    处理公钥
    公钥格式pem,处理成以-----BEGIN PUBLIC KEY-----开头,-----END PUBLIC KEY-----结尾的格式
    :param key:pem格式的公钥,无-----BEGIN PUBLIC KEY-----开头,-----END PUBLIC KEY-----结尾
    :return:
    """
    start = '-----BEGIN PUBLIC KEY-----\n'
    end = '-----END PUBLIC KEY-----'
    result = ''
    # 分割key,每64位长度换一行
    divide = int(len(key) / 64)
    divide = divide if (divide > 0) else divide + 1
    line = divide if (len(key) % 64 == 0) else divide + 1
    for i in range(line):
        result += key[i * 64:(i + 1) * 64] + '\n'
    result = start + result + end
    return result


def get_param(message, public_key):
    """
    处理长消息 不经过 这个处理回报下面error
    OverflowError: 458 bytes needed for message, but there is only space for 117
    :param message 消息
    :param public_key 公钥
    :return:
    """
    pubkey = rsa.PublicKey.load_pkcs1_openssl_pem(public_key)
    crypto = b''
    divide = int(len(message) / 117)
    divide = divide if (divide > 0) else divide + 1
    line = divide if (len(message) % 117 == 0) else divide + 1
    for i in range(line):
        crypto += rsa.encrypt(message[i * 117:(i + 1) * 117].encode(), pubkey)

    crypto1 = base64.b64encode(crypto)
    return crypto1.decode()



if __name__ == '__main__':
    message = '''{"userId":"2088002933729603","transLongitude":"55.755831","transLatitude":"37.617673","merNo":"M000178103","terminalNo":"mini202007030908154720106107","terminalLongitude":"55.755831","terminalLatitude":"37.617673","createTime":"1414561699","tradeType":"WX","orderId":"202207102377965187OR012471381501"}'''
    rsa_public_key = open('conf/public.pem').read()
    param = get_param(message, rsa_public_key)
    print(param)

 

posted @ 2022-07-14 10:20  渐逝的星光  阅读(1045)  评论(0编辑  收藏  举报