decoded_data = bytes.fromhex(encrypted_data) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ValueError: non-hexadecimal number found in fromhex() arg at position 93 0439a729c835872596d6b9f35bda37ab3dc2a08029aeca3769165ed25f842f45bfc38ae5bd3ee1bae092f74c799af
时间: 2025-04-17 14:24:59 浏览: 58
<think>嗯,用户遇到了在Python中使用SM2加密时,从十六进制解码数据时出现ValueError错误,提示“non-hexadecimal number position 93”。我需要仔细分析这个问题可能的原因,并给出解决方案。
首先,用户的问题是在解码十六进制字符串时出错,位置在93。可能的情况有几个:
1. **字符串长度问题**:Hex字符串应该是偶数位,因为每个字节由两个十六进制字符表示。如果字符串长度是奇数,可能在解码时会报错。需要检查字符串的长度是否是偶数,特别是在截取或拼接过程中是否出错。
2. **非法字符存在**:Hex字符串只能包含0-9,a-f,A-F的字符。如果字符串中有其他字符,比如空格、特殊符号或非十六进制字符,就会导致解码错误。需要检查字符串中是否有非法字符,尤其是在位置93附近。
3. **密文结构拆分错误**:SM2加密后的密文通常由C1、C2、C3组成,不同的库可能使用不同的拼接顺序(如C1C2C3或C1C3C2)。如果拆分时位置计算错误,可能导致部分数据被错误分割,从而在解码时出现非十六进制字符。例如,假设C1是65字节,那么转换为Hex应该是130个字符(65*2)。如果拆分时位置错误,可能导致后面的部分包含不完整的字节,从而引发错误。
接下来,我需要参考用户提供的引用内容。引用[1]中的代码示例在处理公钥时分割了“04”前缀,可能涉及到公钥格式的处理。用户之前的回答中提到了重组C1C2C3格式时需要注意各部分的位置,如果库返回的是C1C3C2,需要重新拼接。可能用户在处理过程中拆分位置有误,导致Hex字符串被截断,从而在解码时出现问题。
引用[3]提到不同库可能生成不同格式的密钥,比如Hutool生成的私钥比公钥长,可能涉及编码格式的问题。用户可能在处理密钥或密文时,没有正确处理编码,导致生成的Hex字符串存在问题。
解决方案可能包括:
- 检查Hex字符串的长度是否为偶数,如果是奇数,可能需要补零或检查截取过程。
- 验证Hex字符串中是否包含非法字符,尤其是在报错的位置93附近,是否有非十六进制字符。
- 确保在拆分C1、C2、C3时,各部分的长度正确,特别是C1部分是否为65字节(130 Hex字符),C3是否为32字节(64 Hex字符),C2是否与明文等长。如果库返回的顺序不同,可能需要调整拆分的位置。
- 在处理Hex字符串时,使用binascii.unhexlify前先进行清洗,去除可能的空格或其他无效字符。
- 在解码前打印或检查Hex字符串,确认其正确性。
另外,用户可能在使用gmssl库时,加密返回的密文格式与预期不同,例如库可能返回的是C1C3C2,而用户需要的是C1C2C3,重组时如果拆分位置错误,会导致Hex字符串异常。例如,若密文总长度为65+32+明文长度,正确的拆分应该是前130字符(C1),接着是明文的Hex长度(C2),最后64字符(C3)。如果拆分位置错误,可能导致C2部分被截断,出现非Hex字符。
示例代码中,用户将密文拆分为c1 = ciphertext[:65],这里假设ciphertext是字节形式,65字节转换为Hex应该是130字符。如果密文Hex字符串在重组时长度不正确,可能导致后续解码错误。
可能需要建议用户打印加密后的Hex字符串长度,检查各部分拆分是否正确,并确保在解码前字符串是有效的Hex。</think>在Python中处理SM2加密数据时遇到`ValueError: non-hexadecimal number found`错误,通常与**十六进制字符串格式**或**密文结构拆分错误**相关。以下是具体分析与解决方案:
---
### 问题原因分析
1. **非法十六进制字符**
若加密后的密文字符串包含非`0-9a-fA-F`字符(如空格、特殊符号或截断错误),会导致`bytes.fromhex()`或`binascii.unhexlify()`解码失败。
2. **密文格式拆分错误**
SM2密文标准格式为`C1C2C3`或`C1C3C2`,若拆分时长度计算错误,可能导致部分数据段包含无效字符。
3. **字符串长度不匹配**
Hex字符串必须为**偶数长度**(每个字节对应2个十六进制字符),若长度异常会导致解码失败。
---
### 解决方案
#### 1. 清洗非法字符(通用方法)
在解码前过滤非十六进制字符:
```python
def clean_hex(hex_str):
return ''.join(c for c in hex_str if c in '0123456789abcdefABCDEF')
# 示例用法
encrypted_hex = "306f...0a3g" # 包含非法字符的密文
clean_hex_str = clean_hex(encrypted_hex)
encrypted_bytes = bytes.fromhex(clean_hex_str) # 或 binascii.unhexlify(clean_hex_str)
```
#### 2. 检查密文结构
根据SM2标准格式拆分密文(假设库返回`C1C3C2`,需重组为`C1C2C3`):
```python
# 示例:加密后的密文为hex字符串
encrypted_hex = "04..." # 完整密文
# 拆分各部分(假设C1=130字符,C3=64字符,C2=剩余部分)
c1_hex = encrypted_hex[:130] # 65字节公钥点(130 hex字符)
c3_hex = encrypted_hex[130:194] # 32字节哈希(64 hex字符)
c2_hex = encrypted_hex[194:] # 加密数据
# 重组为C1C2C3格式
correct_hex = c1_hex + c2_hex + c3_hex
encrypted_bytes = bytes.fromhex(correct_hex)
```
#### 3. 验证密钥和加密流程
若使用`gmssl`库,需确保密钥格式正确:
```python
from gmssl import sm2
# 正确格式的公钥(需包含0x04前缀)
public_key = "04" + "00" * 64 # 130字符十六进制
private_key = "00" * 32 # 64字符十六进制
sm2_crypt = sm2.CryptSM2(public_key=public_key, private_key=private_key)
```
---
### 错误排查示例
```python
# 打印加密后的hex长度和内容
encrypted_bytes = sm2_crypt.encrypt(b"ABC123")
encrypted_hex = encrypted_bytes.hex()
print(f"Hex长度: {len(encrypted_hex)}, 内容: {encrypted_hex[:100]}...")
# 检查是否为偶数长度
if len(encrypted_hex) % 2 != 0:
encrypted_hex = encrypted_hex[:-1] # 尝试移除末尾字符(需结合具体场景)
```
---
### 跨语言兼容性注意事项
- **字节顺序对齐**:与Java、Go等语言交互时,需统一使用`C1C2C3`或`C1C3C2`格式[^3]。
- **ASN.1编码处理**:某些库返回的密文可能包含ASN.1结构,需解析后再拆分[^1][^3]。
---
阅读全文
相关推荐












