Java SSL DH 密钥对生成 - 主要大小错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21442547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java SSL DH Keypair Generation - Prime Size Error
提问by ALP_Squid
I'm currently implementing Reddit OAuth2 login into my web app. The handshake and token exchange work fine when testing locally but when running on the server (hosted on 'OpenShift' DIY cartridge) I get the following error:
我目前正在实现 Reddit OAuth2 登录到我的网络应用程序。在本地测试时,握手和令牌交换工作正常,但在服务器上运行(托管在“OpenShift”DIY 墨盒上)时,我收到以下错误:
java.security.InvalidAlgorithmParameterException: Prime size must be
multiple of 64, and can only range from 512 to 1024 (inclusive)
Which is results in
结果是
java.lang.RuntimeException: Could not generate DH keypair
I've been searching most of the day and have found different solutions ranging from changing Java version to using BouncyCastle. However, I'm using the Scribelibrary so I don't think I can implement BouncyCastle without forking and changing the base of scribe, which kind of defeats it's purpose.
我一天中的大部分时间都在搜索,并找到了不同的解决方案,从更改 Java 版本到使用 BouncyCastle。但是,我正在使用Scribe库,所以我认为我无法在不分叉和更改 scribe 基础的情况下实现 BouncyCastle,这违背了它的目的。
Installing JCE Unlimited Strengthalso came up but I can't do that on OpenShift as there's no root access (might be able to get one of their team to do it).
安装JCE Unlimited Strength也出现了,但我不能在 OpenShift 上这样做,因为没有 root 访问权限(也许可以让他们的团队之一来做)。
The java versions in use are (taken from java -version
):
使用的 java 版本是(取自java -version
):
Local Testing Machine:
本地测试机:
java version "1.7.0_51"
OpenJDK Runtime Environment (IcedTea 2.4.4) (7u51-2.4.4-1ubuntu1)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)
OpenShift Server:
OpenShift 服务器:
java version "1.7.0_51"
OpenJDK Runtime Environment (rhel-2.4.4.1.el6_5-i386 u51-b02)
OpenJDK Server VM (build 24.45-b08, mixed mode)
I'm at a loss as to what I can do to solve this. Hopefully I'm being stupid or am misunderstanding something, so any possible solutions would be great!
我不知道我能做些什么来解决这个问题。希望我是愚蠢的或误解了什么,所以任何可能的解决方案都会很棒!
--
——
EDIT 1
编辑 1
The request code that returns the error (using Scribe, as I mentioned, so might not be much use). The token endpoint is https://ssl.reddit.com/api/v1/access_token
using POST. As I said above, this works on my testing machine.
返回错误的请求代码(使用 Scribe,正如我提到的,所以可能没有多大用处)。令牌端点正在https://ssl.reddit.com/api/v1/access_token
使用 POST。正如我上面所说,这适用于我的测试机。
OAuthRequest request = new OAuthRequest(getAccessTokenVerb(), getAccessTokenEndpoint());
request.addHeader("Authorization", "Basic"
+Base64.encode((config.getApiKey()+":"+config.getApiSecret()).getBytes()));
request.addBodyParameter("state", "none");
request.addBodyParameter(OAuthConstants.SCOPE, config.getScope());
request.addBodyParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
request.addBodyParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
request.addBodyParameter(OAuthConstants.CODE, verifier.getValue());
request.addBodyParameter("grant_type", "authorization_code");
Response response = request.send(); // Errors here from Request.createConnection in the Scribe code
return getAccessTokenExtractor().extract(response.getBody());
采纳答案by dave_thompson_085
First, "Unlimited Strength" is irrelevant here. That would fix the entirely different problem that you can't use cipher suites using AES-256 (and if the peer insists on them can't handshake at all). Also bitsize of the JVM doesn't matter; this (not really justified) restriction on DH is in the "run-everywhere" bytecode in SunJCE.
首先,“无限力量”在这里无关紧要。这将解决完全不同的问题,即您不能使用 AES-256 使用密码套件(如果对等方坚持他们根本不能握手)。JVM 的位大小也无关紧要;对 DH 的这个(不是真正合理的)限制在 SunJCE 中的“无处不在”字节码中。
You can use BouncyCastle as a crypto provider without changing the code that does SSL connections (in your case Scribe), but from what I've read making BC the preferred provider causes other problems. If you want to try anyway, either put bcprov-version.jar in JRE/lib/exit and edit JRE/lib/security/java.security; or put it anywhere in your classpath and have your init code call java.security.Security.insertProviderAt (new org.bouncycastle.jce.provider.BouncyCastleProvider(), position);
您可以将 BouncyCastle 用作加密提供程序,而无需更改执行 SSL 连接的代码(在您的情况下为 Scribe),但从我读过的内容来看,将 BC 设为首选提供程序会导致其他问题。如果您无论如何都想尝试,请将 bcprov-version.jar 放在 JRE/lib/exit 中并编辑 JRE/lib/security/java.security;或者把它放在你的类路径中的任何地方,让你的初始化代码调用 java.security.Security.insertProviderAt (new org.bouncycastle.jce.provider.BouncyCastleProvider(), position);
I suggest starting from why your local system DOES work. When I try ssl.reddit.com with openssl, it supports both ECDHE-RSA (with P-256) and DHE-RSA with dh 2048 bits. Suncle Java 7 does support and prefer ECDHE, and I would expect OpenJDK also does but maybe not or maybe sometimes not; I know RedHat until recently nobbled ECC in its rpms of openssl, and it wouldn't astonish me if they did so in openjdk also. If you compile and run the following (with ssl.reddit.com 443) it will tell what suite gets negotiated on your system, using all default SSL settings of your JRE (which I expect/hope Scribe is also using):
我建议从你的本地系统为什么工作开始。当我使用 openssl 尝试 ssl.reddit.com 时,它同时支持 ECDHE-RSA(带有 P-256)和带有 dh 2048 位的 DHE-RSA。Suncle Java 7 确实支持并更喜欢 ECDHE,我希望 OpenJDK 也支持,但可能不支持或有时不支持;我知道 RedHat 直到最近才在其 openssl 的 rpm 中对 ECC 进行了改进,如果他们也在 openjdk 中这样做,我也不会感到惊讶。如果您编译并运行以下内容(使用 ssl.reddit.com 443),它将使用您的 JRE 的所有默认 SSL 设置(我期望/希望 Scribe 也在使用)告诉您系统上协商的套件:
//nopackage DThompson 2012.08.13b
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class JustBConnectSSL {
/* (optionally bind and) just make SSL connection, for testing reach and trust
* uses default providers, truststore (normally JRE/lib/security/[jsse]cacerts),
* and keystore (normally none), override with -Djavax.net.ssl.{trust,key}Store*
*/
public static void main (String[] args) throws Exception {
if( args.length < 2 ){ System.out.println ("Usage: tohost port [fromaddr [fromport]]"); return; }
Socket sock = SSLSocketFactory.getDefault().createSocket();
if( args.length > 2 )
sock.bind (new InetSocketAddress (args[2], args.length>3? Integer.parseInt(args[3]): 0));
sock.connect (new InetSocketAddress (args[0], Integer.parseInt(args[1])));
System.out.println (sock.getInetAddress().getHostName() + " = " + sock.getInetAddress().getHostAddress());
((SSLSocket)sock).startHandshake();
System.out.println ("connect okay " + ((SSLSocket)sock).getSession().getCipherSuite());
}
}
If test gets _DHE_RSA_something, the crypto providers in your JRE must be different from the Suncle ones, either changed by Ubuntu or some customization or patch on your system. If test gets _ECDHE_RSA_something but OpenShift doesn't, they may have disabled ECC/ECDHE somehow. If they can enable that's best (ECDHE-P-256 is at least as secure and probably more efficient than DH-2048). Otherwise until Oracle fixes this (apparently in 8) the only way I think can be relied on is to disable DHE suites (and drop back to plain RSA, which may not be safe against NSA); that is simplest in the code that actually creates the SSLSocket, but if Scribe (like most java web clients) uses URL -> HttpsUrlConnection with its default SSLSocketFactory you can substitute a tweaked factory that changes the EnabledCiphers list along the lines of question #6851461 (although for a host with a good public certificate you don't need the custom-trustmanager parts of that solution).
如果测试得到 _DHE_RSA_something,则您的 JRE 中的加密提供程序必须与 Suncle 的不同,要么是由 Ubuntu 更改的,要么是您系统上的某些自定义或补丁。如果测试得到 _ECDHE_RSA_something 但 OpenShift 没有得到,他们可能以某种方式禁用了 ECC/ECDHE。如果他们可以启用那是最好的(ECDHE-P-256 至少与 DH-2048 一样安全并且可能更有效)。否则,在 Oracle 修复此问题(显然在 8 中)之前,我认为可以依赖的唯一方法是禁用 DHE 套件(并退回到普通 RSA,这可能对 NSA 不安全);这在实际创建 SSLSocket 的代码中是最简单的,但是如果 Scribe(像大多数 Java Web 客户端一样)使用 URL ->
回答by ALP_Squid
Not sure if it matters, but the version of OpenJDK running on OpenShift is 32 bit, you can view this by using the System.getProperty("sun.arch.data.model") in your code.
不确定它是否重要,但在 OpenShift 上运行的 OpenJDK 版本是 32 位,您可以通过在代码中使用 System.getProperty("sun.arch.data.model") 来查看它。
I wrote a quick class to just output the bit-ness and compiled it on the OpenShift gear and ran it and got 32
我写了一个简单的类来输出比特数并在 OpenShift 设备上编译它并运行它并得到 32
class Test {
public static void main(String[] args) {
System.out.println(System.getProperty("sun.arch.data.model"));
}
}
回答by Rahil
I know I am very late to answer this but I was struggling with the similar problem and then solved it. My solution is for MAC-OS.
我知道我回答这个问题已经很晚了,但我一直在努力解决类似的问题,然后解决了它。我的解决方案适用于 MAC-OS。
- Install Bouncy Castle jar from http://www.bouncycastle.org/latest_releases.html, in /Library/Java/JavaVirtualMachines//Contents/Home/jre/lib/ext
- edit java.security file add the below line security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider and then reorder all the other providers you may have.
- voila
- 从http://www.bouncycastle.org/latest_releases.html安装 Bouncy Castle jar ,在 /Library/Java/JavaVirtualMachines//Contents/Home/jre/lib/ext
- 编辑 java.security 文件添加以下行 security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider 然后重新排序您可能拥有的所有其他提供者。
- 瞧
回答by Michael Wyraz
I solved the problem on oracle java 8 by switching to bouncycastle provider for ssl/tls:
我通过切换到 ssl/tls 的 bouncycastle 提供程序解决了 oracle java 8 上的问题:
Added bouncycastle to my project
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.54</version> </dependency>
Before I do any SSL stuff, I add the BouncyCastle provider as 1st provider to the list:
Security.insertProviderAt(new BouncyCastleProvider(),1);
在我的项目中添加了 bouncycastle
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.54</version> </dependency>
在执行任何 SSL 操作之前,我将 BouncyCastle 提供程序作为第一个提供程序添加到列表中:
Security.insertProviderAt(new BouncyCastleProvider(),1);
That's all. Now my connections to sites with 4096 bit DH parameters works as expected (I'm using Apache HTTP Client). This should also work with jdk 7.
就这样。现在,我与具有 4096 位 DH 参数的站点的连接按预期工作(我使用的是 Apache HTTP 客户端)。这也应该适用于 jdk 7。