【问题标题】:SSLSocket and AES EncryptionSSLSocket 和 AES 加密
【发布时间】:2012-01-27 00:22:49
【问题描述】:

我们需要使用 AES 加密进行客户端服务器通信,所以当我在 SSLServetSocket(使用 Java 6)上启用密码套件 TLS_DHE_RSA_WITH_AES_128_CBC_SHA 并运行程序时,我遇到了异常

没有可用的证书或密钥对应于已启用的 SSL 密码套件

我的问题是我们能否通过 SSLSocket 进行 AES 加密,或者它需要是常规套接字。如果我们不能使用它,任何人都可以提供一个使用 AES 加密的客户端服务器通信示例。

这里是代码

public class AESServerSocketTest {

    public static void main(String[] args) {
        SSLServerSocket serverSocket;
        try 
        {
            SSLContext ctx = javax.net.ssl.SSLContext.getDefault();
            serverSocket =(SSLServerSocket)ctx.getServerSocketFactory().createServerSocket(8181);
            serverSocket.setEnabledCipherSuites(new String[]{"TLS_DHE_RSA_WITH_AES_128_CBC_SHA"});        

            SSLSocket in = (SSLSocket)serverSocket.accept(); 
        }
        catch (Exception e) 
        {
            System.out.println("Exception " + e);
        }
    }
}

提前致谢

【问题讨论】:

  • 您是如何配置您的证书/密钥库的?它是否至少在不设置任何特定密码套件的情况下工作?
  • 当我将它设置为匿名密码套件时它可以工作。我没有向密钥库添加任何证书/密钥,因为 AES 使用对称密钥进行加密和解密,我们需要添加吗?如果是,我们如何与客户分享。

标签: ssl aes


【解决方案1】:

匿名密码套件不执行任何身份验证。即使使用加密,您也可以通过加密通道与远程方交谈,但您无法确定那是谁,所以它可能是中间人 (MITM)。 TLS 1.1 specification 对匿名密码套件进行了以下说明:

以下密码套件用于完全匿名 双方均未通过身份验证的 Diffie-Hellman 通信。 请注意,此模式容易受到中间人攻击,并且 因此已弃用。

简而言之,不要使用它们(也许测试除外),或者如果您确实确定不会有活动的 MITM。 (TLS 1.2 规范对它们的使用措辞更加强烈。)

如果您想安全地使用 TLS,您需要一种方法让客户端验证身份的远程方。在绝大多数情况下,这是使用 X.509 证书完成的。特别是,对于 TLS_DHE_RSA_WITH_AES_128_CBC_SHA 密码套件,您需要一个带有 RSA 公钥的证书(这解释了您收到的错误消息)。

您应该生成或请求正确识别服务器的证书(自签名或通过 CA,也许是您自己的,取决于客户端的配置方式)。不仅证书需要被客户端信任(显式地或通过已建立的 CA),而且其身份信息也需要与服务器的身份信息相匹配,以客户端尝试连接到它的名称。

从您的示例中,不清楚您是在实施 HTTPS(例如)还是您自己的 SSL/TLS 协议。 RFC 6125 是该领域的最新规范,它统一了围绕多种协议(例如 HTTPS、LDAPS、IMAPS 等)的实践。由于它是一个相当新的 RFC,很少有库明确实现它(尽管它们在实践中可能会这样做,因为它整合了最佳实践)。毫无疑问,遵循RFC 2818, section 3.1(HTTP over TLS)关于此主题的指南通常是明智的:

如果存在 dNSName 类型的 subjectAltName 扩展,则必须 用作身份。否则,(最具体的)通用名称
必须使用证书的主题字段中的字段。虽然 通用名称的使用是现有的做法,它已被弃用并且 鼓励证书颁发机构改用 dNSName。

使用指定的匹配规则执行匹配 [RFC2459]。如果给定类型的多个身份存在于 证书(例如,多个 dNSName 名称,任何一个匹配 集合中的一个被认为是可接受的。)名称可能包含通配符 字符 * 被认为与任何单个域名匹配 组件或组件片段。例如,.a.com 匹配 foo.a.com 但 不是 bar.foo.a.com。 f.com 匹配 foo.com 但不匹配 bar.com。

在某些情况下,URI 被指定为 IP 地址而不是 主机名。在这种情况下,iPAddress subjectAltName 必须存在
在证书中,并且必须与 URI 中的 IP 完全匹配。

(RFC 6125 explicitly discourages the use of wildcard certificates.)

出于实际原因,证书中的 IP 地址并不理想(我认为许多商业 CA 无论如何都不会生成此类证书)。如果可以,请使用主题备用名称扩展名,否则,将主机名放在主题 DN 的 CN= RDN 中就足够了。 this answer 中有关于如何使用 SAN 生成 CSR/证书的说明。特别是,可以使用-ext option of Java 7's keytool(例如-ext san=dns:www.example.com);请注意,Java 7 的 keytool 生成的密钥库也应该可以在以前版本的 JRE 上使用。

此外,如果您没有除SSLContext.getDefault() 之外的任何其他代码(在这种情况下,您也可以使用默认的SSLServerSocketFactory),您需要指定密钥库:JRE 没有默认值(与信任库相反)。这可以使用javax.net.ssl.keyStore(和相关的系统属性)来完成。这个答案中有更多关于这个主题的内容(例如):https://stackoverflow.com/a/6341566/372643

【讨论】:

  • 感谢您的回复。我们将实现我们自己的协议(不是 https),我们可以为 AES 生成一个公钥吗,我认为它只使用一个密钥进行加密和解密。使用 AES 加密进行客户端服务器通信的过程是什么。
  • TLS 在 TLS 握手期间动态协商共享/对称密钥,然后在其余通信期间用于加密。您通常根本不需要自己访问它们。公钥/私钥在证书中使用(仅在握手期间使用)用于验证远程方和协商这些短期共享密钥。您或许可以改用预共享密钥 (PSK),但如果您不熟悉“传统”SSL/TLS,这可能更难设置。 (请注意,我在回答中所说的并非特定于 HTTPS。)
【解决方案2】:

没有可用的证书或密钥对应于 SSL 密码套件 哪些已启用

这个错误意味着:

您启用的密码套件不适合/不接受私钥/证书(这很可能意味着例如短密钥长度)或者您没有配置任何证书。

【讨论】:

    猜你喜欢
    • 2015-01-20
    • 2014-01-05
    • 2019-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    • 2015-09-03
    • 1970-01-01
    相关资源
    最近更新 更多