AES-CBC加密Socket传输报错:IV长度需为16字节
解决AES CBC模式下IV长度错误的Socket加密传输问题
尝试通过Socket实现数据加密发送、接收解密功能时,触发以下错误:
ValueError: Incorrect IV length (it must be 16 bytes long)
原代码与报错信息
客户端代码
import socket from Crypto.Protocol.KDF import PBKDF2 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad def recv_decrypt(encrypted_code): encrypted_text, iv = encrypted_code.split(',')[0], encrypted_code.split(',')[1] iv = iv[2:] iv = iv.strip("'") encrypted_text = encrypted_text[2:] encrypted_text = encrypted_text.strip("'") encrypted_text = bytes(encrypted_text, 'ascii') iv = bytes(iv, 'ascii') my_key = b'D\xb7\x12t\x85.\xb7\xe7\xea\x08\xed\xd4\xf7\xa3\x9a\x80' password = "{hi&wJO@sVDVUq$" key = PBKDF2(password, my_key, dkLen=32) cipher = AES.new(key, AES.MODE_CBC, iv=iv) original = unpad(cipher.decrypt(encrypted_text), AES.block_size) print(original) client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('localhost', 43785)) while True: msg = client.recv(1024) recv_decrypt(encrypted_code=msg.decode())
服务端代码
import socket from Crypto.Protocol.KDF import PBKDF2 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad def send_encrypted(msg, client): try: my_key = b'D\xb7\x12t\x85.\xb7\xe7\xea\x08\xed\xd4\xf7\xa3\x9a\x80' password = "{hi&wJO@sVDVUq$" key = PBKDF2(password, my_key, dkLen=32) cipher = AES.new(key, AES.MODE_CBC) encrypted_data = cipher.encrypt(pad(bytes(msg), AES.block_size)) iv_data = cipher.iv send_data = f'{encrypted_data},{iv_data}' client.send(bytes(send_data.encode())) except Exception as e: print(f"something went wrong in the encrypt section error code: {e}") pass server_ip = "localhost" connection_port = 43785 Server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) Server.bind((server_ip, connection_port)) Server.listen() client, address = Server.accept() while True: msg = input("MSG: ") send_encrypted(msg=msg.encode('ascii'), client=client)
报错信息
Traceback (most recent call last): File "C:\Users\Desktop\GChat\cleen.py", line 30, in <module> recv_decrypt(encrypted_code=msg.decode()) File "C:\Users\Desktop\GChat\cleen.py", line 20, in recv_decrypt cipher = AES.new(key, AES.MODE_CBC, iv=iv) File "C:\Users\Desktop\GChat\venv\lib\site-packages\Crypto\Cipher\AES.py", line 228, in new return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) File "C:\Users\Desktop\GChat\venv\lib\site-packages\Crypto\Cipher\__init__.py", line 79, in _create_cipher return modes[mode](factory, **kwargs) File "C:\Users\Desktop\GChat\venv\lib\site-packages\Crypto\Cipher\_mode_cbc.py", line 287, in _create_cbc_cipher raise ValueError("Incorrect IV length (it must be %d bytes long)" % ValueError: Incorrect IV length (it must be 16 bytes long)
错误原因
服务端直接将二进制的加密数据和IV转成字符串拼接(比如b'xxx'格式),客户端解析时仅截取字符串部分再转bytes,会导致IV的实际字节长度偏离16字节——因为二进制数据转ASCII字符串会改变长度,解码后无法还原成原始的16字节IV。
正确的做法是用Base64编码二进制数据,将其转换为可安全传输的字符串格式,接收端再解码回二进制。
修改后的代码
服务端代码(添加Base64编码)
import socket import base64 from Crypto.Protocol.KDF import PBKDF2 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad def send_encrypted(msg, client): try: my_key = b'D\xb7\x12t\x85.\xb7\xe7\xea\x08\xed\xd4\xf7\xa3\x9a\x80' password = "{hi&wJO@sVDVUq$" key = PBKDF2(password, my_key, dkLen=32) cipher = AES.new(key, AES.MODE_CBC) encrypted_data = cipher.encrypt(pad(msg, AES.block_size)) # 用Base64编码二进制数据为字符串 encrypted_b64 = base64.b64encode(encrypted_data).decode('utf-8') iv_b64 = base64.b64encode(cipher.iv).decode('utf-8') send_data = f'{encrypted_b64},{iv_b64}' client.send(send_data.encode('utf-8')) except Exception as e: print(f"加密发送出错: {e}") server_ip = "localhost" connection_port = 43785 Server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) Server.bind((server_ip, connection_port)) Server.listen() client, address = Server.accept() while True: msg = input("MSG: ") send_encrypted(msg=msg.encode('ascii'), client=client)
客户端代码(添加Base64解码)
import socket import base64 from Crypto.Protocol.KDF import PBKDF2 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad def recv_decrypt(encrypted_code): encrypted_b64, iv_b64 = encrypted_code.split(',') # 解码Base64字符串回二进制 encrypted_text = base64.b64decode(encrypted_b64) iv = base64.b64decode(iv_b64) my_key = b'D\xb7\x12t\x85.\xb7\xe7\xea\x08\xed\xd4\xf7\xa3\x9a\x80' password = "{hi&wJO@sVDVUq$" key = PBKDF2(password, my_key, dkLen=32) cipher = AES.new(key, AES.MODE_CBC, iv=iv) original = unpad(cipher.decrypt(encrypted_text), AES.block_size) print(original.decode('utf-8')) client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('localhost', 43785)) while True: msg = client.recv(1024) recv_decrypt(encrypted_code=msg.decode('utf-8'))
额外说明
- Base64编码能确保二进制数据转成字符串后无乱码、无长度失真,是二进制数据传输的标准做法
- 服务端和客户端要统一编码格式(这里用utf-8),避免解码错误
- 原代码中服务端的
pad(bytes(msg), ...)可以简化为pad(msg, ...),因为msg已经是bytes类型
内容的提问来源于stack exchange,提问作者Clashers Lab
相关产品推荐
相关产品推荐

