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

如何用Python解密经R语言sodium包加密的密钥?

问题:用Python复刻R语言sodium包的decrypt_access_key函数

我有一套用R语言sodium包实现的、通过密码加解密访问密钥的函数:

encrypt_access_key <- function(access_key, password) {
  key <- sha256(charToRaw(password))
  nonce <- random(24)  # 生成随机nonce
  encrypted <- data_encrypt(charToRaw(access_key), key, nonce)
  list(
    encrypted_access_key = base64encode(encrypted),
    nonce = base64encode(nonce)
  )
}

decrypt_access_key <- function(encrypted_access_key, nonce, password) {
  key <- sha256(charToRaw(password))
  encrypted_raw <- base64decode(encrypted_access_key)
  nonce_raw <- base64decode(nonce)
  rawToChar(data_decrypt(encrypted_raw, key, nonce_raw))
} 

我需要编写一个Python函数复刻上述decrypt_access_key的功能,但尝试均未成功。以下是可直接复现的解密示例:

decrypt_access_key(encrypted_access_key = "QG42J4fSVcY9luHaXiEhQcR85isjgUlmFc97pMHIIwuxQyZzDNpz2w==", nonce = "LpO7fBaCs1iobxDxVmOPFycTe/BCifqh", password = "Example123")

我尝试的失败Python代码

import base64
from Crypto.Cipher import ChaCha20_Poly1305
from Crypto.Protocol.KDF import PBKDF2
import hashlib

def decrypt_access_key(encrypted_access_key, nonce, password):
    # 解码base64编码的内容
    encrypted_access_key_bytes = base64.b64decode(encrypted_access_key)
    nonce_bytes = base64.b64decode(nonce)
    
    # 使用PBKDF2推导密钥
    key = hashlib.pbkdf2_hmac('sha256', password.encode(), b'', 100000)
    
    # 用ChaCha20-Poly1305解密
    cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce_bytes)
    decrypted = cipher.decrypt(encrypted_access_key_bytes)
    
    return decrypted.decode('utf-8')

# 示例调用
encrypted_access_key = 'QG42J4fSVcY9luHaXiEhQcR85isjgUlmFc97pMHIIwuxQyZzDNpz2w=='
nonce = 'LpO7fBaCs1iobxDxVmOPFycTe/BCifqh'
password = 'Example123'

decrypted_access_key = decrypt_access_key(encrypted_access_key, nonce, password)
print(decrypted_access_key)

正确的Python实现

失败原因主要有三点:

  • 密钥推导错误:R中是直接对密码的原始字节做SHA256哈希,而非PBKDF2
  • 加密算法混淆:R的data_encrypt默认使用XChaCha20-Poly1305(对应24字节nonce),不是普通的ChaCha20-Poly1305
  • 密文结构处理错误:data_encrypt返回的是「密文 + 16字节Poly1305校验标签」,解密时需要拆分这两部分

以下是修正后的代码:

import base64
import hashlib
from Crypto.Cipher import ChaCha20_Poly1305

def decrypt_access_key(encrypted_access_key, nonce, password):
    # 解码base64内容
    encrypted_data = base64.b64decode(encrypted_access_key)
    nonce_bytes = base64.b64decode(nonce)
    
    # 按R的逻辑推导密钥:密码转UTF-8字节后做SHA256哈希
    key = hashlib.sha256(password.encode('utf-8')).digest()
    
    # 拆分密文和Poly1305标签(最后16字节是标签)
    ciphertext = encrypted_data[:-16]
    tag = encrypted_data[-16:]
    
    # 使用XChaCha20-Poly1305解密(24字节nonce对应XChaCha20)
    cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce_bytes)
    decrypted = cipher.decrypt_and_verify(ciphertext, tag)
    
    return decrypted.decode('utf-8')

# 测试示例
encrypted_access_key = 'QG42J4fSVcY9luHaXiEhQcR85isjgUlmFc97pMHIIwuxQyZzDNpz2w=='
nonce = 'LpO7fBaCs1iobxDxVmOPFycTe/BCifqh'
password = 'Example123'

print(decrypt_access_key(encrypted_access_key, nonce, password))
# 输出:This is a hidden message

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:50:22