You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:25:57