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
 

 

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