系统要求
Android 7.0(API 24)及以上
功能介绍
- 单向认证,客户端不需要国密证书和密钥
- 接收并显示服务器端国密数字证书
- 忽略服务端域名与国密证书不一致的警告
- 忽略不信任服务端国密根证书的警告
- 使用PP软件授权平台获取授权数据的简要说明
核心代码
/**
*
*/
package com.pplic.android.sample.doublecasseandroidlibproject;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.collections4.MapUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import doubleca.security.gmssl.provider.DoubleCASSE;
import doubleca.security.provider.DoubleCA;
/**
* @author www.DoubleCA.com
*/
public class HttpClientUtil
{
private static final String ENCODING = "UTF-8";
private static HttpClient client = null;
private static SchemeRegistry schemeRegistry; // 协议控制
private static PoolingClientConnectionManager ccm; // HttpClient连接池(多连接的线程安全的管理器)
private static DoubleCASSE dcsse = null;
/**
* 用授权数据初始化dcsse
*/
public boolean initLic(DoubleCASSE obj, String licData)
{
dcsse = obj;
// 获得的本机授权数据,在https://www.PPLIC.com软件授权平台获取
if (licData == null)
{
// 未授权,生成授权请求数据,与授权码一起在PP软件授权平台生成终端的授权数据,也可以请求PP软件授权平台的网络API在线申请授权数据
StringBuffer requestDataBuffer = new StringBuffer();
dcsse.generateLicRequest(requestDataBuffer);
System.out.println("Android终端授权请求数据:" + requestDataBuffer.toString());
return false;
}
else
{
dcsse.setLicData(licData);
Date licDate = dcsse.getLicEndTime();
if (licDate == null)
{
System.out.println("非法授权数据!");
return false;
}
else
{
System.out.println("授权有效期:" + dcsse.getLicEndTime().toLocaleString());
initClient();
return true;
}
}
}
private void initClient()
{
try
{
/*
* 与https请求相关的操作
*/
KeyStore sm2ClientKeyStore = KeyStore.getInstance("DCKS");
sm2ClientKeyStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactoryEx(sm2ClientKeyStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //允许所有主机的验证
HttpParams httpParams = new BasicHttpParams();
httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000);// 连接超时时间(ms)
httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);// 操作超时时间(ms)
httpParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);// 设置http1.1或http1.0
// 设置http https支持
/*
* 定义访问协议
*/
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", sf, 443));
ClientConnectionManager conManager = new ThreadSafeClientConnManager(httpParams, schReg);
client = new DefaultHttpClient(conManager, httpParams);
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* get请求
*
* @param url 请求URL
* @param paramMap 请求参数
* @param headerMap 请求头信息
*/
public String get(String url, Map<String, String> paramMap, Map<String, String> headerMap) throws ClientProtocolException, IOException
{
/*
* 拼接URL与参数
*/
if (MapUtils.isNotEmpty(paramMap))
{
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (String key : paramMap.keySet())
{
params.add(new BasicNameValuePair(key, paramMap.get(key)));
}
String queryString = URLEncodedUtils.format(params, ENCODING);
if (url.indexOf("?") > -1)
{// 存在?,表示这时的URL已经带参数了
url += "&" + queryString;
}
else
{
url += "?" + queryString;
}
}
HttpGet httpGet = new HttpGet(url);
/*
* 设置头信息
*/
if (MapUtils.isNotEmpty(headerMap))
{
Set<String> keySet = headerMap.keySet();
for (String key : keySet)
{
httpGet.addHeader(key, headerMap.get(key));
}
}
String result = "";
HttpResponse response = client.execute(httpGet); // 发出get请求
StatusLine status = response.getStatusLine(); // 获取返回的状态码
HttpEntity entity = response.getEntity(); // 获取返回的响应内容
if (status.getStatusCode() == HttpStatus.SC_OK)
{ // 200
result = EntityUtils.toString(entity, ENCODING);
}
httpGet.abort();// 中止请求,连接被释放回连接池
return result;
}
/**
* post请求
*
* @param url //请求URL
* @param paramMap //请求参数
* @param headerMap //请求头信息
*/
public String post(String url, Map<String, String> paramMap, Map<String, String> headerMap) throws ClientProtocolException, IOException
{
HttpPost httpPost = new HttpPost(url);
/*
* 处理参数
*/
List<NameValuePair> params = new ArrayList<NameValuePair>();
if (MapUtils.isNotEmpty(paramMap))
{
Set<String> keySet = paramMap.keySet();
for (String key : keySet)
{
params.add(new BasicNameValuePair(key, paramMap.get(key)));
}
}
/*
* 设置头信息
*/
if (MapUtils.isNotEmpty(headerMap))
{
Set<String> keySet = headerMap.keySet();
for (String key : keySet)
{
httpPost.addHeader(key, headerMap.get(key));
}
}
String result = "";
httpPost.setEntity(new UrlEncodedFormEntity(params, ENCODING));// 设置参数
HttpResponse response = client.execute(httpPost); // 发出post请求
StatusLine status = response.getStatusLine(); // 获取返回的状态码
HttpEntity entity = response.getEntity(); // 获取响应内容
if (status.getStatusCode() == HttpStatus.SC_OK)
{
result = EntityUtils.toString(entity, ENCODING);
}
httpPost.abort();// 中止请求,连接被释放回连接池
return result;
}
class SSLSocketFactoryEx extends SSLSocketFactory
{
SSLContext sslContext = null;
public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException, NoSuchProviderException
{
super(truststore);
sslContext = SSLContext.getInstance("GMSSLv1.1", DoubleCASSE.PROVIDER_NAME);
TrustManager tm = new X509TrustManager()
{
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return null;
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException
{
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException
{
System.out.println("服务端国密证书信息:");
for (int i = 0; i < chain.length; i++)
{
System.out.println(chain[i].getSubjectDN().getName());
}
}
};
sslContext.init(null, new TrustManager[]{tm}, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException
{
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException
{
return sslContext.getSocketFactory().createSocket();
}
}
}
Android平台运行结果
国密数字证书
DCKS国密SSL通信证书和密钥文件在 大宝 CAhttps://www.DoubleCA.com 网站上免费申请
学习交流与商业授权
Android版本国密SSL协议密码套件的商业应用需要大宝CA的授权许可,有如下两种方式进行授权:
1. 离线授权,通过访问PP商业软件自主授权平台:https://www.PPLIC.com,在页面上进行人工授权
2. 在线授权,通过调用PP商业软件自主授权平台的网络授权服务API函数可自动获取Android终端的授权数据
库文件和示例代码的下载
Android平台通过HttpClient调用大宝CA国密SSL密码套件访问国密HTTPS安全服务示例代码的下载地址:https://download.csdn.net/download/upset_ming/12194460