国密SSL系列之Java编程

1 背景

     Java自身通过JCE和JSSE支持标准的SSL协议,但并不支持国密SSL协议。本文描述了Java使用国密JCE和国密JSSE开发一个简单的客户端程序,连接国密Web网站,发送HTTP请求,并接收HTTP应答。

2 环境

JRE是jre8。

国密JCE和国密JSSE。下载参https://www.gmssl.cn/gmssl/index.jsp?go=gmsdk

gmjce.jar和gmjsse.jar放到jre的lib/ext/目录下

3 源码

package cn.gmssl.test;

 

import java.net.*;

import java.io.*;

import java.security.*;

import java.security.cert.*;

 

import javax.net.*;

import javax.net.ssl.*;

 

public class SocketGet

{

    public static void main(String[] args)

    {

        SocketFactory fact = null;

        SSLSocket socket = null;

       

        String addr"ebssec.boc.cn";

        int port = 443;

        String uri = "/";

 

        try

        {

            if(args.length > 0)

            {

               addr = args[0];

               port = Integer.parseInt(args[1]);

               uri = args[2];

            }

           

            System.out.println("\r\naddr="+addr);

            System.out.println("port="+port);

            System.out.println("uri="+uri);

           

            // 加载国密提供者

           Security.insertProviderAt(new cn.gmssl.jce.provider.GMJCE(), 1);

           Security.insertProviderAt(new cn.gmssl.jsse.provider.GMJSSE(), 2);

 

           fact = createSocketFactory(null, null);

            socket = (SSLSocket)fact.createSocket();

            socket.setTcpNoDelay(true);

 

            System.out.println("\r\nGM SSL connecting...");

            socket.connect(new InetSocketAddress(addr, port), 5000);

            socket.setTcpNoDelay(true);

            socket.startHandshake();

 

            System.out.println("Connected!\n");

 

            DataInputStream in = new DataInputStream(socket.getInputStream());

            OutputStream out = socket.getOutputStream();

           

            String s = "GET " + uri + " HTTP/1.1\r\n";

            s+= "Accept: */*\r\n";

            s+= "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)\r\n";

            s+= "Host: " + addr + (port == 443 ? "" : ":"+port) + "\r\n";

            s+= "Connection: Close\r\n";

            s+= "\r\n";

            out.write(s.getBytes());

            out.flush();

 

            // 读取HTTP

            while(true)

            {

               byte[] lineBuffer = ReadLine.read(in);

               if ( lineBuffer == null || lineBuffer.length == 0)

               {

                   System.out.println();

                   break;

               }

               String line = new String(lineBuffer);

               System.out.println(line);

            }

 

           // 读取HTTP内容

           {

                byte[] buf = new byte[1024];

                while(true)

                {

                     int len = in.read(buf);

                     if(len == -1)

                     {

                        break;

                     }

                    System.out.println(new String(buf,  0,  len));

                }

           }

 

            in.close();

            out.close();

        }

        catch(Exception e)

        {

            e.printStackTrace();

        }

        finally

        {

            try

            {

                socket.close();

            }

            catch(Exception e)

            {}

        }

    }

 

    private static SSLSocketFactory createSocketFactory(KeyStore kepair, char[] pwd) throws Exception

   {

        X509TrustManager[] trust = { new MyTrustAllManager() };

 

        KeyManager[] kms = null;

        if (kepair != null)

        {

           KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");

           kmf.init(kepair, pwd);

           kms = kmf.getKeyManagers();

        }

 

        // 使用国密SSL

        SSLContext ctx = SSLContext.getInstance(cn.gmssl.jsse.provider.GMJSSE.GMSSLv11, cn.gmssl.jsse.provider.GMJSSE.NAME);

 

        java.security.SecureRandom secureRandom = new java.security.SecureRandom();

        ctx.init(kms, trust, secureRandom);

       

        SSLSocketFactory factory = ctx.getSocketFactory();

        return factory;

   }

}

 

class MyTrustAllManager implements X509TrustManager

{

   private X509Certificate[] issuers;

 

   public MyTrustAllManager()

   {

       this.issuers = new X509Certificate[0];

   }

 

   public X509Certificate[] getAcceptedIssuers()

   {

       return issuers ;

   }

 

   public void checkClientTrusted(X509Certificate[] chain, String authType)

   {}

 

   public void checkServerTrusted(X509Certificate[] chain, String authType)

   {}

}

 

class ReadLine

{

    public static final byte[] CRLF = {'\r', '\n'};

    public static final byte CR = '\r';

    public static final byte LF = '\n';

 

    private static final int LINE_MAX_SIZE = 16384;

 

    public static byte[] read(DataInputStream in) throws IOException, SocketException

    {

        ByteArrayOutputStream baosnew ByteArrayOutputStream();

        DataOutputStream s = new DataOutputStream(baos);

        boolean previousIsCR = false;

 

        int len = 0;

        byte b = 0;

 

        try

        {

            b = in.readByte();

            len ++;

        }

        catch(EOFException e)

        {

            return new byte[0];

        }

 

        while(true)

        {

            if(b == LF)

            {

                if(previousIsCR)

                {

                    s.flush();

                    byte[] rs = baos.toByteArray();

                    s.close();

                    return rs;

                }

                else

                {

                    s.flush();

                    byte[] rs = baos.toByteArray();

                    s.close();

                    return rs;

                }

            }

            else if(b == CR)

            {

                if(previousIsCR)

                {

                    s.writeByte(CR);

                }

                previousIsCR = true;

            }

            else

            {

                if(previousIsCR)

                {

                    s.writeByte(CR);

                }

                previousIsCR = false;

                s.write(b);

            }

 

            if(len > LINE_MAX_SIZE)

            {

            s.close();

                throw new IOException("Reach line size limit");

            }

 

            try

            {

                b = in.readByte();

                len ++;

            }

            catch(EOFException e)

            {

                s.flush();

                byte[] rs = baos.toByteArray();

                s.close();

                return rs;

            }

        }

    }

}

4 注释

首先要注册国密提供者

    Security.insertProviderAt(new cn.gmssl.jce.provider.GMJCE(), 1);

           Security.insertProviderAt(new cn.gmssl.jsse.provider.GMJSSE(), 2);

其中要使用国密SSL来连接

        SSLContext ctx = SSLContext.getInstance(cn.gmssl.jsse.provider.GMJSSE.GMSSLv11, cn.gmssl.jsse.provider.GMJSSE.NAME);

是不是比想象中要简单?

5 测试运行

java cn.gmssl.test.SocketGet

 

addr=ebssec.boc.cn

port=443

uri=/

 

GM SSL connecting...

Connected!

 

HTTP/1.1 200 OK

Date: Mon, 24 Aug 2020 03:45:28 GMT

Last-Modified: Sat, 27 Jun 2015 16:48:38 GMT

Accept-Ranges: bytes

Content-Length: 156

Cache-Control: max-age=300

Expires: Mon, 24 Aug 2020 03:50:28 GMT

Vary: Accept-Encoding,User-Agent

Connection: close

Content-Type: text/html

 

<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0;url=/boc15/login.html"><meta name="renderer" content="ie-stand"></head><body></body></html>

8 小结

     通过使用国密JCE和国密JSSE,Java很容易编程来使用国密SSL连接国密Web网站。www.gmssl.cn提供了全部免费的测试组件,并且支持双向国密SSL,可供学习和测试。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值