【问题标题】:Strange behavior of crypto_box_easy and crypto_box_open_easy. Decrypt without private key?crypto_box_easy 和 crypto_box_open_easy 的奇怪行为。不用私钥解密?
【发布时间】:2017-02-09 08:59:05
【问题描述】:

我已经通过 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;
}

使用公钥认证加密,Alice 可以使用 Bob 的公钥加密专门为 Bob 发送的机密消息。

使用 Alice 的公钥,Bob 可以在最终解密之前验证加密消息实际上是由 Alice 创建的并且没有被篡改。

Bob 只需要 Alice 的公钥、nonce 和密文。

为了向 Bob 发送消息,Alice 只需要 Bobs 的公钥。

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

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

【问题讨论】:

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


    【解决方案1】:

    是的,有可能

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

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

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

    3. 身份验证 — 再次依赖在上述步骤中生成的密钥生成 MAC (Poly1305)。

    在步骤 2-3 中使用对称加密意味着 相同 密钥必须可由 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)
    

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

    这很好

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

    由于是 Alice 想要将加密消息发送给 Bob,这意味着 Alice 首先应该已经知道纯文本消息。因此,她可以使用自己的私钥解密该消息,这不是安全问题。

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

     

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

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

    【讨论】:

    • 非常感谢您的回答。这种行为并不明显。在文档中:'pk 是加密消息的发件人的公钥。 sk 是愿意验证和解密它的接收者的密钥。如果验证失败,该函数返回 -1,成功返回 0。成功后,解密的消息存储到 m'
    • 安全问题是如果 Alice 的私钥被盗,攻击者可以解密 Bob 的所有消息。感谢您提示有关密封盒的信息
    • @Lexeich 请注意,密封箱无法验证发件人。您可以在密封盒子后使用真正的私钥应用签名,但不要引用我的内容,最好通过security.stackexchange.com 与安全专家核实。
    • @Lexeich:问题与您的表述略有不同。在“传统”非对称密码学中,获取 Alice 的密钥会危及发送给 Alice 的所有消息(包括那些从 Bob 发送的消息)。使用上述libsodium 方法,发送给 Alice 和 Alice 发送的所有消息都会受到影响。在这两种情况下,鲍勃与其他通讯员的通信中传递的消息都将保密。
    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 2014-07-12
    • 2013-12-24
    • 1970-01-01
    • 2017-11-25
    • 1970-01-01
    • 2012-07-13
    • 1970-01-01
    相关资源
    最近更新 更多