持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
AES加密接口开发
按照管例,既然对加密算法有了初步的了解,接下来要让其应用到接口开发中。嗯,我们要开发一个用 AES加密算法的接口。
这一节的例子为颇为复杂,涉及到不少知识点。为了实现这一节的例子,我翻阅了不少资料,做好准备 和我一起实现它吧!
import requests
import unittest
import json
from Crypto.Cipher import AES
import base64
class AESTest(unittest.TestCase):
def setUp(self):
BS=16
self.pad=lambda s:+(BS-len(s) % BS) * chr(BS - len(s) % BS)
self.base_url="http://127.0.0.1:8000/sign/sec_get_guest_list/"
self.app_key = 'W7v4D60fds2Cmk2U'
def encryptBase64(self, src):
return base64.urlsafe_b64encode(src)
def encryptAES(self, src, key):
"""生成AES密文"""
iv = b"1172311105789011"
cryptor = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cryptor.encrypt(self.pad(src))
return self.encryptBase64(ciphertext)
def test_aes_interface(self):
"""test aes interface"""
payload = {'eid': '1', 'phone': '13800138000'}
#加密
encoded = self.encryptAES(json.dumps(payload), self.app_key).decode()
r = requests.post(self.base_url, data={"data": encoded})
result = r.json()
self.assertEqual(result['status'], 200)
self.assertEqual(result['message'], "success")
我们先来编写测试用例,因为加密的过程是在客户端进行的,也就是我们的测试用中。 self.app_key='W7v4D60fds2Cmk2U'
payload = {'eid': '1',138000} 首先,定义好app_key和接口参数,app_key是密钥,只有合法的客户端才知道,这个一定要保密噢!字 典来存放接口参数再合适不过了,所以,将参数定义为字典。
encoded = self.entAES(json.dumps(payload), self.app_key).decode()
首先将payload参数转化为json格式,然后将参数和app_key传参给 encryptAESO方法用于生成加密串
。 def encryptAES(self,src,key):
iv = b"1172311105789011"
cryptor = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cryptor.encrypt(self.pad(src))
return self.encryptBase64(ciphertext)
v 同样是保密的,并且我们前面知道它必须是16位字节。然后通过 encryp
方法对src 接口参数生成加 密串,但是这里会有问题。encryptO要加密的字符串有严格的长度要求,长度必须是16的倍数。如果直接生 成可能会提示:
ValueError: Input strings must be a multiple of 16 in length
但是,要加密串的长度是不可控。接口参数的个数和参数的长度会随意的影响着长度。所以,为了解决 这个问题,还对参数串时行处理,使其长度固定。
self.pad = lambda s: s + (BS - len(s) % BS)* chr(BS - len(s)
BS - len(s) % BS)
这是函数式编程的一种用法,通过lambda定义匿名函数来对字符串进行补足,实其长度为16的倍数。 再接下来生成的字符串是这样的:
b>_\x80\xlfi\x97\x8fx94~\x
4~\xeaE\xectBm\x9d\xa9\xc5\x85<+e\xa5lW\xel\x84}\xfa\x8b\xb9\xde\xla\x10J\xcd\ xc5\xa1A4Z\xffx05x\
但这样的字符串太长,并不太适合传输。 def encryptBase64(self,src):
return base64.urlsafe_b64encode(src)
通过 base64模块的urlsafe_b64encode()方法对AES加密串进行二次加密。然后得到的字符串是这样的: b'gouBbuKWEeY5wWjMx-nNAYDTion0ADOysaLwluzzGOpvTTASpQGJu5p0WuDhZMiM。到此,加密过程结 束。
r=requests.post(self.base_url,data=
ta={"data": en
ata": encoded})
接下来将加密后的字符串作为接口的data参数发送给接口。
当服务器接收到字符串之后,如何对加密串进行解密处理呢?下接来开发服务器端的处理。
"""AES 加密算法 BS"""
import json
BS=16
unpad = lambda s : s[0: - ord(s[-1])]
def decryptBase64(src):
return base64.urlsafe_b64decode(src)
def decryptAES(src, key):
"""解析AES 密文"""
src = decryptBase64(src)
iv = b"1172311105789011"
cryptor - AES.new(key, AES.MODE_CBC, iv)
text = cryptor.decrypt(src).decode()
return unpad(text)
def aes_encryption(request):
app_key = 'W7v4D60fds2Cmk2U'
if request.method == "Post":
data = request.PosT.get("data", "")
# 解密
decode = decryptAES(data, app_key)
dict_data = json.load(decode)
return dict_data
app_key = 'W7v4D60fds2Cmk2
服务器端与合法客户端约定的密钥app_key。
if request.method=='POST':
data = request.POST.get("data", "")
判断客户端请求是否为POST,通过POST.get()方法接收 data 参数。
decode=decryptAES(data,app_key)
调用解密函数decryptAES(),传参加密串和app_key。
def decryptAES(src, key):
"""解析AES 密文"""
src = decryptBase64(src)
iv = b"1172311105789011"
cryptor - AES.new(key, AES.MODE_CBC, iv)
text = cryptor.decrypt(src).decode()
return unpad(text)
首先,调用decryptBase64()方法,将加密串解密为AES加密串。
def decryptBase64(src):
return base64.urlsafe_b64decode(src)
然后,通过decrypt()对AES加密串进行解密
BS=16
unpad = lambda s : s[0: - ord(s[-1])]
最后,通过upad匿名函数对字符串的长度还原。到此,解密过程结束。
dict_data = json.load(decode)
return dict_data
解密后字符串通过json.loads()方法转化成字典,并将该字典做为aes_encryption()函数的返回值。
接下来利用 查询接口调用aes_encryption()函数进参数解密。