我们有一个Python应用程序,它将字符串作为加密的二进制数据存储在MongoDB中,它使用
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
在NodeJS方面,我一直很难弄清楚如何解密数据,我有我们的salt,我们的密钥,但据我所知,没有IV,或者python模块可能只是隐藏了所有这些,因为python应用程序所要做的就是调用加密(值、盐)和解密(值、盐)
Python:
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 (它不起作用,但很接近):
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失败)
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();发布于 2021-05-22 14:39:05
在Python代码中所谓的salt实际上是当前(或IV),参见ChaCha20Poly1305的密码文档)。说明了现在和盐之间的区别,例如here。在下面的文章中,我使用了“现在”这个词。
在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代码中的以下漏洞:键和Note在实例化时传递给ChaChaEncryptedStringField类。这将导致对此实例执行的所有加密都使用相同的密钥/IV对,这是不安全的,请参见here。正确的方法是为每一次加密创建一个随机的“现在”。现在不是秘密,它与密文和标签一起传递,通常是串联的。
https://stackoverflow.com/questions/67628321
复制相似问题