如何用AES(CBC)128算法加密可变长度数据?含4字节加密咨询
AES-CBC 128处理4字节短数据的解决方案
一、短数据的填充处理
AES-CBC属于分组密码,要求输入必须是块大小(128位=16字节)的整数倍,所以对4字节这种短数据必须做填充。行业通用的标准是PKCS#7填充:
- 填充字节的数值等于需要填充的字节数。比如4字节数据需要补12字节,每个填充字节的值都是
0x0C(十进制12)。 - 解密时,根据最后一个字节的数值,自动去掉对应数量的填充字节,就能还原原始4字节数据。
二、Python实现示例(基于PyCryptodome)
先安装依赖库:
pip install pycryptodome
以下是完整的加密/解密代码,包含PKCS#7填充、IV生成(CBC模式必须使用随机IV,且需随密文一起传输):
from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from Crypto.Random import get_random_bytes def aes_cbc_encrypt(plaintext: bytes, key: bytes) -> bytes: # 生成16字节随机初始化向量IV,CBC模式每次加密都要生成新IV iv = get_random_bytes(AES.block_size) cipher = AES.new(key, AES.MODE_CBC, iv) # 用PKCS#7填充到16字节块大小 padded_data = pad(plaintext, AES.block_size) ciphertext = cipher.encrypt(padded_data) # 返回IV+密文,IV必须和密文一起发送给接收方 return iv + ciphertext def aes_cbc_decrypt(ciphertext_with_iv: bytes, key: bytes) -> bytes: # 拆分出IV和密文(前16字节是IV) iv = ciphertext_with_iv[:AES.block_size] ciphertext = ciphertext_with_iv[AES.block_size:] cipher = AES.new(key, AES.MODE_CBC, iv) # 解密后去除PKCS#7填充 padded_plaintext = cipher.decrypt(ciphertext) plaintext = unpad(padded_plaintext, AES.block_size) return plaintext # 测试用例 if __name__ == "__main__": # 128位密钥(必须是16字节) secret_key = get_random_bytes(16) # 4字节原始数据 raw_data = b"abcd" print(f"原始数据: {raw_data}, 长度: {len(raw_data)}") # 加密 encrypted = aes_cbc_encrypt(raw_data, secret_key) print(f"加密后总数据(IV+密文)长度: {len(encrypted)}") print(f"加密后十六进制: {encrypted.hex()}") # 解密 decrypted = aes_cbc_decrypt(encrypted, secret_key) print(f"解密后数据: {decrypted}, 长度: {len(decrypted)}")
三、无线传输时保留真实数据长度的方法
填充会让数据从4字节变成16字节(加上IV的话是32字节),要保留真实长度有两种实用方案:
- 方案1:在数据包头部添加长度字段
传输时构造数据包为:[1字节长度字段] + [IV(16字节)] + [密文(16字节)]。比如原始数据是4字节,长度字段就填0x04。接收方先读取长度字段,解密后直接截取对应长度的字节即可(也可以和PKCS#7去填充的结果做校验,避免数据篡改)。 - 方案2:依赖PKCS#7填充自动还原
PKCS#7的填充规则本身已经包含了填充长度信息,解密后执行unpad操作会自动去掉填充字节,直接得到原始长度的数据,不需要额外传输长度字段。如果对数据完整性有更高要求,可以再加长度字段做双重校验。
内容的提问来源于stack exchange,提问作者Vikas Choudhary
相关产品推荐
相关产品推荐

