Python实现AES加解密以及发送加解密请求
AES加解密的类
python解释器用的是3.9,安装Crypto相关模块报错的解决方案:
https://stackoverflow.com/questions/19623267/importerror-no-module-named-crypto-cipher
import base64 from binascii import b2a_hex, a2b_hex from Crypto import Random from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad class AESUtil(object): # 使用ECB模式加密 MODE = AES.MODE_ECB # 使用默认的pkcs7 padding PAD_STYLE = 'pkcs7' ENCODING = 'UTF-8' # key长度只能为16或24或32,分别对应AES-128、AES-192、AES-256 @staticmethod def encrypt(plaintext: str, key: str) -> str: # 将密钥编码为UTF-8格式的bytes key_bytes = key.encode(AESUtil.ENCODING) # 创建AES对象 cipher = AES.new(key_bytes, AESUtil.MODE) # 将明文编码为UTF-8格式的bytes plaintext_bytes = plaintext.encode(AESUtil.ENCODING) # 为编码后的明文添加padding plaintext_bytes_padded = pad(plaintext_bytes, AES.block_size, AESUtil.PAD_STYLE) # 执行加密 ciphertext_bytes = cipher.encrypt(plaintext_bytes_padded) # 将加密后的bytes进行base64编码 # 注意:不能用encodebytes!否则会每76个字符增加一个换行符,见:https://docs.python.org/zh-cn/3/library/base64.html ciphertext_base64_bytes = base64.b64encode(ciphertext_bytes) # 将base64编码过的bytes,解码为Python中使用的字符串类型(即unicode字符串) ciphertext = ciphertext_base64_bytes.decode(AESUtil.ENCODING) return ciphertext @staticmethod def decrypt(ciphertext: str, key: str) -> str: # 将密钥编码为UTF-8格式的bytes key_bytes = key.encode(AESUtil.ENCODING) # 创建AES对象 decrypter = AES.new(key_bytes, AESUtil.MODE) # 将密文编码为UTF-8格式的(同时也是base64编码的)bytes ciphertext_base64_bytes = ciphertext.encode(AESUtil.ENCODING) # 将base64编码的bytes,解码为原始的密文bytes ciphertext_bytes = base64.b64decode(ciphertext_base64_bytes) # 解码为明文 plaintext_bytes_padded = decrypter.decrypt(ciphertext_bytes) # 去掉Padding plaintext_bytes = unpad(plaintext_bytes_padded, AES.block_size, AESUtil.PAD_STYLE) # 将UTF-8格式编码的明文bytes,解码为Python中的字符串类型(即unicode字符串) plaintext = plaintext_bytes.decode(AESUtil.ENCODING) return plaintext class PrpCrypt(object): def __init__(self, key): self.key = key.encode('utf-8') self.mode = AES.MODE_CBC self.iv = Random.new().read(AES.block_size) # 加密函数,如果text不足16位就用空格补足为16位, # 如果大于16当时不是16的倍数,那就补足为16的倍数。 def encrypt(self, text): text = text.encode('utf-8') cryptor = AES.new(self.key, self.mode, self.iv) # 这里密钥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).encode('utf-8') elif count > length: add = (length - (count % length)) 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, self.iv) plain_text = cryptor.decrypt(a2b_hex(text)) return bytes.decode(plain_text).rstrip('\0') if __name__ == '__main__': aes_key = 'sbsbsbsbsbsbsbsb' pc = PrpCrypt(aes_key) # 初始化密钥 data = "xxx123" print("原始data: ", data) print("--------------第1种方法符合服务端的AES对称加密算法: ") e1 = AESUtil.encrypt(data, aes_key) d1 = AESUtil.decrypt(e1, aes_key) print("加密:", e1) print("解密:", d1) print("--------------第2种方法不符合服务端的AES对称加密算法: ") e2 = pc.encrypt(data) # 加密 d2 = pc.decrypt(e2).encode() # 解密 print("加密:", e2) print("解密:", d2) """ 原始data: xxx123 --------------第1种方法符合服务端的AES对称加密算法: 加密: fRpmp7q6laM5A96Nr/ZyPA== 解密: xxx123 --------------第2种方法不符合服务端的AES对称加密算法: 加密: b'8efdb7c72cd323ee204e2f290e6becd5' 解密: b'xxx123' """
发动加密的post请请求
import base64 from binascii import b2a_hex, a2b_hex from Crypto import Random from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad class AESUtil(object): # 使用ECB模式加密 MODE = AES.MODE_ECB # 使用默认的pkcs7 padding PAD_STYLE = 'pkcs7' ENCODING = 'UTF-8' # key长度只能为16或24或32,分别对应AES-128、AES-192、AES-256 @staticmethod def encrypt(plaintext: str, key: str) -> str: # 将密钥编码为UTF-8格式的bytes key_bytes = key.encode(AESUtil.ENCODING) # 创建AES对象 cipher = AES.new(key_bytes, AESUtil.MODE) # 将明文编码为UTF-8格式的bytes plaintext_bytes = plaintext.encode(AESUtil.ENCODING) # 为编码后的明文添加padding plaintext_bytes_padded = pad(plaintext_bytes, AES.block_size, AESUtil.PAD_STYLE) # 执行加密 ciphertext_bytes = cipher.encrypt(plaintext_bytes_padded) # 将加密后的bytes进行base64编码 # 注意:不能用encodebytes!否则会每76个字符增加一个换行符,见:https://docs.python.org/zh-cn/3/library/base64.html ciphertext_base64_bytes = base64.b64encode(ciphertext_bytes) # 将base64编码过的bytes,解码为Python中使用的字符串类型(即unicode字符串) ciphertext = ciphertext_base64_bytes.decode(AESUtil.ENCODING) return ciphertext @staticmethod def decrypt(ciphertext: str, key: str) -> str: # 将密钥编码为UTF-8格式的bytes key_bytes = key.encode(AESUtil.ENCODING) # 创建AES对象 decrypter = AES.new(key_bytes, AESUtil.MODE) # 将密文编码为UTF-8格式的(同时也是base64编码的)bytes ciphertext_base64_bytes = ciphertext.encode(AESUtil.ENCODING) # 将base64编码的bytes,解码为原始的密文bytes ciphertext_bytes = base64.b64decode(ciphertext_base64_bytes) # 解码为明文 plaintext_bytes_padded = decrypter.decrypt(ciphertext_bytes) # 去掉Padding plaintext_bytes = unpad(plaintext_bytes_padded, AES.block_size, AESUtil.PAD_STYLE) # 将UTF-8格式编码的明文bytes,解码为Python中的字符串类型(即unicode字符串) plaintext = plaintext_bytes.decode(AESUtil.ENCODING) return plaintext class PrpCrypt(object): def __init__(self, key): self.key = key.encode('utf-8') self.mode = AES.MODE_CBC self.iv = Random.new().read(AES.block_size) # 加密函数,如果text不足16位就用空格补足为16位, # 如果大于16当时不是16的倍数,那就补足为16的倍数。 def encrypt(self, text): text = text.encode('utf-8') cryptor = AES.new(self.key, self.mode, self.iv) # 这里密钥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).encode('utf-8') elif count > length: add = (length - (count % length)) 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, self.iv) plain_text = cryptor.decrypt(a2b_hex(text)) return bytes.decode(plain_text).rstrip('\0') if __name__ == '__main__': aes_key = 'ew19jvgm5wangkbu' pc = PrpCrypt(aes_key) # 初始化密钥 data = "xxx123" print("原始data: ", data) print("--------------第1种方法符合服务端的AES对称加密算法: ") e1 = AESUtil.encrypt(data, aes_key) d1 = AESUtil.decrypt(e1, aes_key) print("加密:", e1) print("解密:", d1) print("--------------第2种方法不符合服务端的AES对称加密算法: ") e2 = pc.encrypt(data) # 加密 d2 = pc.decrypt(e2).encode() # 解密 print("加密:", e2) print("解密:", d2)
import json import urllib3 import requests from utils import block_crypt def block_users(block_url: str, aes_key: str, block_user_ids: list,request_encrypt=False): headers = { 'Content-Type': 'application/json' } # 请求体的参数是固定的 一些服务operator需要传 request_payload = json.dumps({ "operator": "gap1", "reason": "gap1", "ids": block_user_ids, "id_type": "uid", }) aes_text = block_crypt.AESUtil.encrypt(request_payload, aes_key) print("加密的aes_text: ", aes_text) # 发送封禁请求 需要判断一下是否发送加密请求 # 禁用warning urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) if request_encrypt: res = requests.post(block_url, data=aes_text, headers=headers, verify=False) else: res = requests.post(block_url, data=request_payload, headers=headers, verify=False) print("res: ", res, type(res), res.text) if request_encrypt: # 响应解密 res_dec = block_crypt.AESUtil.decrypt(res.text, aes_key) print("res_dec: ", res_dec) res_json = json.loads(res_dec) print("封禁接口返回结果res_json: ", res_json, type(res_json)) code = res_json.json().get("code") res_data = res_json.get("data") if res_data is None: print("返回的data是个None!!!!!") return if __name__ == '__main__': block_url = "https://xxx-xxxice.xx.com/a/b" aes_key = "xxxxxxxxxxxxxxxx" user_ids = ["xxx","xx222"] block_users(block_url, aes_key, user_ids)
~~~