首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从字符串中解密NodeJS中在python应用程序中加密的ChaCha20-Poly1305二进制数据

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

Stack Overflow用户
提问于 2021-05-20 21:44:56
回答 1查看 753关注 0票数 1

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

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

在NodeJS方面,我一直很难弄清楚如何解密数据,我有我们的salt,我们的密钥,但据我所知,没有IV,或者python模块可能只是隐藏了所有这些,因为python应用程序所要做的就是调用加密(值、盐)和解密(值、盐)

Python:

代码语言:javascript
复制
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, key, 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, value, None)

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

Javascript (它不起作用,但很接近):

代码语言: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 (salt从秘密中提取,使用提取的IV失败)

代码语言:javascript
复制
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, authTagLocation);
const encrypted = data.buffer.slice(0, ivLocation);

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

return dec.toString();
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-22 14:39:05

在Python代码中所谓的salt实际上是当前(或IV),参见ChaCha20Poly1305的密码文档)。说明了现在和盐之间的区别,例如here。在下面的文章中,我使用了“现在”这个词。

在NodeJS代码中,密文和标记的分离是以一种过于复杂的方式执行的,但(巧合的是)结果是正确的。IV在分离中没有发挥作用。标记是最后的16个字节,实际的密文是标记之前的剩余数据。

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

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

代码语言:javascript
复制
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代码中的以下漏洞:键和Note在实例化时传递给ChaChaEncryptedStringField类。这将导致对此实例执行的所有加密都使用相同的密钥/IV对,这是不安全的,请参见here。正确的方法是为每一次加密创建一个随机的“现在”。现在不是秘密,它与密文和标签一起传递,通常是串联的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67628321

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档