AES加密接口开发

424 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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()函数进参数解密。