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

使用PyCryptodome的OCB模式通过Socket传输JSON时MAC校验失败

AES-OCB 加密Socket传输后MAC校验失败的排查方案

核心问题定位方向

你遇到的问题大概率是密钥不一致或加密模式不匹配导致的,以下是具体排查步骤和修复建议:

1. 核对加密和解密的密钥

加密函数中使用的是局部变量key,但解密函数用的是glob.aes_key,这两个必须是完全相同的字节串:

  • 加密前打印key.hex(),解密前打印glob.aes_key.hex(),逐字符对比是否一致
  • 建议统一密钥来源,比如加密时也使用glob.aes_key,避免局部变量和全局变量的差异

2. 确认加密模式一致

加密函数中用的是Amode,解密用的是AES.MODE_OCB,必须确保Amode就是AES.MODE_OCB:

  • 可以直接替换成AES.MODE_OCB,避免自定义变量被误赋值

3. 校验传输前后的字节完整性

即使JSON内容看起来一致,也要确认Base64解码后的字节和加密时完全相同:

  • 加密端打印各字段的十六进制值:cipher.nonce.hex()、ciphertext.hex()、tag.hex()
  • 解密端解码后打印对应字段的十六进制值:jv['nonce'].hex()、jv['ciphertext'].hex()、jv['tag'].hex()
  • 逐字节对比,确保没有差异(PyCryptodome的b64encode是标准Base64,编码解码逻辑本身无问题)

4. 检查Socket接收逻辑

如果Socket传输时数据被分段接收,可能导致实际接收的字节不完整(即使JSON看起来完整):

  • 确保接收端用循环接收所有数据,比如先接收数据长度,再根据长度接收对应字节数的内容

修复后的示例代码

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import base64 as b64
import json
import pickle
import glob

def enc_pic(data):
    # 统一使用全局密钥,避免不一致
    cipher = AES.new(glob.aes_key, AES.MODE_OCB, nonce=get_random_bytes(8))
    data = pickle.dumps(data)
    ciphertext, tag = cipher.encrypt_and_digest(data)
    
    # 打印加密端字段的十六进制,方便对比
    print(f"加密nonce: {cipher.nonce.hex()}")
    print(f"加密密文: {ciphertext.hex()}")
    print(f"加密tag: {tag.hex()}")
    
    json_k = ['nonce', 'ciphertext', 'tag']
    json_v = [b64.b64encode(x).decode('utf-8') for x in (cipher.nonce, ciphertext, tag)]
    return json.dumps(dict(zip(json_k, json_v))).encode("UTF-8")

def decr_pic(data):
    try:
        b64_data = json.loads(data.decode("UTF-8"))
        json_k = ['nonce', 'ciphertext', 'tag']
        jv = {k: b64.b64decode(b64_data[k]) for k in json_k}
        
        # 打印解密端字段的十六进制,和加密端对比
        print(f"解密nonce: {jv['nonce'].hex()}")
        print(f"解密密文: {jv['ciphertext'].hex()}")
        print(f"解密tag: {jv['tag'].hex()}")
        
        cipher = AES.new(glob.aes_key, AES.MODE_OCB, nonce=jv['nonce'])
        plaintext = cipher.decrypt_and_verify(jv['ciphertext'], jv['tag'])
        res = pickle.loads(plaintext)
    except (ValueError, KeyError) as e:
        res = "解密失败"
        print(f"错误信息: {e}")
    return res

内容的提问来源于stack exchange,提问作者Сapy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:35:32