android使用ssl与服务端进行通信

前言:

SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。
而默认情况下,java利用的是TLS和JKS密库,而android则使用规定的BKS密库。

1.生成服务端JKS秘钥与证书指令

  • keytool -genkey -keystore server.jks -storepass 密码 -keyalg RSA -keypass 密码

    服务器导出证书server.crt

  • keytool -exportcert -keystore server.jks -storepass 密码 -file server.crt

2.生成客户端BKS秘钥与证书
在这之前,因为Android 要求要BC证书,而Java的keytool本身不提供BKS格式,因此要自己手动配置。

2.1需要到Bouncy Castle的官网去下载对应JDK的包
http://www.bouncycastle.org/latest_releases.html
我这里用的是bcprov-jdk15on-146.jar。

2.2配置bcprov
把下载的bcprov包放到jdk_home\jre\lib\ext目录下
在 jdk_home\jre\lib\security\目录中找到 java.security 在内容增加一行(数字可以自己定义)
security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider
客户端指令:

  • keytool -genkey -keystore client.bks -storepass 密码 -keyalg RSA -keypass 密码 -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
  • keytool -exportcert -keystore client.bks -storepass 密码 -storetype BKS -file client.crt -provider org.bouncycastle.jce.provider.BouncyCastleProvider

最后把各自证书导入到信任库

  1. keytool -import -keystore tserver.bks -storetype BKS -storepass 密码 -file server.crt
  2. keytool -import -keystore tclient.jks -storetype JKS -storepass 密码 -file client.crt

最后服务端文件:server.jks、tclient.jks、server.crt
客户端文件:client.bks、tserver.bks、client.crt

3.服务端代码:
在所在项目下新增目录存放证书文件:例如cert

private static final String TLS = "SSL";
private static final String PROVIDER = "SunX509";
private static final String STORE_TYPE = "JKS";
private static final String KEY_STORE_NAME = ".cert/server.jks";
private static final String TRUST_STORE_NAME = "./cert/tclient.jks";
private static final int DEFAULT_PORT     = 234; //自定义端口
private static final String SERVER_KEY_STORE_PASSWORD  = "server"; //密码
private static final String SERVER_TRUST_KEY_STORE_PASSWORD = "server";//密码
private SSLServerSocket  serverSocket;

public void start() {
	if (serverSocket == null) {
		System.out.println("ERROR");
		return;
	}
	while (true) {
		try {
			SSLSocket s = (SSLSocket) serverSocket.accept();
			Accepter accepter = new Accepter(s);
			accepter.service();				
		} catch (Exception e) {
			System.out.println(e);
		}
	}
}

public void init() {
	try {
		SSLContext ctx = SSLContext.getInstance("SSL");
		KeyManagerFactory kmf = KeyManagerFactory.getInstance(PROVIDER);
		TrustManagerFactory tmf = TrustManagerFactory.getInstance(PROVIDER);
		KeyStore ks = KeyStore.getInstance(STORE_TYPE);
		KeyStore tks = KeyStore.getInstance(STORE_TYPE);
		ks.load(new FileInputStream(KEY_STORE_NAME), SERVER_KEY_STORE_PASSWORD.toCharArray());
		tks.load(new FileInputStream(TRUST_STORE_NAME), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());
		kmf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
		tmf.init(tks);
		ctx.init(kmf.getKeyManagers(),tmf.getTrustManagers(), null);
		serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(DEFAULT_PORT);
		serverSocket.setNeedClientAuth(true);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

private class Accepter implements Runnable{

	private SSLSocket socket;
	private InputStream input;
	private OutputStream output;
	private DataInputStream bis;
	private DataOutputStream bos;
	private BufferedReader reader;
	
	public Accepter(SSLSocket s) {
		this.socket = s;
	}

	public void service() {
		Thread thread = new Thread(this);
		thread.start();
	}

	
	@Override
	public void run() {
		try {
			input = socket.getInputStream();
			output = socket.getOutputStream();
			bis = new DataInputStream(input);
			bos = new DataOutputStream(output);
			String str = bis.readUTF();
			System.out.println("服务端收到的信息:"+str);
			bos.writeUTF(msg);
			bis.close();
			bos.close();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			if(socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}else {
				System.out.println("服务端关闭");
			}
		} 

	}
		
	}

客户端(android)代码:
SslClient:

public class SslClient{
private static final String CHARSET = “UTF-8”;
private static final String TLS = “SSL”;
private static final String PROVIDER = “X509”;
private static final String STORE_TYPE = “BKS”;
private static final char[] KEY_STORE_PASS = “server”.toCharArray();
private static final char[] TRUST_STORE_PASS = “server”.toCharArray();
private SSLSocketFactory socketFactory = null;
private SSLSocket socket = null;
private static String ip = “”;
private static int port = 0;
private boolean isStar = false;
private SSLContext context;
public SslClient(String i,int p){
this.ip = i;
this.port = p;
}

public boolean isConnect() {
    return (socket != null && socket.isBound() && !socket.isClosed() && socket.isConnected());
}

public boolean inTransmitting() {
    return (isConnect() && !socket.isInputShutdown() && !socket.isOutputShutdown());
}

public void close() throws IOException {
    if(isStar)
        return;

    if(inTransmitting()) {
        socket.close();
    }
    if(socketFactory != null) {
        socketFactory = null;
    }
}

public Boolean init() {
    try {
        connect();
    } catch (UnrecoverableKeyException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException
            | CertificateException | IOException e) {
        e.printStackTrace();
        return false;
    }
    return true;
}

public void connect() throws NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException {

    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(PROVIDER);
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(PROVIDER);

    KeyStore keyStore = KeyStore.getInstance(STORE_TYPE);
    KeyStore trustStore = KeyStore.getInstance(STORE_TYPE);

    keyStore.load(getBaseContext().getResources().openRawResource(R.raw.client), KEY_STORE_PASS);
    trustStore.load(getBaseContext().getResources().openRawResource(R.raw.tserver), TRUST_STORE_PASS);

    keyManagerFactory.init(keyStore, KEY_STORE_PASS);
    trustManagerFactory.init(trustStore);

    context = SSLContext.getInstance(TLS);
    context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
    socketFactory = context.getSocketFactory();
    socket = (SSLSocket)socketFactory.createSocket(ip, port);
}
}

证书文件:client.bks、tserver.bks
存放在android目录/res/raw下(raw文件夹为我新增的)

你可能感兴趣的:(android使用ssl与服务端进行通信)