我想做一个测试应用程序,它使用libsodium从客户端到服务器进行通信.
许多语言都有许多端口: C#, PHP,...
并且总有一个例子"bob"和"alice".这很好,但他们从未表明如何以安全的方式通过网络交换公钥.
那么如何推荐交换"alice/client"和"bob/server"的公钥.
它们总是使用相同的文件或同一台机器来生成密钥对.
以下是libsodium-php扩展的摘录:
$alice_kp = crypto_box_keypair(); $alice_secretkey = crypto_box_secretkey($alice_kp); $alice_publickey = crypto_box_publickey($alice_kp); $bob_kp = crypto_box_keypair(); $bob_secretkey = crypto_box_secretkey($bob_kp); $bob_publickey = crypto_box_publickey($bob_kp); $alice_to_bob_kp = crypto_box_keypair_from_secretkey_and_publickey ($alice_secretkey, $bob_publickey); $bob_to_alice_kp = crypto_box_keypair_from_secretkey_and_publickey ($bob_secretkey, $alice_publickey); $alice_to_bob_message_nonce = randombytes_buf(CRYPTO_BOX_NONCEBYTES); $alice_to_bob_ciphertext = crypto_box('Hi, this is Alice', $alice_to_bob_message_nonce, $alice_to_bob_kp); $alice_message_decrypted_by_bob = crypto_box_open($alice_to_bob_ciphertext, $alice_to_bob_message_nonce, $bob_to_alice_kp); $bob_to_alice_message_nonce = randombytes_buf(CRYPTO_BOX_NONCEBYTES); $bob_to_alice_ciphertext = crypto_box('Hi Alice! This is Bob', $bob_to_alice_message_nonce, $bob_to_alice_kp); $bob_message_decrypted_by_alice = crypto_box_open($bob_to_alice_ciphertext, $bob_to_alice_message_nonce, $alice_to_bob_kp);
小智.. 9
Libsodium不提供任何直接的密钥交换方法.您可以通过几种不同的方式安全地进行密钥交换:
通过防篡改的"带外通信"提供公钥或者如果通道对听众是安全的,则是共享秘密.(例如BittorrentSync,包含从设备到设备扫描的共享密钥的QR代码)
让受信任的第三方在未加密发送公钥之前对其进行签名.(例如SSL/TLS中的证书颁发机构)
证书固定(例如Google Chrome for Google URL)
由于您可能不想重新实现SSL/TLS,因此第一个或第三个选项可能是最佳选择.然而,第一种在客户端/服务器格式上有点难,因为PHP服务器可能只有互联网进行通信.
但是,如果您控制客户端,则可以执行证书固定.也就是说,将Bob的公钥嵌入Alice的可执行文件中.然后,Alice将仅使用Bob的公钥加密消息.
例如,Alice使用Bob的公钥和她自己的私钥来加密某些数据,并将其(以及唯一的随机数和Alice的公钥)发送给Bob.
Bob使用他收到的公钥和他自己的私钥来解密和验证加密的数据包.Bob可以安全地使用其中的任何数据,因为只有他和Alice可以解密它.
好吧,Eve可以阻止Alice的消息并发送Eve的公钥,但她会盲目工作,因为Alice只发送用Alice的私钥和Bob的公钥加密的消息.
在鲍勃看来,她只是另一个客户.在爱丽丝的眼里,她会感到沮丧,因为鲍勃似乎没有回应.
如果Eve发送Alice消息,他们将始终被标记为无效,因为Alice使用Alice的私钥和Bob的公钥来尝试解密它们,因为Eve没有Bob的私钥,所以它将失败.
如果Alice没有经过验证的可执行文件,Eve可能会在下载时对其进行更改(并插入Eve的公钥而不是Bob的公钥).验证可以通过她的包管理器,应用程序商店(大多数用于代码签名和SSL/TLS用于下载)或签名的可执行文件/源代码tarball来完成.
有关泄露的私钥的说明,请参阅此答案的最后一部分.
在客户端的用户以某种方式(通过某些用户专用密码或将来可能通过使用SQRL)验证自身后,您可以通过HTTPS在网站上提供QR代码,显示客户端可以扫描的QR代码或链接自定义协议,通过将自身注册到OS作为该uri协议的处理程序.
上述QR代码/ uri方法的一个不太复杂的替代方法是让用户从上面提到的HTTPS站点复制粘贴共享密钥,该密码将用于使用钠的crypto_secretbox()方法进行初始公钥交换.
请注意,共享密钥/公钥在传输过程中可能应该是base64,base32或hex编码,因为密钥中的某些字节可能会因不同的字符编码而受到损坏.
如果您想在私钥泄漏的情况下保密,那么初始公钥/私钥对只应用于交换永远不会保存到永久存储介质的第二轮公钥(实质上,没有磁盘或数据库) ).由于您的案例只是一个测试应用程序,因此Forward Secrecy可能不是很重要.
第二轮密钥每隔一段时间(例如每24小时)被丢弃,从而降低过去数据由于OpenSSL的Heartbleed等漏洞而变得脆弱的风险.
在使用PHP的传统Web服务器中,这可能很难做到,因为为每个HTTP请求重置所有变量.正确配置的memcached实例可能是一个选项,但存在泄漏临时私钥的风险.
Libsodium不提供任何直接的密钥交换方法.您可以通过几种不同的方式安全地进行密钥交换:
通过防篡改的"带外通信"提供公钥或者如果通道对听众是安全的,则是共享秘密.(例如BittorrentSync,包含从设备到设备扫描的共享密钥的QR代码)
让受信任的第三方在未加密发送公钥之前对其进行签名.(例如SSL/TLS中的证书颁发机构)
证书固定(例如Google Chrome for Google URL)
由于您可能不想重新实现SSL/TLS,因此第一个或第三个选项可能是最佳选择.然而,第一种在客户端/服务器格式上有点难,因为PHP服务器可能只有互联网进行通信.
但是,如果您控制客户端,则可以执行证书固定.也就是说,将Bob的公钥嵌入Alice的可执行文件中.然后,Alice将仅使用Bob的公钥加密消息.
例如,Alice使用Bob的公钥和她自己的私钥来加密某些数据,并将其(以及唯一的随机数和Alice的公钥)发送给Bob.
Bob使用他收到的公钥和他自己的私钥来解密和验证加密的数据包.Bob可以安全地使用其中的任何数据,因为只有他和Alice可以解密它.
好吧,Eve可以阻止Alice的消息并发送Eve的公钥,但她会盲目工作,因为Alice只发送用Alice的私钥和Bob的公钥加密的消息.
在鲍勃看来,她只是另一个客户.在爱丽丝的眼里,她会感到沮丧,因为鲍勃似乎没有回应.
如果Eve发送Alice消息,他们将始终被标记为无效,因为Alice使用Alice的私钥和Bob的公钥来尝试解密它们,因为Eve没有Bob的私钥,所以它将失败.
如果Alice没有经过验证的可执行文件,Eve可能会在下载时对其进行更改(并插入Eve的公钥而不是Bob的公钥).验证可以通过她的包管理器,应用程序商店(大多数用于代码签名和SSL/TLS用于下载)或签名的可执行文件/源代码tarball来完成.
有关泄露的私钥的说明,请参阅此答案的最后一部分.
在客户端的用户以某种方式(通过某些用户专用密码或将来可能通过使用SQRL)验证自身后,您可以通过HTTPS在网站上提供QR代码,显示客户端可以扫描的QR代码或链接自定义协议,通过将自身注册到OS作为该uri协议的处理程序.
上述QR代码/ uri方法的一个不太复杂的替代方法是让用户从上面提到的HTTPS站点复制粘贴共享密钥,该密码将用于使用钠的crypto_secretbox()方法进行初始公钥交换.
请注意,共享密钥/公钥在传输过程中可能应该是base64,base32或hex编码,因为密钥中的某些字节可能会因不同的字符编码而受到损坏.
如果您想在私钥泄漏的情况下保密,那么初始公钥/私钥对只应用于交换永远不会保存到永久存储介质的第二轮公钥(实质上,没有磁盘或数据库) ).由于您的案例只是一个测试应用程序,因此Forward Secrecy可能不是很重要.
第二轮密钥每隔一段时间(例如每24小时)被丢弃,从而降低过去数据由于OpenSSL的Heartbleed等漏洞而变得脆弱的风险.
在使用PHP的传统Web服务器中,这可能很难做到,因为为每个HTTP请求重置所有变量.正确配置的memcached实例可能是一个选项,但存在泄漏临时私钥的风险.