Pyhton AES CBC PKCS5加解密对接Java该类型的加解密

刚开始pyhton自己脚本加解密,网上很多方法,都能实现

# -*- coding: utf-8 -*-
# @Time    : 2019/3/11 11:14
# @Author  : guigle
# @File    : AES_CBC.py
# @Software: PyCharm
import base64

from Crypto.Cipher import AES
from binascii import b2a_base64, a2b_base64


# from binascii import  b2a_hex, a2b_hex


class PrpCrypt(object):

    def __init__(self, key, iv):
        self.key = key.encode('utf-8')
        self.iv = iv
        self.mode = AES.MODE_CBC
        # 指定填充
        self.bs = 16
        self.PADDING = lambda s: s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
        # self.PADDING = lambda s: s + ((self.bs - len(s) % self.bs)*' ').encode('utf-8')

    # 加密函数,如果text不足16位就用空格补足为16位,
    # 如果大于16当时不是16的倍数,那就补足为16的倍数。
    def encrypt(self, text):
        # text = text.encode('utf-8')
        # cryptor = AES.new(self.key, self.mode, b'0123qtwhdg1230mn')  # 偏移量必须是16位
        cryptor = AES.new(self.key, self.mode, self.iv)  # 偏移量必须是16位
        text = text.encode('utf-8')
        tt = self.PADDING(text)
        crypt = cryptor.encrypt(tt)
        crypted_str = base64.b64encode(crypt)
        # crypted_str = b2a_base64(crypt)
        result = crypted_str.decode()
        # 这里密钥key 长度必须为16(AES-128),
        # 24(AES-192),或者32 (AES-256)Bytes 长度
        # 目前AES-128 足够目前使用
        # length = 16
        # count = len(text)
        # if count < length:
        #     add = (length - count)
        #     # \0 backspace
        #     # text = text + ('\0' * add)
        #     text = text + ('\0' * add).encode('utf-8')
        # elif count > length:
        #     add = (length - (count % length))
        #     # text = text + ('\0' * add)
        #     text = text + ('\0' * add).encode('utf-8')
        # self.ciphertext = cryptor.encrypt(text)
        # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
        # 所以这里统一把加密后的字符串转化为16进制字符串b2a_hex(self.ciphertext)
        # 当然也可以转换为base64加密的内容,可以使用b2a_base64(self.ciphertext)
        # return b2a_base64(self.ciphertext)  # b2a_hex
        return result  # b2a_hex

    # 解密后,去掉补足的空格用strip() 去掉
    def decrypt(self, text):
        # cryptor = AES.new(self.key, self.mode, b'0123qtwhdg1230mn')  # 偏移量必须是16位
        cryptor = AES.new(self.key, self.mode, self.iv)  # 偏移量必须是16位
        plain_text = cryptor.decrypt(a2b_base64(text))  # a2b_hex
        # return plain_text.rstrip('\0')
        return bytes.decode(plain_text).rstrip('\0')


if __name__ == '__main__':
    # 初始化密钥  必须是16位  这个key和iv是去申请获取的
    # pc = PrpCrypt(key,iv)
    pc = PrpCrypt('TdoO7R7353nT2OWs', 'FxuveEaw8VPdg9lJ'.encode('utf-8'))
    e = pc.encrypt("颜老狗")  # 对某字符串加密
    print("加密:", e, type(e))

    # e2 = e.decode('utf-8')
    # print("加密解码", e2, type(e2))

    d = pc.decrypt('RpDvw0Jdh6lzCzhW4giqsg==')  # 解密
    print("解密:", d, type(d))
    # d2 = d.decode("utf-8")
    # print("解密:", d2, type(d2))

然后java自己脚本的加解密也没问题;但是出现python加解密自己能实现,也能解密java的加密内容。但是java那边解密不了我这边的,但在在线转换上我的是没有问题的。

后来换了种方法,以为可以了,实际上只是实现了英文的可以,由于一个英文对应1byte,一个中文对应2byte,于是用了如下方法.

由于java的PKCS5填充机制与python不同,所以用如下方式填充

# -*- coding: utf-8 -*-
# @Time    : 2019/3/11 11:14
# @Author  : guigle
# @File    : AES_CBC.py
# @Software: PyCharm
import base64
import re

from Crypto.Cipher import AES
from binascii import b2a_base64, a2b_base64


# from binascii import  b2a_hex, a2b_hex


