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

使用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

疑问:

  1. 解密同事密文为空,忽略了什么?
  2. 同事的密文长度为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 09:32:09