如何正确加密客户端和服务器之间的通信通道(没有 SSL)?

信息安全 加密 密码学 网络 tls
2021-09-06 03:53:05

我对密码学的世界知之甚少,我才刚刚开始学习,所以我是新手:)

作为一个进入密码学领域的项目,我想编写一个客户端\服务器程序,它可以以安全的方式(加密)发送和接收数据。

假设我想加密客户端和服务器之间或两个客户端之间的流量。我正在运行的服务只能在已知端口上与服务器或另一个客户端(也充当服务器)通信,服务器基本上在默认端口的一侧侦听连接。

我希望这些服务能够相互交谈,而不会让正在网络上收听的第三方能够解密对话内容或试图冒充服务。

我不是在寻找交换密钥的新方法(或者我应该吗?),我可以将密钥安全地保存在服务中,因此当x向y发送消息并返回时,它们将是唯一可以解密内容和响应(偏离路线,仅对经过验证的服务)。

  • 旁注,密钥可以保存在程序中 - 硬编码,或者它可以从可以传递给客户端的事物组合(例如 IP、计算机名称、用户名或任何其他常量组合)中生成,因此它将能够生成密钥(假设我正在传递 IP、计算机名称和随机种子,将有一个已知的公式从这些值创建密钥)。

我需要使用对称密钥进行加密,但也许我可以像 SSL 一样尝试使用两个预先生成的密钥。

我知道如果我一次又一次地使用同一个密钥,第三方可以嗅探流量并获取密钥(最好是数学,它是如何完成的?),他收集的数据越多,就越容易(?)。

那么,我应该怎么做才能保证没有人能够获得加密密钥(最终读取数据)?我应该使用哪种密码?在我开始我的旅程之前,我还需要知道什么?

4个回答

这实际上比我认为的其他人建议的要简单。这是我的建议:

  1. 使用 RSA 生成公钥/私钥对。您可以使用 openssl 在任何 unix 机器上执行此操作:openssl genrsa -out rsa.private 2048
  2. 在客户端中以硬编码的形式分发公钥。
  3. 当客户端登录时,客户端会生成一个私有共享密钥(也使用 openssl 或其他众所周知的加密库)并使用公钥对其进行加密。
  4. 客户端和服务器之间的所有数据都应在会话期间使用新的共享密钥进行加密。

您可以做很多其他的事情来强化它,例如将会话长度限制在重新生成密钥之前的一小时或几个小时,让服务器签署消息摘要等。全面了解加密将帮助您了解什么这些是为什么,但对于基本实现(对于中低价值数据),这应该足够了。

在编码之前,请阅读:http ://www.schneier.com/book-applied.html

不幸的是,这个问题太宽泛了,不适合 StackExchange。如果没有接受过数学、计算机科学和工程方面的正规教育,很少有人能够通过密码学的长度和广度取得任何程度的成功。

这本书将帮助你学习常见的概念、常见的错误、要学习的知识点和要遵循的例子。

基本上,您需要 SSL 提供的那种隧道。这些事情实际上很难做对。

SSL 是几个东西的集合。有隧道本身:一旦有一个共享密钥(在TLS 规范中称为“预主密钥” ),并且客户端和服务器就使用哪种算法达成一致,则可以对各个数据记录进行加密,如在规范的第 6 节中进行了描述。为了达到这一点,SSL 首先执行发生非对称加密的握手如果您同时控制客户端和服务器,并且它们已经“固有地”共享一个秘密,那么您可以跳过握手。

在握手期间,服务器发送一个不透明的 blob(“证书”),客户端可以使用它来获取服务器的公钥。如果客户端对服务器的公钥有固有的了解,那么它可以完全忽略服务器发送的内容,而只需使用已知的公钥。仅当客户端想要动态发现服务器的公钥时才使用证书验证(这是一段相当复杂的代码) ——这就是在 Web 上发生的事情。但是,根据您的情况,这不是必需的。

我们现在在这个网站上有一个关于SSL 如何使用非常描述性的答案(如果很长)的问题。

如果 SSL 不能激发您的灵感,请查看 SSH。相同的概念,不同的协议。SSH 在多个文档中进行了描述;RFC 4251开始。

如果没有独立的分发渠道将密钥从服务器传输到客户端,则无法完成。对于 SSL,这就是整个证书签名过程以及 Web 浏览器中包含的证书颁发机构根证书的公钥。因此,您的第一个问题是解决如何以无法被中间人攻击(即不通过网络)拦截的方式从服务器获取密钥到客户端。