系统要求
Android 7.0(API 24)及以上
功能介绍
- 单向认证
- 接收并显示服务器端国密数字证书
- 使用PP软件授权平台获取授权数据的简要说明
核心代码
//这里写入子线程需要做的工作
try
{
DoubleCASSE dcsse = new DoubleCASSE();
Security.addProvider(new DoubleCA());
Security.addProvider(dcsse);
// 下面代码是获取授权请求编码的代码
// StringBuffer buffer = new StringBuffer();
// dcsse.generateLicRequest(buffer);
// System.out.printf(buffer.toString());
// 模拟器授权数据,每部手机的授权数据不同,请向大宝CA销售人员【QQ:1337588982】索取【国密SSL密码套件】的授权码或批量授权码
String licData = "AdZeAkVxs7NYwAABC1I9LrCu48kTTA8gL2/iGnR72qL2RK93B2nqoqCRyjELcFo\n" + "YZYyfG7mKh+XuKLjfXy+ptpcfp60eyHnrPfU+S9ZKPnRvto7xtkUah9EzJNq4iP\n" + "+VC/+p7A/aQ/+/selzXDDTx2+tALb505UyVddV1QMo5AjyE6kOrz9GYd47jip63\n" + "4qU+o9QqWXq/yw3HErftCXP/OJcYZdoMqoLVk8BziIdsmYVcEslDFMpKgy8bzHi\n" + "qvRXj+gn9ZoWhxJVhLqUOet8CnoVERtsMONXGm1NxgVqpsSg0DGAr1qxfI+70R/\n" + "OsXh4zWpb12yJm6e+Vs3K7UbCbii5nOqSfJwUguPB+8LwAJ7eXZvmmy41BjppEC\n" + "bWyIKKdh0+P/S0EJJJVVQtMhovv2L87OoOrZ4oyCh3LXe4pgVASkdXZoMg3p5wO\n" + "8a7Ngmkhf2ZS9ltu7X01DLk++DEitC6/qSEO32uoLMZjffoaitbNQmy018lWJWi\n" + "yt21hLcqYXoXq/hYJKaS7+hP+DMzumpem3MJRwbnCxYGL4Fi6E7ppOUNM5MqMtv\n" + "6skg93tjeUTQWK1FB5hh8Oc+fZ6kR39oAvV7qs6VxkKDKn5DmhRhXctQ9LhwiVj\n" + "g0ydU8SlVsFdll0zIxVqeByCcqdnhj7jCdLsJgZv4xile5wkujTw==";
dcsse.setLicData(licData);
Date endTime = dcsse.getLicEndTime();
String endTimeStr = endTime.toString();
// 密钥管理器
KeyStore sm2ClientKeyStore = KeyStore.getInstance("DCKS");
sm2ClientKeyStore.load(getAssets().open("CLIENT.dcks"), "DoubleCA".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509", DoubleCASSE.PROVIDER_NAME);
kmf.init(sm2ClientKeyStore, "DoubleCA".toCharArray());
// 信任管理器
KeyStore sm2TrustKeyStore = KeyStore.getInstance("DCKS");
sm2TrustKeyStore.load(getAssets().open("CLIENT.dcks"), "DoubleCA".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", DoubleCASSE.PROVIDER_NAME);
tmf.init(sm2TrustKeyStore);
// SSL上下文
SSLContext sslContext = SSLContext.getInstance("GMSSLv1.1", DoubleCASSE.PROVIDER_NAME);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocketFactory sslcntFactory = (SSLSocketFactory) sslContext.getSocketFactory();
//
outMess.setLength(0);
SSLSocket sslSocket = (SSLSocket)sslcntFactory.createSocket();
// 服务端IP地址:192.168.1.12,端口:80
// 服务端国密SSL密码套件库请在【大宝CA】网站下载
sslSocket.connect(new InetSocketAddress("192.168.1.12", 80), 1000);
sslSocket.startHandshake();
Certificate[] serverCerts = sslSocket.getSession().getPeerCertificates();
outMess.append("服务端身份信息: ");
for (int i = 0; i < serverCerts.length; i++)
{
outMess.append("\r\n" + ((X509Certificate)serverCerts[i]).getSubjectDN().getName());
}
String[] supported = sslSocket.getSupportedCipherSuites();
sslSocket.setEnabledCipherSuites(supported);
outMess.append("\r\n\r\n启用的加密套件: " + Arrays.asList(supported));
// 发送
InputStream in = sslSocket.getInputStream();// 输入流
OutputStream out = sslSocket.getOutputStream();
out.write("大宝CA 国密数字证书\r\n".getBytes());
out.flush();
out.write("Android 国密SSL解决方案\r\n".getBytes());
out.write(new byte[]{0});
out.flush();
byte[] buffer = new byte[1024];
int a = in.read(buffer);
// 循环检查是否有消息到达
outMess.append("\r\n\r\n来自于服务端信息: \r\n");
while (a > 0)
{
outMess.append(new String(buffer).trim());
// 接收到 0x00 数据后通信结束
if (buffer[a - 1] != 0)
{
buffer = new byte[1024];
a = in.read(buffer);
}
else
{
a = 0;
}
}
sslSocket.close();
textview.post(new Runnable()
{
@Override
public void run()
{
textview.setText(outMess.toString());
}
});
}
catch(Exception ex)
{
outMess.setLength(0);
outMess.append(ex.getLocalizedMessage());
textview.post(new Runnable()
{
@Override
public void run()
{
textview.setText(outMess.toString());
}
});
}
Android平台运行结果
国密数字证书
DCKS国密SSL通信证书和密钥文件在 大宝CA https://www.DoubleCA.com 网站上免费申请
学习交流与商业授权
Android版本国密SSL协议密码套件的商业应用需要大宝CA的授权许可,获取授权的具体步骤如下:
1. 访问PP商业软件自主授权平台:https://www.PPLIC.com
2. 在应用端注册应用端会员账户
3. 向大宝CA获取Android版本国密SSL协议密码套件的【批量授权码】
4. 使用应用端会员账户的【服务认证令牌】、【服务认证密钥】和【批量授权码】通过PP商业软件授权接口服务为Android移动终端获取授权数据
通过PP软件授权平台在线获取授权数据
PP商业软件授权接口服务的核心调用代码如下:
/**
*
* @param requestAddr 授权码服务地址:https://service.pplic.com/authorizationservice
* 批量授权码服务地址:https://service.pplic.com/batchauthorizationservice
* @param workToken 服务认证令牌,例:PPTOKEN-B7D2F1064BB634A9A245A6F655ABE919,需要在pplic.com应用端申请
* @param workKey 服务认证密钥,一组Base64编码数据,与服务认证令牌配套使用,需要在pplic.com应用端申请
* @param requestType 请求类型,"1":新申请授权数据,"2":找回授权数据
* @param licRequestCode 授权请求编码,一组Base64编码数据,在需要授权的终端设备上生成
* @param projectMap 需要申请授权数据的软件编号和(批量)授权码,Key:软件编号,Value:授权码或批量授权码,一一对应,授权码与批量授权码不能同时请求
* @return
*/
public Map<String, Object> requestLicense(String requestAddr, String workToken, String workKey, String requestType, String licRequestCode, Map<String, String> projectMap)
{
Map<String, Object> resultMap = new HashMap<String, Object>();
try
{
if (projectMap.size() < 1)
{
resultMap.put(MAP_KEY_RESULT_STATUS, RESULT_ERROR_PARAM);
resultMap.put(MAP_KEY_RESULT_ERRORDESC, "授权数据参数错误!");
return resultMap;
}
Map<String, Object> requestMap = new HashMap<String, Object>();
// 请求授权的项目数量
String projectnum = new Integer(projectMap.size()).toString();
requestMap.put("projectnum", projectnum);
// 服务认证令牌
requestMap.put("token", workToken);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timestamp = dateFormat.format(new Date());
// 时间戳
requestMap.put("timestamp", timestamp);
// 请求类型
requestMap.put("requesttype", requestType);
// 请求摘要值
requestMap.put("digest", doSHA256Digest(workToken, workKey, timestamp, projectnum, requestType));
// 需要授权的软件和授权码信息
requestMap.put("projectslic", projectMap);
// 终端授权请求编码
requestMap.put("clientinfo", licRequestCode);
ObjectMapper objectMapper = new ObjectMapper();
// 将请求转换为json编码
String jsonString = objectMapper.writeValueAsString(requestMap);
String jsonResult = doPost(requestAddr, jsonString);
Map<String, Object> responseMap = null;
if (jsonResult != null && jsonResult.length() > 0)
{
responseMap = objectMapper.readValue(jsonResult, Map.class);
}
if (responseMap == null)
{
throw new Exception("授权服务请求失败!");
}
String status = (String) responseMap.get(MAP_KEY_RESULT_STATUS);
if (RESULT_SUCCESS.equals(status))
{
// 服务授权成功
String licenseData = (String) responseMap.get("licenseBase64");
Map<String, Integer> licenseValidityDaysMap = (Map<String, Integer>) responseMap.get("licenseValidityDaysMap");
List<LicenseValidityDays> list = new ArrayList<LicenseValidityDays>();
for (Entry<String, Integer> entry : licenseValidityDaysMap.entrySet())
{
LicenseValidityDays obj = new LicenseValidityDays();
obj.setProjectSN(entry.getKey());
int validityHours = entry.getValue();
if (validityHours == 999999)
{
obj.setEndTime("永久授权");
}
else
{
Date nowTime = new Date();
Date endTime = new Date(nowTime.getTime() + validityHours * 60 * 60 * 1000L);
obj.setEndTime(new java.text.SimpleDateFormat("yyyy-MM-dd HH时").format(endTime));
}
list.add(obj);
}
resultMap.put("licenseBase64", licenseData);
resultMap.put("licenseValidityDaysList", list);
resultMap.put(MAP_KEY_RESULT_STATUS, RESULT_SUCCESS);
}
else
{
// 服务授权失败
resultMap.put(MAP_KEY_RESULT_STATUS, status);
String errorDesc = (String) responseMap.get(MAP_KEY_RESULT_ERRORDESC);
resultMap.put(MAP_KEY_RESULT_ERRORDESC, errorDesc);
}
}
catch(Exception ex)
{
resultMap.put(MAP_KEY_RESULT_STATUS, RESULT_ERROR_OTHER);
resultMap.put(MAP_KEY_RESULT_ERRORDESC, ex.getMessage());
ex.printStackTrace();
}
return resultMap;
}
private String doPost(String url, String json)
{
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5000).setConnectTimeout(5000).setSocketTimeout(5000).build();
HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig);
CloseableHttpClient client = builder.build();
HttpPost httpPost = new HttpPost(url);
String result = "";
CloseableHttpResponse response = null;
try
{
StringEntity s = new StringEntity(json);
s.setContentEncoding("UTF-8");
s.setContentType("application/json");// 发送json数据需要设置contentType
httpPost.setEntity(s);
response = client.execute(httpPost);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
{
HttpEntity entity = response.getEntity();
if (entity != null)
{
InputStream instream = entity.getContent();
byte[] buffer = readStream(instream);
if (buffer != null)
{
result = new String(buffer);
}
instream.close();
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
if (response != null)
{
try
{
response.close();
}
catch (Exception ex)
{
}
}
}
return result;
}
private byte[] readStream(InputStream inStream)
{
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
try
{
while ((len = inStream.read(buffer)) != -1)
{
outSteam.write(buffer, 0, len);
}
return outSteam.toByteArray();
}
catch (Exception ex)
{
return null;
}
finally
{
try
{
outSteam.close();
}
catch (Exception ex)
{
}
}
}
private String doSHA256Digest(String token, String key, String timestamp, String projectnum, String type) throws NoSuchAlgorithmException
{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update((token + key + timestamp + projectnum + type).getBytes());
return new String(Base64.getEncoder().encode(md.digest()));
}
库文件和示例代码的下载
Android版本国密SSL协议密码套件和示例代码下载地址:https://download.csdn.net/download/upset_ming/12194455