使用Python解密AES-256-CBC加密字符串得到空结果的求助
AES-256-CBC解密同事密文为空及密文长度差异问题
问题背景
我需要访问受密码保护的资源,同事提供了存储加密密码的数据库表,这些密码是加密后的密文(长度44字符,始终以等号结尾,推测是Base64编码)。同事告知加密算法是AES-256-CBC,并提供了加密密钥。我实现了加密解密函数,自测试正常,但解密同事的密文时结果为空,同时疑惑同事的密文长度为何和我测试的不同。
我的实现代码
# Define the encryption function def encrypt_AES_CBC_256(key, message): key_bytes = key.encode('utf-8') message_bytes = message.encode('utf-8') iv = get_random_bytes(AES.block_size) cipher = AES.new(key_bytes, AES.MODE_CBC, iv) padded_message = pad(message_bytes, AES.block_size) ciphertext_bytes = cipher.encrypt(padded_message) ciphertext = b64encode(iv + ciphertext_bytes).decode('utf-8') return ciphertext # Define the decryption function def decrypt_AES_CBC_256(key, ciphertext): key_bytes = key.encode('utf-8') ciphertext_bytes = b64decode(ciphertext) iv = ciphertext_bytes[:AES.block_size] cipher = AES.new(key_bytes, AES.MODE_CBC, iv) ciphertext_bytes = ciphertext_bytes[AES.block_size:] decrypted_bytes = cipher.decrypt(ciphertext_bytes) plaintext_bytes = unpad(decrypted_bytes, AES.block_size) plaintext = plaintext_bytes.decode('utf-8') return plaintext
自测试情况
测试代码:
key = "XXXXXXXXXXXXXXXXXXXXXXXXXXX" # actual key is 32 characters long print('-----------') raw_input = "HERE IS MY TEST STRING" print(f"Entrée : {raw_input}") test4 = encrypt_AES_CBC_256(key, raw_input) print(f"Entrée chiffrée : {test4}") test5 = decrypt_AES_CBC_256(key, test4) print(f"Message déchiffré : {test5}")
测试输出:
----------- Entrée : HERE IS MY TEST STRING Entrée chiffrée : sZ1iZks9+qGVDHzt9WEO1hU3YrXKHvJj5sQzVd64HscPT8fiFBNbeihGFxpFyGC3 Message déchiffré : HERE IS MY TEST STRING
遇到的问题
解密同事提供的密文时结果为空:
测试代码:
print('-----------') raw = "e46mK0OmmYMBa2qkaALx5aUea4y/pT43OapQ6lmnDOA=" print(f"Mot de passe chiffré : {raw}") FINAL_TEST = decrypt_AES_CBC_256(key, raw) print(f"Mot de passe déchiffré : {FINAL_TEST}") print(f"Longueur du résultat : {len(FINAL_TEST)} caractères")
输出:
----------- Mot de passe chiffré : e46mK0OmmYMBa2qkaALx5aUea4y/pT43OapQ6lmnDOA= Mot de passe déchiffré : Longueur du résultat : 0 caractères
疑问:
- 解密同事密文为空,忽略了什么?
- 同事的密文长度为44而非我测试的64,原因是什么?
问题分析与解决
1. 解密为空的关键问题
你的代码是把IV和密文拼接后再做Base64编码,但同事的加密逻辑大概率没这么干:
- AES-CBC必须用IV,但不同实现的IV存储方式不一样:你是把IV加在密文前面一起编码,而同事可能用了固定IV(比如全0字节)、IV存在别的字段,甚至是用密钥派生了IV。
- 你现在的解密逻辑会从同事的密文前16字节(AES块大小)拆出一段错误的IV,解密后得到的是乱码。而你用的
unpad函数(PKCS#7填充)在处理乱码时,可能恰好把所有字节都判定为填充字节,直接去掉了,最后就得到空字符串。
可以这么验证:
- 试试用全0的IV直接解密同事的密文,跳过拆分IV的步骤:
def decrypt_with_fixed_iv(key, ciphertext): key_bytes = key.encode('utf-8') ciphertext_bytes = b64decode(ciphertext) iv = b'\x00' * AES.block_size # 尝试固定全0IV cipher = AES.new(key_bytes, AES.MODE_CBC, iv) decrypted_bytes = cipher.decrypt(ciphertext_bytes) # 若同事用的是Zero Padding,这里要替换成对应去填充逻辑 plaintext_bytes = unpad(decrypted_bytes, AES.block_size) return plaintext_bytes.decode('utf-8') - 如果还是不行,一定要问同事:IV是怎么生成、存储的?用的是哪种填充方式(你的代码用的是PKCS#7,若同事用Zero Padding,
unpad也会出错)。
2. 密文长度差异的原因
密文长度不同,本质是原始加密数据的字节数不一样:
- Base64编码的长度规则是:每3字节原始数据对应4个Base64字符,不足的补等号凑成4的倍数。
- 你的测试密文:16字节IV + 32字节加密明文(你的测试明文21字节,PKCS#7填充后凑成32字节),总字节数48 → 48÷3×4=64字符,和你测试的一致。
- 同事的密文:没有包含IV,只有32字节加密明文(原始明文填充后是32字节),32字节做Base64编码需要44字符(32÷3≈10.666,向上取整到11组,11×4=44,补等号凑整),所以是44字符。
内容的提问来源于stack exchange,提问作者R. Bourgeon
相关产品推荐
相关产品推荐

