crypto_box_easy 和 crypto_box_open_easy 的奇怪行为。不用私钥解密?
Strange behavior of crypto_box_easy and crypto_box_open_easy. Decrypt without private key?
我测试了 libsodium 的 Public-key-cryptography 并遇到了一个奇怪的行为。加密的消息在没有私钥的情况下被解密。
来自官方网站的例子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 用自己的密钥解密来自 Alice 的消息,并用 Alice 的 public 密钥对其进行验证。
我在代码中犯了一个错误,并且在没有 Bob 的私钥的情况下正确解密了消息!
怎么可能?我的错误在哪里?谢谢
有可能
在 libsodium 中,public-key 认证加密分三个阶段完成,顺序为:
密钥交换 — 使用elliptic-curve Diffie-Hellman算法(X25519)生成共享密钥来自我的私钥和你的 public 密钥。
加密 — 使用在步骤 1 中生成的共享密钥对明文消息应用对称密钥加密 (XSalsa20)。
Authentication — 生成一个 MAC (Poly1305),再次依赖上述步骤中生成的密钥。
- 这些是
crypto_box_afternm
个步骤,即 the same as crypto_secretbox_easy
。
在步骤 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)
由于我们要求两对密钥生成相同的共享密钥,因此不难看出两对密钥也可以解密同一消息。
这很好
请注意,在您实施 "wrong" 解密时,您不仅使用了 Bob 的 public 密钥,还使用了 Alice 的私钥(只有 Alice知道)。
既然是爱丽丝要将加密的消息发送给鲍勃,这意味着爱丽丝应该首先知道明文消息。所以她可以使用自己的私钥解密该消息,这不是安全问题。
如果您将 Bob 的 public 密钥与另一个人 (Eve) 的私钥一起使用,解密程序将真的失败。
如果您认为 Alice 能够解密她自己的消息是个问题,您可以强制 Alice 在对话后销毁她的私钥,这样现在只有 Bob 可以解密它(并且不能从 Alice 发送更多消息).
事实上 libsodium 提供了 sealed box API 来执行此操作(生成一个临时密钥对并在加密后立即将其销毁)。
我测试了 libsodium 的 Public-key-cryptography 并遇到了一个奇怪的行为。加密的消息在没有私钥的情况下被解密。
来自官方网站的例子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 用自己的密钥解密来自 Alice 的消息,并用 Alice 的 public 密钥对其进行验证。 我在代码中犯了一个错误,并且在没有 Bob 的私钥的情况下正确解密了消息!
怎么可能?我的错误在哪里?谢谢
有可能
在 libsodium 中,public-key 认证加密分三个阶段完成,顺序为:
密钥交换 — 使用elliptic-curve Diffie-Hellman算法(X25519)生成共享密钥来自我的私钥和你的 public 密钥。
加密 — 使用在步骤 1 中生成的共享密钥对明文消息应用对称密钥加密 (XSalsa20)。
Authentication — 生成一个 MAC (Poly1305),再次依赖上述步骤中生成的密钥。
- 这些是
crypto_box_afternm
个步骤,即 the same ascrypto_secretbox_easy
。
- 这些是
在步骤 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)
由于我们要求两对密钥生成相同的共享密钥,因此不难看出两对密钥也可以解密同一消息。
这很好
请注意,在您实施 "wrong" 解密时,您不仅使用了 Bob 的 public 密钥,还使用了 Alice 的私钥(只有 Alice知道)。
既然是爱丽丝要将加密的消息发送给鲍勃,这意味着爱丽丝应该首先知道明文消息。所以她可以使用自己的私钥解密该消息,这不是安全问题。
如果您将 Bob 的 public 密钥与另一个人 (Eve) 的私钥一起使用,解密程序将真的失败。
如果您认为 Alice 能够解密她自己的消息是个问题,您可以强制 Alice 在对话后销毁她的私钥,这样现在只有 Bob 可以解密它(并且不能从 Alice 发送更多消息).
事实上 libsodium 提供了 sealed box API 来执行此操作(生成一个临时密钥对并在加密后立即将其销毁)。