還是老規矩,本文重要部分就是文章結尾的代碼,路過的大佬不想聽鹹魚嘮嗑的直接劃到結尾拿代碼就好了,記得點讚,寶貝。
先講講為什麼寫這篇文章,就是昨天分析了某服務平臺的加密數據分析,果不其然炸了不少小白讀者,老夫甚是欣慰。
於是,在孤寂的深夜。
有讀者找到我想問問關於AES加密的 Python 實現應該怎麼寫,聽到這個需求我第一時間是拒絕的
對,就是這麼真實,畢竟我是鹹魚,能 BB 絕對不會動手的
但是,畢竟讀者爸爸都是磨人的小妖精,所以我屈服了。
之後我就打開了某個不可描述的網站開始找資源
果然,找到了不少關於 AES 加密的文章,不過看文章的日期基本是2017-2019的居多。
而且這裡一定要提一句,Python 的 PyCrypto 已死,現在用 Python 實現加密常用的是PyCryptodom
PyCryptodom可以使用下面這句命令安裝
pip3 install pycryptodome
# pip3 install -i https://pypi.douban.com/simple pycryptodome然後不停使用 CV 大法調試網上的代碼,不得不吐槽一句,C*DN 網站真的垃圾,十篇文章有九篇文章雷同。
先看下關於pycryptodome的用法
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from Crypto.Cipher import AES如果有嘗試過用 Python 實現的朋友一定遇到過下面的報錯
TypeError: Object type <class 'str'> cannot be passed to C code這個報錯的解決辦法非常簡單,但是昨晚沒有找到原因的時候真的和噩夢一樣
最後在stackoverflow找到了處理辦法,大家可以去圍觀下
https://stackoverflow.com/questions/50302827處理辦法也很簡單,encode就行了
obj = AES.new('This is a key123'.encode("utf8"), AES.MODE_CBC, 'This is an IV456'.encode("utf8"))解決了這個問題之後,之後就是通暢無阻了
這裡直接給出AES-CBC兩種輸出的代碼,以下代碼的加解密結果與http://tool.chacuo.net/cryptaes相同。
AES-CBC 輸出 Hash 的示例代碼
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
class PrpCrypt(object):
def __init__(self, key):
self.key = key.encode('utf-8')
self.mode = AES.MODE_CBC
# 加密函數,如果text不足16位就用空格補足為16位,
# 如果大於16當時不是16的倍數,那就補足為16的倍數。
def encrypt(self, text):
text = text.encode('utf-8')
cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF')
# 這裡密鑰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進位字符串
return b2a_hex(self.ciphertext)
# 解密後,去掉補足的空格用strip() 去掉
def decrypt(self, text):
cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF')
plain_text = cryptor.decrypt(a2b_hex(text))
# return plain_text.rstrip('\0')
return bytes.decode(plain_text).rstrip('\0')
if __name__ == '__main__':
pc = PrpCrypt('jo8j9wGw%6HbxfFn') # 初始化密鑰 key
e = pc.encrypt('{"code":200,"data":{"apts":[]},"message":"","success":true}') # 加密
d = pc.decrypt("lXgLoJQ3MAUdzLX+ORj5/pJlkRAU423JfyUKVd5IwfCSxw6d1mHwBdHV9p3kmKCYwNRmAIEWeb/9ypLCqTZ1FA==") # 解密
print("加密:", e)
print("解密:", d)AES-CBC 輸出 Base64 的示例代碼
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import base64
class PrpCrypt(object):
def __init__(self, key):
self.key = key.encode('utf-8')
self.mode = AES.MODE_CBC
# 加密函數,如果text不足16位就用空格補足為16位,
# 如果大於16當時不是16的倍數,那就補足為16的倍數。
def encrypt(self, text):
text = text.encode('utf-8')
cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF')
# 這裡密鑰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)
return base64.b64encode(self.ciphertext).decode()
# 解密後,去掉補足的空格用strip() 去掉
def decrypt(self, text):
cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF')
decryptByts = base64.b64decode(text)
plain_text = cryptor.decrypt(decryptByts)
return bytes.decode(plain_text).rstrip('\0')
if __name__ == '__main__':
pc = PrpCrypt('jo8j9wGw%6HbxfFn') # 初始化密鑰 key
e = pc.encrypt('{"code":200,"data":{"apts":[]},"message":"","success":true}') # 加密
d = pc.decrypt("lXgLoJQ3MAUdzLX+ORj5/pJlkRAU423JfyUKVd5IwfCSxw6d1mHwBdHV9p3kmKCYwNRmAIEWeb/9ypLCqTZ1FA==") # 解密
print("加密:", e)
print("解密:", d)這裡只給出了代碼,關於 AES 的原理講解之類的信息在夜幕的系列課程已經講過了,這裡不再贅述。
今天的內容就到這裡,咱們下次再會~