我阅读了有关错误“无法生成密钥对DH”一前一后发射时超过1024位服务器sents的关键时间。 下载JCE无限制的罐子应该可以解决这个问题。 在测试环境中我有我遇到以下,对于相同的Web服务器,如果我使用Java 6进行HTTPS查询时,我没有得到任何错误,但如果我用Java 7的话,我得到“无法生成密钥对DH”。
我试图替换的jar文件JCE无限制,但仍然得到同样的错误。 自2007年以来的错误报道,但为什么它运行的Java 6,而不是针对Java 7? 要下载的文件不正确的? 我从以前的帖子链接的Java:为什么SSL握手给“无法生成密钥对DH”异常? 。
在这一点上,我不知道该怎么办。 如果我尝试加载BouncyCastle的供应商,我得到一个ArrayOutOfIndex例外。 我的服务器只允许DH算法,所以我不能用另一种算法类似建议在上述职位。
一些补充或澄清:
(Suncle)的Java 7,因为7u09默认使用的密码组比较明智一致的顺序,与7u04看似随机的顺序。 (我没有04和09之间的测试),这使秩序和ECDHE纯RSA(又名akRSA)DHE之前,从而避免问题当且仅当服务器支持ECDHE或RSA并同意客户的偏好。 (或者ECDH固定,但是几乎没有人使用了。)如果服务器上坚持DHE(无论何种原因),并使用DH> 1024位,你仍然有问题。
如果提问者(或其他人)连接到真正需要整数-DH(而不是ECDH或RSA)的服务器,8日前与Java工作的唯一途径是让使用DH 1024位服务器。 这AFAWK是一个几年在技术上安全的,但有一个薄利它是由像NIST重要机构(见csrc.nist.gov特别酒吧800-57)禁止。 (即使RSA 1024不破其实还,但它可能会很快,因此是禁止的。)
在“无限力量的政策”是不相关的这个问题,或者至少不是直接的,和良好的答案#6851461没说它是。 它不会改变对DH参数限制在了SunJCE,这(错误地)为标准的问题不是实力的问题进行处理。 (特别是它需要的是用于为DSA是正确的限制,并将其应用到DH)。它确实启用AES-256和SHA-2(仅适用于TLSv1.2工作)的套房,并给予足够奇怪的优先级列表,这可能改变从DHE(失败)非DHE(作品)的选择结果。
你并不需要完全回转到Java 6的列表中,你只需要在DHE等重点交流优先,或桀骜不驯服务器下降DHE完全。 你绝对不应该回去让任何出口或单DES套房,除非绝对需要一个传统的服务器; 他们已经不是现在很安全了好几年,并于6仍然默认启用远远超过他们应该有。
我偶然在与SSLScokets同样的问题,我想我发现此回归与Java 7的原因的原因涉及到客户端和服务器之间协商的加密算法。
默认情况下,Java 6中使得这些密码用于TLS连接(按优先顺序排列):
SSL_RSA_WITH_RC4_128_MD5
SSL_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_DES_CBC_SHA
SSL_DHE_RSA_WITH_DES_CBC_SHA
SSL_DHE_DSS_WITH_DES_CBC_SHA
SSL_RSA_EXPORT_WITH_RC4_40_MD5
SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
而Java 7使这些密码:
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_RC4_128_SHA
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_RC4_128_SHA
TLS_ECDH_ECDSA_WITH_RC4_128_SHA
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDH_RSA_WITH_RC4_128_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_RC4_128_MD5
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
使用的Diffie-Hellman密码来在更高的优先级上的Java 7,但他们似乎并不除非安装了强加密包,支持按键超过1024位。
我使用的解决方法是通过指定的Java 6的启用密码SSLSocket
:
SSLSocketFactory socketFactory = SSLContext.getInstance("TLS").getSocketFactory();
SSLSocket socket = (SSLSocket) socketFactory.createSocket(InetAddress.getByName(hostname), port);
socket.setEnabledCipherSuites(new String[] {
"SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_WITH_RC4_128_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV"});
socket.startHandshake();
由于您使用的是最新的Java版本,仍然得到了错误,你可以在java.security更改设置(例如,在文件夹C:\ Program Files文件\的Java \ jre1.8.0_xx \ lib \ security中
# Example:
# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
jdk.tls.disabledAlgorithms=SSLv3, RC4
加入DH作为jdk.tls.disabledAlgorithms禁用算法
jdk.tls.disabledAlgorithms=SSLv3, RC4, DH
tomcat的重新启动或重新运行您的程序。
我们也遇到了这个问题,Java7和Java8。 我们还使用了类似Emanual博格的建议解决方法。 但我们的目标是避免硬编码密码套件的固定列表。 因此,我们试图消除这些导致问题的项(通过试验和错误...)。
String[] enabledCipherSuites = socket.getEnabledCipherSuites();
// avoid hardcoding a new list, we just remove the entries
// which cause the exception
List<String> asList = new ArrayList(Arrays.asList(enabledCipherSuites));
// we identified the following entries causeing the problems
// "Could not generate DH keypair"
// and "Caused by: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)"
asList.remove("TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
asList.remove("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
asList.remove("TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
String[] array = asList.toArray(new String[0]);
socket.setEnabledCipherSuites(array);
问:是否有人看到这种方法有问题?
顺便说一句:如果你使用的是Apache了HTTPClient,然后https://issues.apache.org/jira/browse/HTTPCLIENT-1111有趣的是它展示了如何设置选择密码通过该方法(从V4.2的HTTPClient)
SSLConnectionSocketFactory() {...}.prepareSocket(SSLSocket)
更新2015年10月31日:为了帮助更好地理解上下文在何处使用这个,因为在这里,你看如何挂钩,在覆盖prepareSocket()全伪代码示例方法:
HttpClientBuilder builder = HttpClients.custom();
SSLContextBuilder sslContextBuilder = SSLContexts.custom();
SSLContext sslContext = sslContextBuilder.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostNameVerfier)
{
protected void prepareSocket(SSLSocket socket) throws IOException {
// Workaround to use different order of CipherSuites used by Java6 in order
// to avoid the the problem of java7 "Could not generate DH keypair"
String[] enabledCipherSuites = socket.getEnabledCipherSuites();
// but to avoid hardcoding a new list, we just remove the entries
// which cause the exception (via TrialAndError)
List<String> asList = new ArrayList(Arrays.asList(enabledCipherSuites));
// we identified the following entries causeing the problems
// "Could not generate DH keypair"
// and "Caused by: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)"
asList.remove("TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
asList.remove("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
asList.remove("TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
String[] array = asList.toArray(new String[0]);
socket.setEnabledCipherSuites(array);
};
};
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslsf).build();
PoolingHttpClientConnectionManager conman = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
builder.setConnectionManager(conman);
CloseableHttpClient httpClient = builder.build();
要小心,我们只是在一个方面,其中用户明确允许信任自签名证书使用这段代码(例如,用于测试环境等)。 如果你不希望这样做的话,最好做的SSL-东西不乱。
如果使用的是jdk1.7.0_04,升级到jdk1.7.0_21。 该问题已被固定在更新。