如何避免Python加密函数参数传递顺序混淆?
避免AES加密函数参数顺序颠倒的解决方案
我正在开发一套包含KDF(密钥派生函数keygen)和AES加密函数stringE(data, key)的Python加密逻辑。当前遇到的问题是:调用stringE函数时,若误将待加密数据data与加密密钥key的传递顺序颠倒,会导致加密失效,后续解密无法获取正确数据或触发错误。目前我仅能想到通过函数内部的条件检查来避免该问题,希望了解其他更优的解决方案,确保参数按正确顺序传递。
相关代码
import os import json import base64 as b64 from argon2 import hash_password_raw, Type from alive_progress import alive_bar from Crypto.Cipher import AES # 清屏函数 def clear(): os.system("clear||cls") # 密钥派生函数(生成AES密钥) def keygen(master): if len(master) < 100: clear() input('使用的密码/字符长度必须大于等于100位!\n\n按回车键继续...') clear() return None else: salt = os.urandom(16) print("生成密钥中...") with alive_bar(0) as bar: key = hash_password_raw( time_cost=16, memory_cost=2**20, parallelism=4, hash_len=32, password=master, salt=salt, type=Type.ID ) bar() clear() return key # 返回字节类型,如需可自行base64编码 # AES加密函数 def stringE(data, key): # 补充定义原代码缺失的header变量 header = b"encryption-header" cipher = AES.new(key, AES.MODE_GCM) cipher.update(header) ciphertext, tag = cipher.encrypt_and_digest(data) json_k = [ 'nonce', 'header', 'ciphertext', 'tag' ] json_v = [ b64.b64encode(x).decode('utf-8') for x in [cipher.nonce, header, ciphertext, tag ]] result = json.dumps(dict(zip(json_k, json_v))) result_bytes = bytes(result, 'utf-8') b64_result = b64.b64encode(result_bytes) return b64_result.decode() # 加密示例 if __name__ == "__main__": data = b'Hello World <3' key_data = b'abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde' eKey = keygen(key_data) # 若输入长度不足100位返回None save_me = b64.b64encode(eKey) # 保存密钥用于后续解密 input(f'请保存此密钥以便后续解密:{save_me}\n\n按回车键继续...') clear() data_enc = stringE(data, eKey) # 必须确保先传数据,再传密钥 clear() print(data_enc)
可行解决方案
1. 强制关键字传参
修改stringE函数定义,使用*强制调用时必须通过关键字传递参数,彻底从语法层面避免顺序错误:
def stringE(*, data: bytes, key: bytes) -> str: header = b"encryption-header" # 原有加密逻辑...
调用时必须写成stringE(data=data, key=eKey),少写关键字或顺序错误都会直接触发语法错误。
2. 类型标注+静态检查
给参数添加明确的类型提示,配合mypy、PyCharm等静态检查工具,在编码阶段就识别参数类型不匹配的问题:
def stringE(data: bytes, key: bytes) -> str: header = b"encryption-header" # 原有加密逻辑...
因为keygen生成的是固定32字节的密钥,而待加密数据长度通常不会刚好是32字节,静态检查工具能在传参顺序颠倒时立刻给出警告。
3. 封装为加密类
把密钥和加密逻辑封装成类,初始化时传入密钥,后续加密仅需传递数据,从调用逻辑上消除参数顺序问题:
class AESEncryptor: def __init__(self, key: bytes): if len(key) != 32: raise ValueError("密钥必须是32字节的AES-256密钥") self.key = key self.header = b"encryption-header" def encrypt(self, data: bytes) -> str: cipher = AES.new(self.key, AES.MODE_GCM) cipher.update(self.header) ciphertext, tag = cipher.encrypt_and_digest(data) json_k = [ 'nonce', 'header', 'ciphertext', 'tag' ] json_v = [ b64.b64encode(x).decode('utf-8') for x in [cipher.nonce, self.header, ciphertext, tag ]] result = json.dumps(dict(zip(json_k, json_v))) return b64.b64encode(bytes(result, 'utf-8')).decode() # 使用方式 encryptor = AESEncryptor(eKey) data_enc = encryptor.encrypt(data)
4. 参数格式校验
利用keygen生成固定32字节密钥的特性,在stringE中添加密钥长度校验,传参顺序颠倒时会直接抛出明确错误:
def stringE(data: bytes, key: bytes) -> str: if len(key) != 32: raise ValueError("无效密钥:必须是32字节的AES-256密钥") if not data: raise ValueError("待加密数据不能为空") header = b"encryption-header" # 原有加密逻辑...
即使传反参数,待加密数据几乎不可能刚好是32字节,会立刻报错而非默默失败。
内容的提问来源于stack exchange,提问作者Ori
相关产品推荐
相关产品推荐

