Java SSL Socket:keytool工具与安全Socket通信

xiaoxiao2021-02-27  391

  Java安全Socket扩展(JSSE)可以使用安全Socket层(SSL)版本3和传输层安全(TLS)协议及相关算法来保护网络通信的安全。SSL可以提供各级机密和认证功能,前者依靠密钥,后者依靠证书。同普通Socket类似,SSLSocket对象构建客户端安全套接字流程,而SSLServerSocket对象构建服务端安全套接字流程,用户调用两者的通信接口同普通Socket大体一致;与普通Socket不同的是,SSL**需要控制身份认证和加密行为,但是做法很简单,配置支持的密码组(CipherSuites)即可。   下面首先介绍使用Java工具keytool生成公钥和证书的方法: 1. 生成服务端私钥server.keys keytool -genkey -alias serverkey -keystore server.keys 2. 从服务端私钥导出服务端证书server.crt keytool -export -alias serverkey -keystore server.keys -file server.crt 3. 将服务端证书导入到客户端KeyStore,即client.keys keytool -import -alias serverkey -file server.crt -keystore client.keys


  以上利用keytool只生成了服务端的证书和密钥,这和大多数web服务一致,仅需要单方面认证身份即可,往往服务端需要向客户端证明自身身份,客户端并不需要。现在客户端利用client.keys来对服务端进行身份验证和数据加/解密,服务端利用server.keys来对数据加/解密。下面提供SSL通信服务端和客户端的示例代码:

SSLServer.java,SSL服务端: import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import java.io.*; import java.net.Socket; import java.security.*; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; /** * Created by Cheney Hwang on 2017/5/2. * SSLServerSocketFactory.getDefault()返回的工厂只支持服务器验证而不支持加密 * 使用SSLContext来对其弥补 */ public class SSLServer { public final static int PORT=5555; public final static String PROTOCOL="ssl"; public static void main(String[] args){ try { //用指定的协议创建SSL上下文(有SSL和TLS协议) SSLContext context = SSLContext.getInstance(PROTOCOL); //管理x.509密钥 KeyManagerFactory kmf=KeyManagerFactory.getInstance("Sunx509"); //JKS密钥库 KeyStore ks=KeyStore.getInstance("JKS"); //密钥文件加密口令,server.keys的口令是Hc19920210 char[] passwd="Hc19920210".toCharArray(); ks.load(new FileInputStream("server.keys"),passwd); //授权管理密钥 kmf.init(ks,passwd); //初始化上下文 context.init(kmf.getKeyManagers(),null,null); //下面创建的工厂支持服务器验证和加密 SSLServerSocketFactory factory=context.getServerSocketFactory(); SSLServerSocket server=(SSLServerSocket)factory.createServerSocket(PORT); String[] supported=server.getSupportedCipherSuites(); List<String> anonSupported=new ArrayList<>(); //获取所有匿名(非验证)密码组 for(String elem:supported){ if(elem.indexOf("_anon_")>0){ anonSupported.add(elem); } } String[] oldEnabled=server.getEnabledCipherSuites(); String[] newEnabled=new String[oldEnabled.length+anonSupported.size()]; System.arraycopy(oldEnabled,0,newEnabled,0,oldEnabled.length); int index=oldEnabled.length; for(String elem:anonSupported){ newEnabled[index++]=elem; } //允许匿名和加密身份认证,JDK1.7默认只支持加密认证密码组,此处打开包括匿名认证密码组 server.setEnabledCipherSuites(newEnabled); while(true){ try(Socket client=server.accept()){ Writer out=new OutputStreamWriter(client.getOutputStream()); Date now=new Date(); out.write(now.toString()+"\r\n"); out.flush(); out.close(); }catch (IOException e){ e.printStackTrace(); } } }catch (IOException|KeyManagementException|KeyStoreException |NoSuchAlgorithmException|CertificateException |UnrecoverableEntryException ex){ ex.printStackTrace(); } } } SSLClient.java,SSL客户端: import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; /** * Created by Cheney Hwang on 2017/5/2. */ public class SSLClient { public final static int PORT = 5555; public final static String HOST = "localhost"; public static void main(String[] args) { System.setProperty("javax.net.ssl.trustStore", "client.keys"); System.setProperty("javax.net.ssl.trustStorePassword", "Hc19920210"); SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); try (SSLSocket socket = (SSLSocket) factory.createSocket(HOST, PORT)) { //启用所有密码组 String[] supported = socket.getSupportedCipherSuites(); socket.setEnabledCipherSuites(supported); Reader in = new InputStreamReader(socket.getInputStream()); int c; while ((c = in.read()) != -1) { System.out.write((char) c); } in.close(); } catch (IOException ex) { ex.printStackTrace(); } } }

  JDK1.7默认只启用所有加密认证密码组。以上SSL服务端启用了匿名(无需身份验证)密码组,SSL客户端启用了所有密码组。

转载请注明原文地址: https://www.6miu.com/read-846.html

最新回复(0)