上一篇《OpenSSL与KeyStore指令小集》里面说到,最近研究SSL加密,会给出一个Java的小示例。复制一份可以运行的代码到生产上是非常不负责任的行为,不过小示例可以带我们入门,快速看清事物的本质。罗马不是一天建成的。
本文将给出一个Java SSL Socket的小例子,包括了Server和Client。希望大家上手之后,要多去研究相关的资料,理解基础概念。Java的优点是封装得比较彻底,需要介入的地方比较少,缺点是随着Java版本的升级和发展,会有很多新的概念和类涌出来,都要搞清楚要费不少力,另外代码量也比较大(生产级别的代码)。
具体代码
从最简单来说,Java里面只需要配置几个系统属性,创建及调用几个SSL相关的对象即可。这四个属性分别是:
- javax.net.ssl.keyStore
本方的密码,证书等存放地点(KeyStore文件地址)。 - javax.net.ssl.keyStorePassword
KeyStore的密码。没有密码可以不填。 - javax.net.ssl.trustStore
受信任证书的存放地点(TrustKeyStore文件地址)。 - javax.net.ssl.trustStorePassword
TrustKeyStore的密码。没有密码可以不填。
KeyStore类型默认是JKS类型的,不是的话,还需要设置 javax.net.ssl.keyStoreType和javax.net.ssl.trustStoreType。
Server端代码
每一次收新的连接,都新开一个线程接待。生产上请用线程池等技术。更推荐用Netty或Mina等框架处理。
- public class SslServer {
- public static void main(String[] args) throws Exception {
- System.setProperty("javax.net.debug", "ssl,handshake");
- System.setProperty("javax.net.ssl.keyStore", "./cfg/server.jks");
- System.setProperty("javax.net.ssl.keyStorePassword", "123456");
- System.setProperty("javax.net.ssl.trustStore", "./cfg/clienttrust.jks");
- System.setProperty("javax.net.ssl.trustStorePassword", "123456");
- SSLServerSocketFactory serverSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory
- .getDefault();
- SSLServerSocket serverSocket = (SSLServerSocket) serverSocketFactory
- .createServerSocket(9100);
- // 要求客户端身份验证
- serverSocket.setNeedClientAuth(true);
- while (true) {
- SSLSocket socket = (SSLSocket) serverSocket.accept();
- Accepter accepter = new Accepter(socket);
- accepter.service();
- }
- }
- static class Accepter implements Runnable {
- private SSLSocket socket;
- public Accepter(SSLSocket socket) {
- this.socket = socket;
- }
- public void service() {
- Thread thread = new Thread(this);
- thread.start();
- }
- @Override
- public void run() {
- try {
- InputStream inputStream = socket.getInputStream();
- InputStreamReader inputstreamreader = new InputStreamReader(
- inputStream);
- BufferedReader bufferedreader = new BufferedReader(
- inputstreamreader);
- String string = null;
- while ((string = bufferedreader.readLine()) != null) {
- System.out.println(string);
- System.out.flush();
- }
- } catch (Exception e) {
- // replace with other code
- e.printStackTrace();
- }
- }
- }
- }
public class SslServer {
public static void main(String[] args) throws Exception {
System.setProperty("javax.net.debug", "ssl,handshake");
System.setProperty("javax.net.ssl.keyStore", "./cfg/server.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "123456");
System.setProperty("javax.net.ssl.trustStore", "./cfg/clienttrust.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
SSLServerSocketFactory serverSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory
.getDefault();
SSLServerSocket serverSocket = (SSLServerSocket) serverSocketFactory
.createServerSocket(9100);
// 要求客户端身份验证
serverSocket.setNeedClientAuth(true);
while (true) {
SSLSocket socket = (SSLSocket) serverSocket.accept();
Accepter accepter = new Accepter(socket);
accepter.service();
}
}
static class Accepter implements Runnable {
private SSLSocket socket;
public Accepter(SSLSocket socket) {
this.socket = socket;
}
public void service() {
Thread thread = new Thread(this);
thread.start();
}
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(
inputStream);
BufferedReader bufferedreader = new BufferedReader(
inputstreamreader);
String string = null;
while ((string = bufferedreader.readLine()) != null) {
System.out.println(string);
System.out.flush();
}
} catch (Exception e) {
// replace with other code
e.printStackTrace();
}
}
}
}
Client代码
建立连接,并发一个消息给Server。很简单。记得换行符以及调用flush方法。
- public class SslClient {
- public static void main(String[] args) throws Exception {
- System.setProperty("javax.net.debug", "ssl,handshake");
- System.setProperty("javax.net.ssl.keyStore", "./cfg/client.jks");
- System.setProperty("javax.net.ssl.keyStorePassword", "123456");
- System.setProperty("javax.net.ssl.trustStore", "./cfg/servertrust.jks");
- System.setProperty("javax.net.ssl.trustStorePassword", "123456");
- SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory
- .getDefault();
- SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(
- "127.0.0.1", 9100);
- OutputStream outputStream = sslsocket.getOutputStream();
- BufferedWriter bufferedWriter = new BufferedWriter(
- new OutputStreamWriter(outputStream));
- bufferedWriter.write("沉睡的雄狮\n");
- bufferedWriter.flush();
- TimeUnit.SECONDS.sleep(2000);
- }
- }
public class SslClient {
public static void main(String[] args) throws Exception {
System.setProperty("javax.net.debug", "ssl,handshake");
System.setProperty("javax.net.ssl.keyStore", "./cfg/client.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "123456");
System.setProperty("javax.net.ssl.trustStore", "./cfg/servertrust.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory
.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(
"127.0.0.1", 9100);
OutputStream outputStream = sslsocket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(
new OutputStreamWriter(outputStream));
bufferedWriter.write("沉睡的雄狮\n");
bufferedWriter.flush();
TimeUnit.SECONDS.sleep(2000);
}
}
结束语
JDK后来加了SSLEngine这个类,具有异步通讯的能力。不过看官方文档,给出的代码很长。还是那句话,有条件的推荐用Netty或者Mina来处理通讯的问题,应该会比自己写的性能好一些。
原文地址:http://blog.csdn.net/kimylrong/article/details/43603815