如何在非对称加密(libsodium)中使用随机数?

9
我正在编写一款应用程序,用户可以使用端对端加密在设备之间通信。为此,我使用libsodium加密库。非对称加密函数crypto_box(...)需要一个nonce作为其中一个参数。
我有点困惑如何处理nonce。每个发送给某个人的消息都需要使用不同的nonce进行加密吗?这似乎不正确,因为我将不得不在具有公共访问权限的服务器上存储已使用的nonce,攻击者可以随便再次使用其中一个nonce。
所有从A发送到B的消息都具有不同的nonce是否足够,或者用于从A发送到B的nonce不能用于从C发送到B?
请有人向我解释一下。

2
“nonce”实际上是“Number used ONCE”的缩写。所以,是的,您需要使用不同的数字! - OJFord
2个回答

7
每次使用共享密钥发送消息时,都需要一个唯一的nonce。Nonce不必是秘密的;一个简单的计数器就可以了;即使两次发送相同的消息,只要更改nonce中的一个位,密文看起来也会完全不同。
什么是共享密钥?它是从(A的私钥,B的公钥)或(A的公钥,B的私钥)计算出来的密钥。A和B根据自己拥有的内容进行不同的计算,但最终得到相同的共享密钥。
在crypto_box中使用的共享密钥长度为256位。这是非常大的。您可以安全地认为每个“对话”使用的共享密钥都是唯一的。
因此,(A,B),(A,C)和(C,B)可以安全地使用相同的nonce交换消息。但是,如果A使用给定的nonce向B发送消息,则B不能使用相同的nonce向A发送消息。在A和B之间的所有交换中,nonce都必须是唯一的。
因此,一个简单的计数器可能很好。让A选择偶数,留下奇数给B,在发送每条消息后将nonce增加2,然后您就可以开始了。
但是,在crypto_box构造中使用的密码实际上具有非常大的nonce。192位。
这意味着,如果您忽略我写的一切,每次发送消息时只需选择一个随机nonce,那么发生冲突的概率是如此之小,以至于您可以放心地保证它在实践中永远不会发生。
Sodium中包含的一些流密码(AES128-CTR,ChaCha20,Salsa20)具有较短的nonce,并且需要计数器以避免冲突。这就是它们在文档的“高级”部分中的原因。
但是对于crypto_box和crypto_secretbox,每次都选择一个随机nonce(randombytes_buf(nonce,sizeof nonce)),您将是安全的。

6
每个发给一个人的消息都需要使用不同的nonce进行加密吗?
是的。事实上,永远不要为相同的私钥使用相同的nonce。确实需要跟踪nonce来实现这一点。
这似乎不太对,因为我必须在具有公共访问权限的服务器上存储已使用的nonce,攻击者可以再次使用其中一个已使用的nonce。
您为什么必须将nonce存储在具有公共访问权限的服务器上?您认为攻击者如何“使用”nonce?他们需要您的私钥才能这样做。
为什么不能将nonce存储在与您的私钥相同的位置?

但是当A想要向B发送一个加密消息时,A会使用B的公钥对消息进行加密。这就是我感到困惑的地方。因此,A决定随机数而B无法控制用于加密发送给B并稍后使用B的私钥解密的消息所使用的随机数。我在这里缺失了什么? - joakimb
发现了这个链接:http://curvecp.org/nonces.html,其中说,“在使用特定的nonce加密数据包之后,不能再使用相同的nonce来加密另一个从发送者的秘密密钥到此接收者的公共密钥的数据包,并且不能再使用相同的nonce来加密从接收者的秘密密钥到该发送者的公共密钥的另一个数据包。”现在我明白了,只有在A和B之间才不能使用相同的nonce两次。 - joakimb
6
如果 A 向 B 发送加密信息,B 是否需要使用相同的一次性数字(A 用来加密信息的)来解密信息?还是它会生成一个新的一次性数字来解密信息。我理解加密和解密需要对方的公钥。我的疑问是,在除公钥以外的数据加/解密中,是否需要将一次性数字在 A 和 B 之间交换。 - Feru
1
@Feru 是的,nonce 不是一个秘密,并且作为密码文本有效负载的一部分包含在内。 - Woodstock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接