6

这是我用来执行简单 HTTPS 请求的代码的简化版本:

// Assume the variables host, file and postData have valid String values

final URL url = new URL("https", host, file);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();

connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-length", String.valueOf(postData.length()));

final DataOutputStream output = new DataOutputStream(connection.getOutputStream());
output.writeBytes(postData);
output.close();

final InputStream input = new DataInputStream(connection.getInputStream());

for (int c = input.read(); c != -1; c = input.read()) {
  System.out.print((char) c);
}

System.out.println();

input.close();

直到最近完成了一些安全升级,这在连接到我们的服务器时效果很好(如果我使用 http 作为协议,仍然可以)。

现在它给了我这个问题中提到的“无法生成 DH 密钥对”和“Prime 大小必须是 64 的倍数,并且只能从 512 到 1024(含)”错误:

Java:为什么 SSL 握手会给出“无法生成 DH 密钥对”异常?

原来这是 Java 中的一个已知错误,建议使用 BouncyCastle 的 JCE 实现。

我的问题是......我如何使用 BouncyCastle 来做这样的事情?还是有更多的选择?

免责声明:我对密码学和使 HTTPS 查询成为可能的底层技术知之甚少,也不感兴趣。相反,我更愿意专注于我的应用程序逻辑,让各种库来处理低级问题。

我查看了 BouncyCastle 网站和文档,并在 Google 上搜索以了解有关 JCE 等的更多信息,但总而言之,这非常令人难以抗拒,我无法找到任何简单的代码示例来执行上述代码之类的操作。

4

4 回答 4

5

以下示例代码使用 jdk1.6.0_45 和 bcprov-jdk15on-153.jar 执行简单的 https 查询:

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;

import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.tls.DefaultTlsClient;
import org.bouncycastle.crypto.tls.TlsAuthentication;
import org.bouncycastle.crypto.tls.TlsClientProtocol;
import org.bouncycastle.crypto.tls.TlsCredentials;

public class TestHttpClient {
    // Reference: http://boredwookie.net/index.php/blog/how-to-use-bouncy-castle-lightweight-api-s-tlsclient/
    //            bcprov-jdk15on-153.tar\src\org\bouncycastle\crypto\tls\test\TlsClientTest.java
    public static void main(String[] args) throws Exception {
        java.security.SecureRandom secureRandom = new java.security.SecureRandom();
        Socket socket = new Socket(java.net.InetAddress.getByName("www.google.com"), 443);
        TlsClientProtocol protocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(),secureRandom);
        DefaultTlsClient client = new DefaultTlsClient() {
            public TlsAuthentication getAuthentication() throws IOException {
                TlsAuthentication auth = new TlsAuthentication() {
                    // Capture the server certificate information!
                    public void notifyServerCertificate(org.bouncycastle.crypto.tls.Certificate serverCertificate) throws IOException {
                    }

                    public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException {
                        return null;
                    }
                };
                return auth;
            }
        };
        protocol.connect(client);

        java.io.OutputStream output = protocol.getOutputStream();
        output.write("GET / HTTP/1.1\r\n".getBytes("UTF-8"));
        output.write("Host: www.google.com\r\n".getBytes("UTF-8"));
        output.write("Connection: close\r\n".getBytes("UTF-8")); // So the server will close socket immediately.
        output.write("\r\n".getBytes("UTF-8")); // HTTP1.1 requirement: last line must be empty line.
        output.flush();

        java.io.InputStream input = protocol.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        String line;
        while ((line = reader.readLine()) != null)
        {
            System.out.println(line);
        }
    }
}
于 2015-10-19T09:27:46.233 回答
3

是有关如何注册充气城堡 JCE 提供商的页面。如果选择第二个选项,请确保N(preference order) 的值位于 Sun JCE 提供者之前(并相应地调整 Sun JCE 提供者注册的首选项顺序)。

于 2011-11-17T18:21:23.313 回答
1

我找到了一个甚至不需要使用 BouncyCastle 的不同解决方案(尽管通过 srkavin 发布的链接):

Java 下载站点下载“Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files”并替换我的 JRE 中的文件后,上述代码无需任何修改即可开始工作。

于 2011-11-18T10:53:24.270 回答
0

我有同样的问题并解决,包括这些行

Security.addProvider(new BouncyCastleProvider());
System.setProperty("https.protocols", "TLSv1");
于 2018-07-12T10:54:44.723 回答