使用 python-cryptography 解密 pushbullet 通知时出现 InvalidTag 错误

InvalidTag error decrypting pushbullet notification with python-cryptography

我正在尝试为 python3 中的 pushbullet 临时消息实现端到端加密支持。

我正在使用 python-cryptography,但我在解密时遇到 InvalidTag-Exception。我已经仔细检查了密钥、iv 和标签,但我不知道哪里出了问题。

密钥是这样导出的:

    salt = user_ident.encode()
    pw = password.encode()

    kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(), 
            length=32,
            salt=salt,
            iterations=30000,
            backend=backend)

    dkey = kdf.derive(pw)

然后它作为 Base64 编码字符串存储在密钥环中,但我在加密时仔细检查了我是否得到了正确的字节字符串(也通过在 REPL 中手动执行)。

解密:

ciphertxt = a2b_base64(msg['ciphertext'])
version = ciphertxt[0:1]
tag = ciphertxt[1:17]
iv = ciphertxt[17:29]
enc_msg = ciphertxt[29:]

# Construct an AES-GCM Cipher object
decryptor = Cipher(
    algorithms.AES(self.dkey_),
    modes.GCM(iv, tag),
    backend=backend
).decryptor()

cleartxt = decryptor.update(enc_msg) + decryptor.finalize()

所有变量都是字节串,这里是python-密码学的relevant docs

澄清一下: 我尝试了自己的方法来加密并成功解密一些文本。但是当我在我的 phone 和我的客户端上激活 Pushbullet e2e 加密并且我收到通知时,我得到了上面的错误。

加密方法像这样组装加密消息:

b'1' + encryptor.tag + iv + ciphertxt

而且我可以破译它。不适用于收到的邮件中的标签。

有什么想法吗? :/

我最近在文档页面上添加了一些交互式 javascript 内容:https://docs.pushbullet.com/#example-encrypt-a-message

我发现调试此类问题的最佳方法是单独测试每个部分,并确保针对给定的输入获得正确的输出。

对于您的情况,我认为您应该创建一个不变的密钥、IV 和消息,并确保您的库生成与该示例中的 javascript 代码相同的 encrypted_message做。这可能是这样的:

// convert key from base64 to binary
var key = atob("1sW28zp7CWv5TtGjlQpDHHG4Cbr9v36fG5o4f74LsKg=");
var initialization_vector = atob("O2QAL8AYQB+qbre8"); // 96-bit
var message = "meow!";

var cipher = forge.cipher.createCipher('AES-GCM', key);
cipher.start({"iv": initialization_vector});
cipher.update(forge.util.createBuffer(forge.util.encodeUtf8(message)));
cipher.finish();

var tag = cipher.mode.tag.getBytes();
console.log("tag", btoa(tag));
var encrypted_message = cipher.output.getBytes();
console.log("encrypted_message", btoa(encrypted_message));

输出为:

tag OBA7UU/Rd9j0Zn+9korAyQ== 
encrypted_message 7YS1aTE= 

一旦您的 python 加密与此匹配,您应确保解密部分有效。

var key = atob("1sW28zp7CWv5TtGjlQpDHHG4Cbr9v36fG5o4f74LsKg=")
var tag = atob("OBA7UU/Rd9j0Zn+9korAyQ==")
var initialization_vector = atob("O2QAL8AYQB+qbre8"); // 96 bits
var encrypted_message = atob("7YS1aTE=");

var decipher = forge.cipher.createDecipher('AES-GCM', key);
decipher.start({
    'iv': initialization_vector,
    'tag': tag
});
decipher.update(forge.util.createBuffer(encrypted_message));
decipher.finish();

var message = decipher.output.toString('utf8');
console.log("message:", message);

应该打印:

message: meow! 

我对那个特定的 python 库没有任何经验,但如果您使用这种调试技术,您应该能够缩小问题所在的范围。