JSSE应用

来源:互联网 发布:为什么不禁止网络主播 编辑:程序博客网 时间:2024/05/16 05:47
数据在网络的传输是无所不在的,但是如果数据中包含了一些私有的信息,如:密码或信用卡号码,那么就要使数据对于那些未被授权的用户保密。同样,也要确信数据在传输过程中有没有被故意或无意更改。Secure Sockets Layer(SSL) 和Transport Layer Security(TLS)协议被用来保护数据在网络传输过程中的秘密性和完整性。 Java Secure Socket Extension(JSSE)能够保证网络的通信安全。它提供了一套框架和java版本的SSL和TLS协议的实现,也包括了广泛的功能,如:数据加密,服务器证明,消息完整性,以及可选的客户证明。使用JSSE,开发者能够提供一个基于任何协议之上(如: Hypertext Transfer Protocol(Http) , Telnet, or FTP, over TCP/IP)的客户和服务器的安全数据通道。 JSSE是基于安全算法和握手机制之上的合成体。JSSE将危险的安全弱点降到最低点,并且它减轻了开发者的负担,使得开发者可以很轻松的整合到程序中。 SSL(Secure Sockets Layer)是JSSE中的重要的部分。SSL是用的最广泛的实现网络的加密协议。SSL用一个密码处理来提供网络安全通信。SSL是基于标准的TCP/IP socket协议的安全增加用于网络通信,所以SSL是位于传输层和应用程序层之间。最普通的使用SSL的是HTTP(Hypertext Transfer Protocol),用于网络页面。其他的如: Net News Transfer Protocol (NNTP), Telnet, Lightweight Directory Access Protocol (LDAP), Interactive Message Access Protocol (IMAP), and File Transfer Protocol (FTP),也能够使用SSL。

TCP/IP Protocol Stack With SSL

TCP/IP Layer

Protocol

应用程序层

    HTTP, NNTP, Telnet, FTP, etc.

Secure Sockets Layer

    SSL

传输层

    TCP

网络层

    IP

SSL 是Netscape公司于1994年开发的。后来应用到因特网成了一个标准。 SSL提供一个高标准的在客户和服务器发送加密消息之前的SSL握手描述,如下图:

Sequence of messages exchanged in SSL handshake.

