上文讲了netty如何使用openssl生成的签名证书进行加密通信,结果客户端告诉我他们用的netty版本没有SslContextBuilder类,并且由于一些PY交易的原因还不能更新netty....
SslContextBuilder没有java你总有吧,来吧。
一、老规矩,创建key
1.创建客户端和服务端的keystore文件
随便找个文件夹就行,打开命令行输入
keytool -genkey -alias sslserver -keystore sslserverkeys
keytool -genkey -alias sslclient -keystore sslclientkeys
2.将keystore导出证书格式
keytool -export -alias sslserver -keystore sslserverkeys -file sslserver.cer
keytool -export -alias sslclient -keystore sslclientkeys -file sslclient.cer
3.将客户端证书导入到服务器端信任的 keystore 里,将服务器端证书导入到客户端信任的 keystore 里。
keytool -import -alias sslclient -keystore sslservertrust -file sslclient.cer
keytool -import -alias sslserver -keystore sslclienttrust -file sslserver.cer
最后得到有用的文件分别为
服务端:sslserverkeys、sslservertrust
客户端:sslclientkeys、sslclienttrust
二、服务器端代码 (git)
服务器key工厂类 SecureChatSslContextFactory.java
public class SecureChatSslContextFactory {
private static final String PROTOCOL = "SSL";
private static final SSLContext SERVER_CONTEXT;
private static String SERVER_KEY_STORE = ".\\ssl\\sslserverkeys";
private static String SERVER_TRUST_KEY_STORE = ".\\ssl\\sslservertrust";
private static String SERVER_KEY_STORE_PASSWORD = "123123123";
private static String SERVER_TRUST_KEY_STORE_PASSWORD = "123123123";
static {
String algorithm = SystemPropertyUtil.get("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) {
algorithm = "SunX509";
}
SSLContext serverContext;
try {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(SERVER_KEY_STORE), SERVER_KEY_STORE_PASSWORD.toCharArray());
KeyStore tks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream(SERVER_TRUST_KEY_STORE), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
kmf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
tmf.init(tks);
serverContext = SSLContext.getInstance(PROTOCOL);
serverContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
} catch (Exception e) {
throw new Error(e);
}
SERVER_CONTEXT = serverContext;
}
public static SSLContext getServerContext() {
return SERVER_CONTEXT;
}
}
Main.java
public class Main {
private static final int m_port = 23333;
public void run() throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new Initializer());
System.out.println("启动了,端口:" + m_port);
ChannelFuture f = b.bind(m_port).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
System.out.println("关闭了");
}
}
public static void main(String[] args) throws Exception {
new Main().run();
}
}
Initializer.java
public class Initializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
engine.setUseClientMode(false);
engine.setNeedClientAuth(true);
pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new Handler());
}
}
Handler.java
public class Handler extends SimpleChannelInboundHandler<String> {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
ctx.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n");
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
Channel incoming = ctx.channel();
System.out.println("收到" + incoming.id() + "消息:" + s);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient:" + incoming.remoteAddress() + "在线");
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
ctx.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 离开\n");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
System.out.println(incoming.remoteAddress() + "掉线");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Channel incoming = ctx.channel();
System.out.println(incoming.remoteAddress() + "异常");
// 当出现异常就关闭连接
cause.printStackTrace();
ctx.close();
}
}
三、客户端代码(git)
SecureChatSslContextFactory.java
public class SecureChatSslContextFactory {
private static final String PROTOCOL = "SSL";
private static final SSLContext CLIENT_CONTEXT;
private static String CLIENT_KEY_STORE = ".\\ssl\\sslclientkeys";
private static String CLIENT_TRUST_KEY_STORE = ".\\ssl\\sslclienttrust";
private static String CLIENT_KEY_STORE_PASSWORD = "321321321";
private static String CLIENT_TRUST_KEY_STORE_PASSWORD = "321321321";
static {
String algorithm = SystemPropertyUtil.get("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) {
algorithm = "SunX509";
}
SSLContext clientContext;
try {
KeyStore ks2 = KeyStore.getInstance("JKS");
ks2.load(new FileInputStream(CLIENT_KEY_STORE), CLIENT_KEY_STORE_PASSWORD.toCharArray());
KeyStore tks2 = KeyStore.getInstance("JKS");
tks2.load(new FileInputStream(CLIENT_TRUST_KEY_STORE), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
KeyManagerFactory kmf2 = KeyManagerFactory.getInstance(algorithm);
TrustManagerFactory tmf2 = TrustManagerFactory.getInstance("SunX509");
kmf2.init(ks2, CLIENT_KEY_STORE_PASSWORD.toCharArray());
tmf2.init(tks2);
clientContext = SSLContext.getInstance(PROTOCOL);
clientContext.init(kmf2.getKeyManagers(), tmf2.getTrustManagers(), null);
} catch (Exception e) {
throw new Error(e);
}
CLIENT_CONTEXT = clientContext;
}
public static SSLContext getClientContext() {
return CLIENT_CONTEXT;
}
Main.java
public class Main {
private static String m_host = "127.0.0.1";
private static int m_prot = 23333;
public static void main(String[] args) throws Exception {
new Main().run();
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bt = new Bootstrap().group(group).channel(NioSocketChannel.class).handler(new Initializer());
Channel channel = bt.connect(m_host, m_prot).sync().channel();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (true) {
channel.writeAndFlush(in.readLine() + "\r\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}
Initializer.java
public class Initializer extends ChannelInitializer<SocketChannel>{
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
SSLEngine engine = SecureChatSslContextFactory.getClientContext().createSSLEngine();
engine.setUseClientMode(true);
pipeline.addLast("ssl", new SslHandler(engine));
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new Handler());
}
}
Handler.java
public class Handler extends SimpleChannelInboundHandler<String>{
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println("收到:" + s);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。