• python3 实现RSA算法分段加密解密


    参考博客地址:

    https://blog.csdn.net/qq_33414271/article/details/78424951

    https://www.cnblogs.com/piperck/p/7257043.html

    最近由于工作的需要,需要写mock,写mock就需要接触到加密解密签名验签的问题,下面是一些总结(只针对加密解密):

    加密解密概念

    关于加解密和加签验签的概念参考上面的第二个博主内容,解释的很到位,这里直接摘取过来了:

      加密和加签完全不是同样一件事情。

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

    如果数据量超过这个数,可能会涉及到对数据进行分段加密的问题。而且现在rsa 1024bit长度的钥匙已经被证明了不够安全,

    应该尽量使用2048bit长度的钥匙。2048bit长度的钥匙一次可以加密245byte长度的数据。这个计算方法是 2048bit/8 =

    256byte - 11byte = 245byte长数据。就是钥匙长度减去11byte得到的自己最大能一次加密多长的数据。如果超过了就会报错,

    所以很多平台要求对数据用公钥进行加密,就可能涉及到分段加密的问题。同时要注意的是,解密的时候不存在这11byte的

    减少。就是说一把1024bit的钥匙可以解密128byte长的数据而2048bit的可以解密256byte的数据。

      而加签是使用自己的私钥对需要加签的字符串进行签名。而对方需要拿着你给的公钥来验证这个数据是不是由你发出的,

    需要使用公钥对数据进行验签。如果成功验签才能说明你是你。

    代码实现

    这里公钥私钥是找开发要的,不是自己生成的,因为是做mock,需要和开发的公钥私钥一致。 

    实现加密代码:

    from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
    from Crypto.PublicKey import RSA
    import base64
    
    
    '''
    单次加密串的长度最大为(key_size/8 - 11)
    加密的 plaintext 最大长度是 证书key位数/8 - 11, 例如1024 bit的证书,被加密的串最长 1024/8 - 11=117,
    解决办法是 分块 加密,然后分块解密就行了,
    因为 证书key固定的情况下,加密出来的串长度是固定的。
    '''
    
    
    def rsa_long_encrypt(pub_key_str, msg):
        msg = msg.encode('utf-8')
        length = len(msg)
        default_length = 117
        #公钥加密
        pubobj = Cipher_pkcs1_v1_5.new(RSA.importKey(pub_key_str))
        #长度不用分段
        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)

    这里有个问题,我怎么知道证书key的位数呢?开始的时候尝试过用print(len(key))来查看key的位数,但是输出的结果不对,

    最后是通过监测Crypto模块中计算key位数的代码来查看的:

    上面的modBits值就是key的位数。

    根据需要,可以使用base64算法将二进制流转换成字符串。这里加密的时候还出现了一个问题,就是分段加密后最后拼接成一

    个加密串的时候报错了:

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

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

    后的为b''.join(res)。

    实现解密代码:

    def rsa_long_decrypt(priv_key_str, msg):
        msg = base64.b64decode(msg)
        length = len(msg)
        default_length = 128
        #私钥解密
        priobj = Cipher_pkcs1_v1_5.new(RSA.importKey(priv_key_str))
        #长度不用分段
        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)

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

    果也需要转换成byte类型。

    对加密解密代码进行测试:

    msg = '{"ApplyId":"20180504002","ChannelId":"O00420000001","LoanId":"9996401-5077812265125477811","LoanAmount":"5000.00""LoanPeriod":6,"LoanCardNo":"6225768313133272","BankId":"BANKLIST/ZHAOHANG"}'
    
    
    with open('rsa-public.pem') as f:
        '''读取公钥并加密'''
        key = f.read()
        result = rsa_long_encrypt(key, msg)
        print(result.decode('utf-8'))
    
    with open('rsa-private.pem') as f:
        '''读取私钥并解密'''
        key1 = f.read()
        result1 = rsa_long_decrypt(key1, data)
        print(result1.decode('utf-8'))

    这里可能会出现读取密钥格式错误的问题,这时需要在密钥的前后加上以下内容,如果是自动生成的.pem文件不会有这个问题的。

    公钥:

    私钥:

     以上

  • 相关阅读:
    python3.7版本安装pyinstaller
    Redis
    电商路演
    前台Vue、后台Django、设置axios解决csrf_token问题
    企业为什么要设置中台
    2021.1.11 学习总结
    2021.1.10 学习总结
    2021.1.9 学习总结
    2021.1.8 学习总结
    2021.1.7 学习总结
  • 原文地址:https://www.cnblogs.com/sammy1989/p/9583965.html
Copyright © 2020-2023  润新知