SSL消息按如下顺序发送: 1.Client Hello: 客户发送服务器信息,包括它所支持的密码组。密码组中有密码算法和钥匙大小; 2.Server Hello:服务器选择客户和服务器都支持的密码组到客户。 3.Certificate: 服务器发送一个证书或一个证书链到客户端,一个证书链开始于服务器公共钥匙证书并结束于证明权威的根证书。这个消息是可选的,但服务器证书需要时,必须使用它。 4.Certificate request:当服务器需要鉴别客户时,它发送一个证书请求到客户端。在网络程序中,这个消息很少发送。 5.Server key exchange:服务器当发送来的公共钥匙对钥匙交换不是很充分时,发送一个服务器钥匙交换消息。 6.Server hello done:服务器告诉客户完成它的初始化流通消息。 7.Certificate:假如服务器需要一个客户证书时,客户端发送一个证书链。(只有在服务器需要客户证书时) 8.Client key exchange:客户产生用于对称算法的一个钥匙。对RSA客户用服务器公共钥匙加密这个钥匙信息并把它送到服务器。 9.Certificate verify:在网络程序中,这个消息很少发送,它主要是用来允许服务器结束对客户的鉴别处理。当用这个消息时,客户发送用密码函数的数字签名的信息到服务端,当服务端用公共钥匙解密这个消息时,服务器能够鉴别客户。 10.Change cipher spec:客户发送一个消息告诉服务器改变加密模式。 11.Finished:客户告诉服务器它已准备安全数据通信。 12.Change cipher spec:服务器发送一个消息到客户端并告诉客户修改加密模式。 13.Finished:服务器告诉客户端它已准备好安全数据通信。这是client-server握手协议最后一步。 14.Encrypted data:客户同服务器用对称加密算法和密码函数,并用客户发送到服务器的秘密钥匙加密通信。 下面有一个例子可以简单的实现JSSE: 服务器端程序: import java.io.*; import java.net.*; import java.security.KeyStore; import javax.net.*; import javax.net.ssl.*; import javax.security.cert.X509Certificate;   //for a simple server public class ClassFileServer extends ClassServer {   private String docroot;   private static int DefaultServerPort = 2001;   public ClassFileServer(ServerSocket ss, String docroot) throws IOException { super(ss); this.docroot = docroot; }   public byte[] getBytes(String path) throws IOException { System.out.println("reading: " + path); File f = new File(docroot + File.separator + path); int length = (int)(f.length()); if (length == 0) { throw new IOException("File length is zero: " + path); } else { FileInputStream fin = new FileInputStream(f); DataInputStream in = new DataInputStream(fin);   byte[] bytecodes = new byte[length]; in.readFully(bytecodes); return bytecodes; } }   public static void main(String args[]) { System.out.println( "USAGE: java ClassFileServer port docroot [TLS [true]]"); System.out.println(""); System.out.println( "If the third argument is TLS, it will start as/n" + "a TLS/SSL file server, otherwise, it will be/n" + "an ordinary file server. /n" + "If the fourth argument is true,it will require/n" + "client authentication as well.");   int port = DefaultServerPort; String docroot = "";   if (args.length >= 1) { port = Integer.parseInt(args[0]); }   if (args.length >= 2) { docroot = args[1]; } String type = "PlainSocket"; if (args.length >= 3) { type = args[2]; } try { ServerSocketFactory ssf = ClassFileServer.getServerSocketFactory(type); ServerSocket ss = ssf.createServerSocket(port); if (args.length >= 4 && args[3].equals("true")) { ((SSLServerSocket)ss).setNeedClientAuth(true); } new ClassFileServer(ss, docroot); } catch (IOException e) { System.out.println("Unable to start ClassServer: " + e.getMessage()); e.printStackTrace(); } }   private static ServerSocketFactory getServerSocketFactory(String type) { if (type.equals("TLS")) { SSLServerSocketFactory ssf = null; try { // set up key manager to do server authentication SSLContext ctx; KeyManagerFactory kmf; KeyStore ks; char[] passphrase = "passphrase".toCharArray();   ctx = SSLContext.getInstance("TLS"); kmf = KeyManagerFactory.getInstance("SunX509");//加密算法. ks = KeyStore.getInstance("JKS");//钥匙存储名字.可以用keytool工具产生.   ks.load(new FileInputStream("testkeys"), passphrase);//存储钥匙文件. kmf.init(ks, passphrase); ctx.init(kmf.getKeyManagers(), null, null);   ssf = ctx.getServerSocketFactory(); return ssf; } catch (Exception e) { e.printStackTrace(); } } else { return ServerSocketFactory.getDefault(); } return null; } }   以及: import java.io.*; import java.net.*; import javax.net.*;   public abstract class ClassServer implements Runnable {   private ServerSocket server = null; protected ClassServer(ServerSocket ss) { server = ss; newListener(); }   public abstract byte[] getBytes(String path) throws IOException, FileNotFoundException;   public void run() { Socket socket;   // accept a connection try { socket = server.accept(); } catch (IOException e) { System.out.println("Class Server died: " + e.getMessage()); e.printStackTrace(); return; }   // create a new thread to accept the next connection newListener();   try { DataOutputStream out = new DataOutputStream(socket.getOutputStream()); try { // get path to class file from header BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); String path = getPath(in); // retrieve bytecodes byte[] bytecodes = getBytes(path); // send bytecodes in response (assumes HTTP/1.0 or later) try { out.writeBytes("HTTP/1.0 200 OK/r/n"); out.writeBytes("Content-Length: " + bytecodes.length + "/r/n"); out.writeBytes("Content-Type: text/html/r/n/r/n"); out.write(bytecodes); out.flush(); } catch (IOException ie) { ie.printStackTrace(); return; }   } catch (Exception e) { e.printStackTrace(); // write out error response out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "/r/n"); out.writeBytes("Content-Type: text/html/r/n/r/n"); out.flush(); }   } catch (IOException ex) { // eat exception (could log error to log file, but // write out to stdout for now). System.out.println("error writing response: " + ex.getMessage()); ex.printStackTrace();   } finally { try { socket.close(); }catch (IOException e) { } } }   private void newListener() { (new Thread(this)).start(); }   private static String getPath(BufferedReader in) throws IOException { String line = in.readLine(); System.out.println("line ==============="+line); String path = ""; // extract class from GET line if (line.startsWith("GET /")) { line = line.substring(5, line.length()-1).trim(); int index = line.indexOf(' '); if (index != -1) { path = line.substring(0, index); } }   // eat the rest of header do { line = in.readLine(); } while ((line.length() != 0) && (line.charAt(0) != '/r') && (line.charAt(0) != '/n'));   if (path.length() != 0) { return path; } else { throw new IOException("Malformed Header"); } } }   这个服务器程序默认的端口号是:2001,你可以将服务器根目录设在任何目录,如启动服务器用: java ClassFileServer 2001(端口号) D:/j2sdk14/j2sdk-1_4_0-doc/docs/guide/security/jsse/samples(根目录) tls(安全通信)   为了证明client –server的安全通信,可以写一个client 程序,如下: import java.net.*; import java.io.*; import javax.net.ssl.*;   public class SSLSocketClient {   public static void main(String[] args) throws Exception { try { SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); SSLSocket socket = (SSLSocket)factory.createSocket("localhost", 2001);   socket.startHandshake(); PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream())));   out.println("GET http://localhost:2001/index.html HTTP/1.1"); out.println(); out.flush();   /* * Make sure there were no surprises */ if (out.checkError()) System.out.println( "SSLSocketClient: java.io.PrintWriter error");   /* read response */ BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream()));   String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine);   in.close(); out.close(); socket.close();   } catch (Exception e) { e.printStackTrace(); } } } 我们可以运行: java SSLSocketClient ,由于加密跟解密是非常耗时的,也许比较慢一点。 在这个测试程序中,我们用的算法是: SunX509,钥匙是JKS(可以用 keytool工具添加及修改),储存钥匙的文件是:testkeys(可以从jdk14 文档资料中找到)。运行这个文件还必须要有一个证书文件samplecacerts(也可以在jdk14 文档资料中找到),并替换 /lib/security/cacerts,或者加上一个参数: Djavax.net.ssl.trustStore=path_to_samplecacerts_file. Java的安全性是非常完善的,微软的。net安全性都或多或少借鉴了java的功能。而JSSE在网络上安全传输秘密信息是非常有用的。  

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1907448


原创粉丝点击