要实现国密双向认证的数据发送,需要使用支持国密算法的Java库,并且确保HTTP客户端能够处理SSL/TLS连接时的客户端证书验证。
在这个例子中,使用Java标准库结合Bouncy Castle作为提供国密算法的支持。
下面是一个简化的示例,展示如何使用Java实现国密双向认证的数据发送。
请注意,实际开发中可能需要更多的错误处理和配置细节。
首先,确保你已经添加了Bouncy Castle作为安全提供者,以支持国密算法:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
public class GmProviderInitializer {
static {
Security.addProvider(new BouncyCastleProvider());
}
}
接下来,我们需要一个GmHttpClient
类来处理HTTP请求。这个类将使用Apache HttpClient来发送请求,并使用Bouncy Castle来处理SSL连接。
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfoBuilder;
import org.bouncycastle.pkcs.PKCS8PrivateKeyInfo;
import org.bouncycastle.pkcs.PKCS8PrivateKeyInfoBuilder;
import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.pkcs.PKCSPrivateKey;
import org.bouncycastle.x509.X509CertificateHolder;
import org.bouncycastle.x509.X509v3CertificateBuilder;
import org.bouncycastle.x509.extension.X509Extensions;
import org.bouncycastle.x509.util.X509Principal;
import org.bouncycastle.x509.util.X509TBSCertificateBuilder;
import org.bouncycastle.x509.util.X509Time;
import org.bouncycastle.x509.util.X509v3TBSCertificateBuilder;
import javax.net.ssl.SSLContext;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class GmHttpClient {
private KeyStore encCertStore;
private KeyStore sigCertStore;
public void setEncCert(String path) throws Exception {
loadKeyStore(path, "encCertStore");
}
public void setSigCert(String path) throws Exception {
loadKeyStore(path, "sigCertStore");
}
private void loadKeyStore(String path, String storeName) throws Exception {
try (InputStream is = this.getClass().getResourceAsStream(path)) {
if (is == null) {
throw new FileNotFoundException("Resource not found: " + path);
}
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(is, "password".toCharArray()); // Change password as needed.
if ("encCertStore".equals(storeName)) {
encCertStore = ks;
} else {
sigCertStore = ks;
}
}
}
public static String sendPost(String url, Map<String, String> params) throws Exception {
SSLContext sslContext = createSslContext();
try (CloseableHttpClient httpClient = HttpClients.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build()) {
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json");
StringEntity entity = new StringEntity(objectToJson(params), StandardCharsets.UTF_8);
httpPost.setEntity(entity);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
return EntityUtils.toString(response.getEntity(), "UTF-8");
}
}
}
private static SSLContext createSslContext() throws Exception {
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream is = GmHttpClient.class.getResourceAsStream("/cert/VHD_ENC.p12")) {
keyStore.load(is, "password".toCharArray());
}
keyManagerFactory.init(keyStore, "password".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, new SecureRandom());
return sslContext;
}
private static String objectToJson(Map<String, String> obj) {
StringBuilder json = new StringBuilder();
json.append("{");
for (Map.Entry<String, String> entry : obj.entrySet()) {
json.append("\"").append(entry.getKey()).append("\":\"").append(entry.getValue()).append("\",");
}
if (json.length() > 1) {
json.setLength(json.length() - 1); // Remove last comma
}
json.append("}");
return json.toString();
}
}
然后,使用这个类来发送一个POST请求:
public class Main {
public static void main(String[] args) throws Exception {
GmHttpClient client = new GmHttpClient();
client.setEncCert("classpath:cert/VHD_ENC.p12");
client.setSigCert("classpath:cert/VHD_SIG.p12");
HashMap<String, String> params = new HashMap<>();
params.put("param", "请求参数值");
String url = "https://192.168.2.100:1443/client/v1/list";
String result = GmHttpClient.sendPost(url, params);
System.out.println(result);
}
}
这个示例中的createSslContext
方法假设客户端证书是在运行时从资源路径读取的,你需要确保这些证书文件存在于指定的路径中,并且具有正确的密码。此外,这里简化了一些细节,例如证书的验证过程和异常处理等