微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从字符串解密在python应用程序中加密的NodeJS中的ChaCha20-Poly1305二进制数据

如何解决从字符串解密在python应用程序中加密的NodeJS中的ChaCha20-Poly1305二进制数据

我们有一个 Python 应用程序,它将字符串作为加密的二进制数据存储在 MongoDB 中,它使用

from cryptography.hazmat.primitives.ciphers.aead import ChaCha20poly1305

在 NodeJS 方面,我一直无法弄清楚如何解密数据,我有我们的盐,我们的密钥,但据我所知没有 IV,或者 python 模块可能只是隐藏了所有所有python应用程序必须做的就是调用encrypt(value,salt)和decrypt(value,salt)

蟒蛇:

class ChaChaEncryptedStringField(EncryptedStringField):
"""
A field which,given an encryption key and salt,will automatically encrypt/decrypt
sensitive data to avoid needing to do this before passing in. This encryption
method reliably produces a searchable string.
"""

def __init__(self,key,salt,*args,**kwargs):
    """Initialize the ChaChaEncryptedStringField.
    Args:
        key (str) -
        salt (str) -
    """
    class Hook:
        def __init__(self,salt):
            self.salt = salt
            self.chacha = ChaCha20poly1305(key)

        def encrypt(self,value):
            return self.chacha.encrypt(self.salt,value,None)

        def decrypt(self,value):
            return self.chacha.decrypt(self.salt,None)

    self.encryption_hook = Hook(b64decode(key),b64decode(salt))
    super(EncryptedStringField,self).__init__(*args,**kwargs)

Javascript(不起作用但已关闭):

const authTagLocation = data.buffer.length - 16;
const ivLocation = data.buffer.length - 28;
const authTag = data.buffer.slice(authTagLocation);
const iv = data.buffer.slice(ivLocation,authTagLocation);
const encrypted = data.buffer.slice(0,ivLocation);
const decipher = crypto.createDecipheriv('chacha20-poly1305',keyBuffer,iv,{ authTagLength: 16 } );
let dec = decipher.update(
  data.buffer,'utf-8','utf-8'
);
dec += decipher.final('utf-8');

return dec.toString();

通过一些研究和反复试验,我克服了它,抱怨 IV 不正确,并且密钥长度正确,但仍然返回乱码

所以我实际上让以下代码工作,但我不会声称完全理解正在发生的事情:

正在运行的 Javascript(从秘密中提取盐,使用提取的 IV 失败)

const authTagLength = 16
const authTagLocation = data.buffer.length - authTagLength;
const ivLocation = data.buffer.length - 16;
const authTag = data.buffer.slice(authTagLocation);
const iv = data.buffer.slice(ivLocation,ivLocation);

const decipher = crypto.createDecipheriv('chacha20-poly1305',saltBuffer,{ authTagLength: authTagLength } );
let dec = decipher.update(
  encrypted,'utf-8'
);
dec += decipher.final('utf-8');

return dec.toString();

解决方法

Python 代码中所谓的 salt 实际上是 nonce(或 IV),请参阅 Cryptography 文档以了解 {{3} })。解释了 nonce 和 salt 之间的区别,例如ChaCha20Poly1305。在下文中,我使用术语 nonce。

在 NodeJS 代码中,密文和标签的分离以一种过于复杂的方式进行,但(巧合)得到了正确的结果。 IV 在分离中不起作用。标签为最后16个字节,实际密文为标签前的剩余数据。

此外,目前没有进行身份验证,这是不安全的。要启用身份验证,必须在 setAuthTag() 调用之前使用 final() 设置标记。如果认证失败,则抛出异常。

以下示例显示了用于解密的可能的 NodeJS 实现。密文是用发布的 Python 代码生成的:

const crypto = require('crypto');

const keyBuffer = Buffer.from('MDEyMzQ1Njc4OTAxMjM0NTAxMjM0NTY3ODkwMTIzNDU=','base64');
const nonceBuffer = Buffer.from('MDEyMzQ1Njc4OTAx','base64')
const dataBuffer = Buffer.from('4bAaXOlQGhLI3tAsJju0e8Z737eF683Izik+6Uz4axPKj6NbmGLXcCgxukIyo8whOsu2lEgg3llInLA=','base64')

const authTagLength = 16
const encrypted = dataBuffer.slice(0,-authTagLength)
const tag = dataBuffer.slice(-authTagLength);

const decipher = crypto.createDecipheriv('chacha20-poly1305',keyBuffer,nonceBuffer,{authTagLength: authTagLength});
decipher.setAuthTag(tag)

let decrypted;
try {
    decrypted = decipher.update(encrypted,'','utf-8');
    decrypted += decipher.final('utf-8');
    console.log(decrypted);
} catch(e) {
    console.log("Decryption failed!");
}

注意 Python 代码中的以下漏洞:Key 和 nonce 在实例化时传递给 ChaChaEncryptedStringField 类。这会导致对该实例执行的所有加密使用相同的密钥/IV 对,这是不安全的,请参阅 here。正确的方法是为每个加密创建一个随机数。 nonce 不是秘密的,它与密文和标签一起传递,通常是连接在一起的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。