剛開始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