国密SSL协议的Android JSSE实现 大宝CA Android版本 国密SSL身份识别与双向认证

系统要求
Android 7.0(API 24)及以上 


功能介绍

  1. 单向认证
  2. 接收并显示服务器端国密数字证书
  3. 使用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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值