c++ - crypto_box_easy 和 crypto_box_open_easy 的奇怪行为。不用私钥解密?

标签 c++ cryptography public-key-encryption libsodium

我已经通过 libsodium 测试了公钥加密并遇到了一个奇怪的行为。加密的消息在没有私钥的情况下被解密。

官网示例libsodium

#include "sodium.h"

#define MESSAGE         "test"
#define MESSAGE_LEN     4
#define CIPHERTEXT_LEN (crypto_box_MACBYTES + MESSAGE_LEN)

static bool TestSodium()
{
    unsigned char alice_publickey[crypto_box_PUBLICKEYBYTES];
    unsigned char alice_secretkey[crypto_box_SECRETKEYBYTES];
    crypto_box_keypair(alice_publickey, alice_secretkey);

    unsigned char bob_publickey[crypto_box_PUBLICKEYBYTES];
    unsigned char bob_secretkey[crypto_box_SECRETKEYBYTES];
    crypto_box_keypair(bob_publickey, bob_secretkey);

    unsigned char nonce[crypto_box_NONCEBYTES];
    unsigned char ciphertext[CIPHERTEXT_LEN];
    randombytes_buf(nonce, sizeof nonce);

    // message alice -> bob
    if (crypto_box_easy(ciphertext, (const unsigned char*)MESSAGE, MESSAGE_LEN, nonce, bob_publickey, alice_secretkey) != 0)
    {
        return false;
    }

    unsigned char decrypted[MESSAGE_LEN + 1];
    decrypted[MESSAGE_LEN] = 0;

    // Original!
    //if (crypto_box_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce, alice_publickey, bob_secretkey) != 0)

    // Whis works without Bobs secret key!
    if (crypto_box_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce, bob_publickey, alice_secretkey) != 0)
    {
        return false;
    }

    if(strcmp((const char*)decrypted, MESSAGE) != 0) return false;

    return true;
}

Using public-key authenticated encryption, Alice can encrypt a confidential message specifically for Bob, using Bob's public key.

Using Alice's public key, Bob can verify that the encrypted message was actually created by Alice and was not tampered with, before eventually decrypting it.

Bob only needs Alice's public key, the nonce and the ciphertext.

And in order to send messages to Bob, Alice only needs Bobs's public key.

在原始示例中,Bob 使用自己的 key 解密来自 Alice 的消息,并使用 Alice 的公钥对其进行验证。 我在代码中犯了一个错误,并且在没有 Bob 的私钥的情况下正确解密了消息!

这怎么可能?我的错误在哪里?谢谢

最佳答案

是的,这是可能的

在 libsodium 中,公钥认证加密是在三个独立的阶段完成的,顺序是:

  1. key 交换 — 使用 elliptic-curve Diffie-Hellman算法 (X25519) 从我的私钥和你的公钥生成共享 key

  2. 加密 — 使用在步骤 1 中生成的共享 key 对明文消息应用对称 key 加密 (XSalsa20)。

  3. Authentication — 生成 MAC (Poly1305),同样依赖于上述步骤中生成的 key 。

在步骤 2-3 中使用对称加密意味着 相同 key 必须可由 Alice 和 Bob 计算,即

shared_key_computed_by_alice = crypto_box_beforenm(bob_pk, slice_sk)
shared_key_computed_by_bob = crypto_box_beforenm(alice_pk, bob_sk) 
assert(shared_key_computed_by_alice == shared_key_computed_by_bob)

由于我们要求两个 key 对生成相同的共享 key ,因此不难看出这两个 key 对也可以解密相同的消息。

这很好

请注意,在您实现“错误”解密时,您不仅使用了 Bob 的公钥,还使用了 Alice 的私钥(只有 Alice 知道)。

因为是 Alice 想将加密消息发送给 Bob,这意味着 Alice 应该首先知道明文消息。所以她可以使用自己的私钥解密该消息,这不是安全问题。

如果您将 Bob 的公钥与另一个人 (Eve) 的私钥一起使用,解密程序将真的失败。

如果您认为 Alice 能够解密她自己的消息是一个问题,您可以强制 Alice 在对话后销毁她的私钥😛,所以现在只有 Bob 可以解密它(并且不能从 Alice 发送更多消息) .

事实上 libsodium 提供了 sealed box API它执行此操作(生成一个临时 key 对并在加密后立即将其销毁)。

关于c++ - crypto_box_easy 和 crypto_box_open_easy 的奇怪行为。不用私钥解密?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39797321/

相关文章:

c++ - 在C++中将Char数组添加到Char *变量

c++ - 如何在新的 JetBrains Fleet for C++ 中创建和配置 run.json?

javascript - 浏览器中javascript中的openssl解密

c++ - 为什么C++内联函数有调用指令?

c++ - is_trivially_destructible : invalid use of incomplete type ‘class Bar2’

security - 此 SSO 实现安全吗?

java - 从密码重新生成私钥

c# - 无法解密使用 AesManaged 加密的文件

c++ - DSA 公钥大于私钥

Java 强加密 - 独立库 - 仅源代码