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

news/2024/10/30 23:16:57/

系统要求
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


http://www.ppmy.cn/news/332831.html

相关文章

pos密事(续2)

紧接上文&#xff0c;本篇简述mac值的计算以及PIN(个人工作秘钥)的加密以及转加密。 信息&#xff1a;就用上文算出来的PIN和PAK PIN秘钥明文 B42C67015B2FA5B85135D170A2ECC4E5 PAK秘钥明文 7C8B366BD1C56183655F8D3529A2117B3.MAC密钥的计算(国密和国际) 数据 0200602406C0…

分析网站登录处的加密算法(二)

前言&#xff1a;在渗透测试过程中&#xff0c;我们经常会碰到登录处用js加密字段的情况。在大多数情况下&#xff0c;看到这种加密方式&#xff0c;我们都会放弃对该登录处进行暴力破解。本文主要讲解对js加密进行绕过&#xff0c;以达到爆破或绕反爬的目的&#xff01; 对登录…

加密算法整理(哈希SHA, 奇偶校验, DES, 3DES, 3DES 分散, MAC, RSA, SM2) 持续更新

现有加密算法&#xff1a; 对称算法&#xff1a;DES / 3DES / SM4 / AES / SSF33 / RCX 非对称算法&#xff1a; RSA / SM2 / ECC / DSA / DH 信息摘要算法&#xff1a; SHA1 / SM3 / MD4 / MD5 / SHA256 目前银联规范银行卡中使用的安全加密算法分为两种&#xff1a;国际算…

Sm-DOTA DOTA修饰稀土钐 Sm-DTPA二亚乙基三胺五乙酸修饰稀土钐

Sm-DOTA DOTA修饰稀土钐 Sm-DTPA二亚乙基三胺五乙酸修饰稀土钐 镧系元素&#xff08;有时称为稀土元素&#xff09;是元素周期表中从原子序数57&#xff08;镧&#xff09;到71的14个“ f嵌段”元素的集合。其中&#xff0c;euro&#xff08;Eu&#xff09;&#xff0c;&#x…

国密算法 SM2 公钥加密 非对称加密 数字签名 密钥协商 python实现完整代码

SM2算法是国家密码管理局于2010年12月颁布的中国商用公钥密码标准算法。SM2基于椭圆曲线离散对数问题&#xff0c;计算复杂度是指数级&#xff08;暂未发现亚指数级或多项式级的计算方法&#xff09;&#xff0c;相较于广泛应用的RSA公钥密码算法&#xff0c;在同等安全程度要求…

sm2多端加密解密,java,js,android,ios实战

SM2非对称加密 公钥 04xxxxxxxxxxxxxxxxxxxx&#xff0c;私钥 276xxxx原文&#xff1a;你哦哈1232154 3654 {} &#xff0c;俺可接受不符点 公钥私钥是我后台自己生成的&#xff0c; java代码实现 pom.xml <dependency><groupId>org.bouncycastle</group…

加密方式之SM2

有一项需求&#xff0c;为了相对保证安全&#xff0c;需要敏感字符添加加密国密方式&#xff0c;于是想到了SM2&#xff0c;话不多说&#xff0c;上代码。 一、前端js代码。 开始也是找了好久的m2的前端js加密方式&#xff0c;很少&#xff0c;这里找到一个大哥的&#xff0c…

sm2

sm2加密&#xff1a; (function (global, undefined) {"use strict";var SM2CipherMode {C1C2C3: "0",C1C3C2: "1"};var CryptoJS CryptoJS || function (a, b) {var c {}, d c.lib {}, e d.Base function () {function a() { }return {e…