基于TLS双向验证的java模拟FTPS的Server端和client端
一、首先实现加密的Ftp需要创建证书
1、利用jdk自带的keytools工具生成
- 为了实现消息认证。
- Server需要:
- 1)KeyStore: 其中保存服务端的私钥
- 2)Trust KeyStore:其中保存客户端的授权证书
- 同样,Client需要:
- 1)KeyStore:其中保存客户端的私钥
- 2)Trust KeyStore:其中保存服务端的授权证书
2、步骤
可以参照我另外一篇文章:KeyStore生成秘钥
1)生成服务端私钥,并且导入到服务端KeyStore文件中
keytool -genkey -alias serverkey -keyalg RSA -keystore E:\FTPConfig\SedTest\kserver.keystore
---过程中,分别需要填写,根据需求自己设置就行
这样 就可以生成kserver.keystore文件
server.keystore是给服务端用的,其中保存着自己的私钥
2)根据私钥,导出服务端证书
keytool -export -alias serverkey -keystore E:\FTPConfig\SedTest\kserver.keystore -file E:\FTPConfig\SedTest\server.crt
server.crt就是服务端的证书
3)将服务端证书,导入到客户端的Trust KeyStore中
keytool -import -alias serverkey -file E:\FTPConfig\SedTest\server.crt -keystore E:\FTPConfig\SedTest\tclient.keystore
tclient.keystore是给客户端用的,其中保存着受信任的证书
采用同样的方法,生成客户端的私钥,客户端的证书,并且导入到服务端的Trust KeyStore中
keytool -genkey -alias clientkey -keyalg RSA -keystore E:\FTPConfig\SedTest\kclient.keystore
keytool -export -alias clientkey -keystore E:\FTPConfig\SedTest\kclient.keystore -file E:\FTPConfig\SedTest\client.crt
keytool -import -alias clientkey -file E:\FTPConfig\SedTest\client.crt -keystore E:\FTPConfig\SedTest\tserver.keystore
如此一来,生成的文件分成两组
服务端保存:kserver.keystore tserver.keystore
客户端保存:kclient.keystore tclient.kyestore
二、下载Apache FTPServer (由于一直尝试,此步不确定是否为必须,后经验证不需要这一步的下载)
可以到官网下载: 官网下载ApacheServer
将下载下来的压缩包解压到本地
然后进入cmd窗口的管理员模式,注意是管理员模式,否则服务可能开启失败然后输入
service install ftpd.bat res/conf/ftpd-typical.xml
ftpd.bat res/conf/ftpd-typical.xml(这是启动ftpserver,如果代码实现,这一步不用执行)
下面附一套实验成功的Server和client
server端
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.ftplet.Authority;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.ftplet.UserManager;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.ssl.SslConfigurationFactory;
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.apache.ftpserver.usermanager.impl.WritePermission;
public class StartFTPS
{
/**
* 通过程序启动FTP with SSL认证,以Apache FTPServer为例
* @param args
* @throws FtpException
* @author ocean
*/
public static void main(String[] args) throws FtpException
{
// TODO Auto-generated method stub
FtpServerFactory serverFactory = new FtpServerFactory();
ListenerFactory factory = new ListenerFactory();
// set the port of the listener
factory.setPort(2121);
// define SSL configuration
SslConfigurationFactory ssl = new SslConfigurationFactory();
ssl.setKeystoreFile(new File("F:/apache-ftpserver-1.2.0-bin/apache-ftpserver-1.2.0/res/kserver.keystore"));
ssl.setKeystorePassword("123456");
ssl.setTruststoreFile(new File("F:/apache-ftpserver-1.2.0-bin/apache-ftpserver-1.2.0/res/tserver.keystore"));
ssl.setTruststorePassword("123456");
// set the SSL configuration for the listener
factory.setSslConfiguration(ssl.createSslConfiguration());
factory.setImplicitSsl(true);
// replace the default listener
serverFactory.addListener("default", factory.createListener());
PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
userManagerFactory.setFile(new File("F:/apache-ftpserver-1.2.0-bin/apache-ftpserver-1.2.0/res/conf/users.properties"));
BaseUser user = new BaseUser();
//设置用户名
user.setName("testuser");
//设置密码
user.setPassword("123456");
//设置已存在的目录为该用户的主目录
user.setHomeDirectory("F:\\FTPConfig\\FTP");
//用户权限信息
List<Authority> authorities = new ArrayList<Authority>();
//添加写的权限
authorities.add(new WritePermission());
user.setAuthorities(authorities);
UserManager userManager = userManagerFactory.createUserManager();
userManager.save(user);
serverFactory.setUserManager(userManager);
serverFactory.setUserManager(userManagerFactory.createUserManager());
// start the server
FtpServer server = serverFactory.createServer();
server.start();
}
}
client端
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.KeyStore;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPSClient;
public class ConnectFTPS
{
private static FTPSClient ftpsClient;
private static final String trust_path = "F:/apache-ftpserver-1.2.0-bin/apache-ftpserver-1.2.0/res/kclient.keystore";
private static final String trust_pw = "123456";
private static final String key_path = "F:/apache-ftpserver-1.2.0-bin/apache-ftpserver-1.2.0/res/tclient.keystore";
private static final String key_pw = "123456";
private static final String serverIP = "127.0.0.1";
private static final int serverPort = 2121;
private static final int defaultTimeout = 10000;
private static final int soTimeout = 900000;
private static final int dataTimeout = 5000;
/**
* 测试连接FTP With SSL,以Apache FTPServer为例
* @param args
* @throws Exception
* @author ocean
*/
public static void main(String[] args) throws Exception
{
// connect("passive");
FileInputStream fs = new FileInputStream("F:\\apache-ftpserver-1.2.0-bin\\apache-ftpserver-1.2.0\\res\\home\\README.txt");
System.out.println("storeFile: " + ftpsClient.storeFile("test_file", fs));
fs.close();
ftpsClient.disconnect();
}
/**
* 登陆FTP
* @param active
* @return
* @throws Exception
*/
private static boolean connect(String active) throws Exception
{
ftpsClient = new FTPSClient(true);
ftpsClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
ftpsClient.setKeyManager(getKeyManager());
// ftpsClient.setTrustManager(getTrustManager());
ftpsClient.setDefaultTimeout(defaultTimeout);
ftpsClient.connect(serverIP, serverPort);
System.out.println("connect FTP success");
ftpsClient.setSoTimeout(soTimeout);
ftpsClient.getReplyCode();
ftpsClient.execPBSZ(0);
ftpsClient.execPROT("P");
ftpsClient.login("testuser", "123456");
ftpsClient.changeWorkingDirectory("/");
ftpsClient.setDataTimeout(dataTimeout);
if (active.equalsIgnoreCase("active"))
{
ftpsClient.enterLocalActiveMode();
} else
{
ftpsClient.enterLocalPassiveMode();
}
return testLink();
}
/**
* 遍历FTP文件
* @return
*/
private static boolean testLink()
{
long t1 = System.currentTimeMillis();
try
{
System.out.println("hello1");
FTPFile[] listFiles = ftpsClient.listFiles();
System.out.println("listFiles()通过");
System.out.println("List file length:" + ftpsClient.listFiles().length);
} catch (IOException e)
{
System.out.println(e.getMessage());
long t2 = System.currentTimeMillis();
long t = (t2 - t1) / 1000;
System.out.println("t: " + t);
try
{
ftpsClient.disconnect();
} catch (IOException e1)
{
e1.printStackTrace();
}
return false;
}
return true;
}
private static KeyManager getKeyManager() throws Exception
{
KeyStore key_ks = KeyStore.getInstance("JKS");
key_ks.load(new FileInputStream(key_path), key_pw.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(key_ks, key_pw.toCharArray());
KeyManager[] km = kmf.getKeyManagers();
System.out.println("km len: " + km.length);
return km[0];
}
private static TrustManager getTrustManager() throws Exception
{
KeyStore trust_ks = KeyStore.getInstance("JKS");
trust_ks.load(new FileInputStream(trust_path), trust_pw.toCharArray());
TrustManagerFactory tf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tf.init(trust_ks);
TrustManager[] tm = tf.getTrustManagers();
System.out.println("tm len: " + tm.length);
return tm[0];
}
}