class PrpCrypt(object):

    def __init__(self, key, iv):
        self.key = key.encode('utf-8')
        self.iv = iv
        self.mode = AES.MODE_CBC
        # 指定填充
        self.bs = 16
        self.PADDING01 = lambda s: s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
        self.PADDING02 = lambda s: s + bytes((self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs), encoding='utf8')
        # self.PADDING02 = lambda s: s + ((self.bs - len(s) % self.bs)*' ').encode('utf-8')

    def encrypt(self, text):
        # text = text.encode('utf-8')
        # cryptor = AES.new(self.key, self.mode, b'0123qtwhdg1230mn')  # 偏移量必须是16位
        cryptor = AES.new(self.key, self.mode, self.iv)  # 偏移量必须是16位
        contents = u'%s' % text
        zhmodel = re.compile(u'[\u4e00-\u9fa5]')  # 检查中文
        # zhmodel = re.compile(u'[^\u4e00-\u9fa5]')   #检查非中文
        match = zhmodel.search(contents)
        if match:
            text = text.encode('utf-8')
            tt = self.PADDING02(text)
            crypt = cryptor.encrypt(tt)
            crypted_str = base64.b64encode(crypt)
            # crypted_str = b2a_base64(crypt)
            result = crypted_str.decode()
            return result
        else:
            tt = self.PADDING01(text)
            crypt = cryptor.encrypt(tt.encode("utf-8"))
            crypted_str = base64.b64encode(crypt)
            # crypted_str = b2a_base64(crypt)
            result = crypted_str.decode()
            return result  # b2a_hex

    # 解密后,去掉补足的空格用strip() 去掉
    def decrypt(self, text):
        # cryptor = AES.new(self.key, self.mode, b'0123qtwhdg1230mn')  # 偏移量必须是16位
        cryptor = AES.new(self.key, self.mode, self.iv)  # 偏移量必须是16位
        plain_text = cryptor.decrypt(a2b_base64(text))  # a2b_hex
        # return plain_text.rstrip('\0')
        return bytes.decode(plain_text).rstrip('\0')


# if __name__ == '__main__':
#     # 初始化密钥  必须是16位  这个key和iv是去申请获取的
#     # pc = PrpCrypt(key,iv)
#     pc = PrpCrypt('TdoO7R7353nT2OWs', 'FxuveEaw8VPdg9lJ'.encode('utf-8'))
#     e = pc.encrypt("dsbltb")  # 对某字符串加密
#     print("加密:", e, type(e))
#
#     # e2 = e.decode('utf-8')
#     # print("加密解码", e2, type(e2))
#
#     d = pc.decrypt('RpDvw0Jdh6lzCzhW4giqsg==')  # 解密
#     print("解密:", d, type(d))
    # d2 = d.decode("utf-8")
    # print("解密:", d2, type(d2))

java的PKCS5和PKCS7填充机制

参考链接:https://blog.csdn.net/chary8088/article/details/21185187

拓展:

最近做到了关于加密和解密的部分。

使用算法AES的时候,涉及到数据填充的部分,数据的填充有很多种方案,用的比较多的有pkcs#5,pkcs#7,

下面的都是从网上转来的。结论就是在AES 的使用中,pkcs#5填充和pkcs#7填充没有任何区别。

 

PKCS #7 填充字符串由一个字节序列组成,每个字节填充该填充字节序列的长度。

假定块长度为 8,数据长度为 9,
数据: FF FF FF FF FF FF FF FF FF
PKCS7 填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07

简单地说, PKCS5, PKCS7和SSL3, 以及CMS(Cryptographic Message Syntax)

有如下相同的特点:
1)填充的字节都是一个相同的字节
2)该字节的值,就是要填充的字节的个数

如果要填充8个字节,那么填充的字节的值就是0×8;
要填充7个字节,那么填入的值就是0×7;

如果只填充1个字节,那么填入的值就是0×1;

这种填充方法也叫PKCS5, 恰好8个字节时还要补8个字节的0×08

正是这种即使恰好是8个字节也需要再补充字节的规定,可以让解密的数据很确定无误的移除多余的字节。

 

标准

PKCS #7: Cryptographic Message Syntax

在 10.3节中讲到了上面提到的填充算法,  对Block Size并没有做规定

PKCS #5: Password-Based Cryptography Specification

在6.1.1 中对 填充做了说明
但是因为该标准 只讨论了 8字节(64位) 块的加密, 对其他块大小没有做说明
其 填充算法跟 PKCS7是一样的

后来 AES 等算法, 把BlockSize扩充到 16个字节

比如, Java中
Cipher.getInstance(“AES/CBC/PKCS5Padding”)
这个加密模式
跟C#中的
RijndaelManaged cipher = new RijndaelManaged();
cipher.KeySize = 128;
cipher.BlockSize = 128;
cipher.Mode = CipherMode.CBC;
cipher.Padding = PaddingMode.PKCS7;
的加密模式是一样的

因为AES并没有64位的块, 如果采用PKCS5, 那么实质上就是采用PKCS7
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章