AES-CTR解密函数异常:无法获取目标明文,返回字节数据求助
AES-CTR解密失败无法得到预期明文问题排查
问题描述
编写AES-CTR加解密函数后,调用解密时得到字节数据,解码UTF-8时报错:'utf-8' codec can't decode byte 0xf6 in position 0: invalid start byte,无法得到预期明文SandI2021。
输入信息
- 密钥:
maru000000000000 - IV:
b'\x19\x89j=-\xed)\xe3\xca\x1b\xde?\x15\x1d$!' - 密文:
b'\xc6Q\xff\x94\x82\xf8\xd4\xfd\x17' - 当前解密结果:
b'\xf6\x18n:\x8a\xb6\x8e\xb1\xb1'
现有代码
解密函数
def decrypt(key, iv, ciphertext): assert len(key) == key_bytes # Initialize counter for decryption. iv should be the same as the output of # encrypt(). iv_int = int(binascii.hexlify(iv), 16) ctr = Counter.new(AES.block_size * 8, initial_value=iv_int) # Create AES-CTR cipher. aes = AES.new(key.encode('utf8'), AES.MODE_CTR, counter=ctr) # Decrypt and return the plaintext. plaintext = aes.decrypt(ciphertext) return plaintext
加密函数
def encrypt(key, pt): plaintext = read_file(pt) if isinstance(plaintext, str): pt= plaintext.encode("utf-8") if len(key) <= key_bytes: for x in range(len(key),key_bytes): key = key + "0" assert len(key) == key_bytes # Choose a random, 16-byte IV. iv = Random.new().read(AES.block_size) # Convert the IV to a Python integer. iv_int = int(binascii.hexlify(iv), 16) # Create a new Counter object with IV = iv_int. ctr = Counter.new(AES.block_size * 8, initial_value=iv_int) # Create AES-CTR cipher. aes = AES.new(key.encode('utf8'), AES.MODE_CTR, counter=ctr) # Encrypt and return IV and ciphertext. ciphertext = aes.encrypt(pt) return (iv, ciphertext)
问题排查与修复
1. 加密函数read_file逻辑错误
加密函数第一行plaintext = read_file(pt)默认将输入的pt当作文件路径读取,若调用时传入的是明文字符串(如SandI2021),实际加密的是文件内容(文件不存在则为错误数据),而非预期明文,导致解密结果不符。
修复方案:修改加密函数,支持直接传入明文或文件路径:
def encrypt(key, pt): # 尝试读取文件,失败则将pt视为明文 try: with open(pt, 'r', encoding='utf-8') as f: plaintext = f.read() except (FileNotFoundError, IsADirectoryError): plaintext = pt if isinstance(plaintext, str): pt = plaintext.encode("utf-8") # 用ljust简化密钥补0逻辑,替代循环 key_bytes = 16 # 需与AES密钥长度匹配:16(AES-128)/24(AES-192)/32(AES-256) key = key.ljust(key_bytes, '0') assert len(key) == key_bytes iv = Random.new().read(AES.block_size) iv_int = int(binascii.hexlify(iv), 16) ctr = Counter.new(AES.block_size * 8, initial_value=iv_int) aes = AES.new(key.encode('utf8'), AES.MODE_CTR, counter=ctr) ciphertext = aes.encrypt(pt) return (iv, ciphertext)
2. 解密函数缺失密钥补全逻辑
加密函数会对长度不足的密钥补0,但解密函数直接断言密钥长度等于key_bytes,若解密时传入原始短密钥会触发错误,且无法与加密流程匹配。
修复方案:让解密函数与加密函数保持一致的密钥补全逻辑:
def decrypt(key, iv, ciphertext): key_bytes = 16 # 与加密函数的key_bytes值一致 key = key.ljust(key_bytes, '0') assert len(key) == key_bytes iv_int = int(binascii.hexlify(iv), 16) ctr = Counter.new(AES.block_size * 8, initial_value=iv_int) aes = AES.new(key.encode('utf8'), AES.MODE_CTR, counter=ctr) plaintext = aes.decrypt(ciphertext) return plaintext
3. 验证输入一致性
确保解密使用的密钥、IV、密文完全匹配加密输出:
- 手动输入的IV/密文可能存在字节转义错误,建议通过加密函数生成对应值后再测试;
- 运行以下测试代码验证流程:
# 依赖导入需确保齐全 from Crypto.Cipher import AES from Crypto.Util import Counter from Crypto.Random import Random import binascii # 测试加解密流程 key = "maru000000000000" expected_plaintext = "SandI2021" # 加密生成IV和密文 iv, ciphertext = encrypt(key, expected_plaintext) # 解密验证 decrypted_data = decrypt(key, iv, ciphertext) print(f"解密结果: {decrypted_data.decode('utf-8')}") # 应输出SandI2021
内容的提问来源于stack exchange,提问作者PyhonLovers
相关产品推荐
相关产品推荐

