Qt&Java笔记-Qt与Java进行SSL双向认证(Qt客户端,Java服务端)
Posted IT1995
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt&Java笔记-Qt与Java进行SSL双向认证(Qt客户端,Java服务端)相关的知识,希望对你有一定的参考价值。
这里使用Java作为服务端,使用Qt作为客户端。
程序运行截图如下:
这里的证书Qt使用的p12,Java使用的jks,看以前的博文生成。
源码打包下载地址:
https://github.com/fengfanchen/Java/tree/master/Ssl_QtClient_JavaServer
Qt客户端源码:
源码如下:
QSSLClient.h
#ifndef QSSLCLIENT_H
#define QSSLCLIENT_H
#include <QObject>
#include <QSslError>
QT_BEGIN_NAMESPACE
class QSslCertificate;
class QSslKey;
class QSslSocket;
QT_END_NAMESPACE
class QSSLClient : public QObject
{
Q_OBJECT
public:
QSSLClient(QObject *parent = nullptr);
~QSSLClient();
void connectServer();
void sendMsg(const QString &msg);
void closeSocket();
Q_SIGNALS:
void disconnected(void);
protected:
void loadCertificate();
private slots:
void sslErrors(const QList<QSslError> &errors);
void rx(void);
void serverDisconnect(void);
private:
QList<QSslCertificate> m_publicCertificateList;
QSslCertificate *m_privateCertificate;
QSslKey *m_key;
QSslSocket *m_client;
};
#endif // QSSLCLIENT_H
main.cpp
#include <QCoreApplication>
#include <QTimer>
#include <QDebug>
#include "QSSLClient.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSSLClient sslClient;
sslClient.connectServer();
sslClient.sendMsg("Hello Server");
QTimer::singleShot(2 * 1000, &sslClient, &QSSLClient::closeSocket);
return a.exec();
}
QSSLClient.cpp
#include "QSSLClient.h"
#include <QSslSocket>
#include <QSslCertificate>
#include <QFile>
#include <QSslKey>
#include <QJsonDocument>
#include <QList>
#include <QDebug>
QSSLClient::QSSLClient(QObject *parent) : QObject(parent)
{
m_key = new QSslKey;
m_privateCertificate = new QSslCertificate;
m_client = new QSslSocket;
loadCertificate();
connect(m_client, &QSslSocket::readyRead, this, &QSSLClient::rx);
connect(m_client, &QSslSocket::disconnected, this, &QSSLClient::serverDisconnect);
connect(m_client, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
m_client->addCaCertificates(m_publicCertificateList);
m_client->setPrivateKey(*m_key);
m_client->setLocalCertificate(*m_privateCertificate);
m_client->setPeerVerifyMode(QSslSocket::VerifyPeer);
qDebug() << "QSSLClient load over";
}
QSSLClient::~QSSLClient()
{
delete m_privateCertificate;
delete m_client;
delete m_key;
}
void QSSLClient::connectServer()
{
m_client->connectToHostEncrypted("localhost", 19999);
if(m_client->waitForEncrypted(5000)){
qDebug() << "Authentication Suceeded";
}
else{
qDebug("Unable to connect to server");
exit(0);
}
}
void QSSLClient::sendMsg(const QString &msg)
{
m_client->write(msg.toUtf8());
}
void QSSLClient::closeSocket()
{
if(m_client->disconnect()){
m_client->close();
qDebug() << "close success";
}
}
void QSSLClient::loadCertificate()
{
QFile p12File(":/res/p_client.p12");
if(!p12File.open(QIODevice::ReadOnly)){
qDebug() << "The certificate file open failed!";
exit(0);
}
bool ok = QSslCertificate::importPkcs12(&p12File, m_key, m_privateCertificate, &m_publicCertificateList, "cccccc");
if(!ok){
qDebug() << "The certificate import error!";
exit(0);
}
p12File.close();
}
void QSSLClient::sslErrors(const QList<QSslError> &errors)
{
foreach (const QSslError &error, errors)
qDebug() << error.errorString();
}
void QSSLClient::rx()
{
QString getMsg = m_client->readAll();
qDebug() << getMsg;
}
void QSSLClient::serverDisconnect()
{
// m_client->close();
// exit(0);
}
Java服务端源码:
SslContextProvider.java
package cn.it1995;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
public interface SslContextProvider {
TrustManager[] getTrustManagers() throws Exception;
KeyManager[] getKeyManagers() throws Exception;
String getProtocol();
}
SslUtil.java
package cn.it1995;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.Socket;
import java.security.*;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
public class SslUtil {
private static final String JKS = "JKS";
public static KeyManager[] createKeyManagers(String keyStorePath, String password) throws Exception {
return createKeyManagers(keyStorePath, password, password);
}
public static KeyManager[] createKeyManagers(String keyStorePath, String storePassword, String keyPassword) throws Exception {
String defaultAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmInstance = KeyManagerFactory.getInstance(defaultAlgorithm);
KeyStore ksInstance = KeyStore.getInstance(JKS);
FileInputStream fileInputStream = new FileInputStream(keyStorePath);
try{
ksInstance.load(fileInputStream, storePassword.toCharArray());
}
catch (IOException e){
e.printStackTrace();
}
catch (CertificateException e){
e.printStackTrace();
}
finally {
if(fileInputStream != null){
fileInputStream.close();
}
}
try{
kmInstance.init(ksInstance, keyPassword.toCharArray());
}
catch (UnrecoverableKeyException e){
e.printStackTrace();
}
return kmInstance.getKeyManagers();
}
public static SSLContext createSSLContext(SslContextProvider provider) throws Exception{
SSLContext context = SSLContext.getInstance(provider.getProtocol());
context.init(provider.getKeyManagers(), provider.getTrustManagers(), new SecureRandom());
return context;
}
public static SSLServerSocket createSSLServerSocket(int port, SslContextProvider provider) throws Exception {
SSLContext sslContext = createSSLContext(provider);
SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket)sslServerSocketFactory.createServerSocket(port);
sslServerSocket.setEnabledProtocols(new String[]{provider.getProtocol()});
sslServerSocket.setNeedClientAuth(true);
return sslServerSocket;
}
public static SSLSocket createSSLSocket(String host, int port, SslContextProvider provider) throws Exception{
SSLContext sslContext = createSSLContext(provider);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket)sslSocketFactory.createSocket(host, port);
sslSocket.setEnabledProtocols(new String[]{provider.getProtocol()});
return sslSocket;
}
public static TrustManager[] createTrustManagers(String keyStorePath, String password) throws Exception{
String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmInstance = TrustManagerFactory.getInstance(defaultAlgorithm);
KeyStore ksInstance = KeyStore.getInstance(JKS);
FileInputStream fileInputStream = new FileInputStream(keyStorePath);
try{
ksInstance.load(fileInputStream, password.toCharArray());
}
catch (IOException e){
e.printStackTrace();
}
catch (CertificateException e){
e.printStackTrace();
}
finally {
if(fileInputStream != null){
fileInputStream.close();
}
}
tmInstance.init(ksInstance);
return tmInstance.getTrustManagers();
}
public static String getPeerIdentity(Socket socket){
if(!(socket instanceof SSLSocket)){
return null;
}
SSLSession sslSession = ((SSLSocket)socket).getSession();
try{
Principal peerPrincipal = sslSession.getPeerPrincipal();
return getCommonName(peerPrincipal);
}
catch (SSLPeerUnverifiedException e){
e.printStackTrace();
}
return "unknown client";
}
private static String getCommonName(Principal subject){
try{
LdapName ldapName = new LdapName(subject.getName());
for(Rdn rdn : ldapName.getRdns()){
if("cn".equalsIgnoreCase(rdn.getType())){
return (String)rdn.getValue();
}
}
}
catch (Exception e){
e.printStackTrace();
}
return null;
}
}
SslServer.java
package cn.it1995;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
public class SslServer implements SslContextProvider{
@Override
public TrustManager[] getTrustManagers() throws Exception {
return SslUtil.createTrustManagers("D:\\\\IDEAProject\\\\SSLDemo\\\\src\\\\main\\\\resources\\\\server.jks", "cccccc");
}
@Override
public KeyManager[] getKeyManagers() throws Exception {
return SslUtil.createKeyManagers("D:\\\\IDEAProject\\\\SSLDemo\\\\src\\\\main\\\\resources\\\\server.jks", "cccccc");
}
@Override
public String getProtocol() {
return "TLSv1.2";
}
private ServerSocket createSSLSocket(int port) throws Exception {
SSLServerSocket sslServerSocket = SslUtil.createSSLServerSocket(port, this);
return sslServerSocket;
}
public void run(int port) throws Exception {
ServerSocket serverSocket = createSSLSocket(port);
System.out.println("服务端启动成功,等待客户端连接 ...... ...... ...... ......");
while(true){
try(SSLSocket client = (SSLSocket) serverSocket.accept(); OutputStream os = client.getOutputStream(); InputStream is = client.getInputStream()){
System.out.println("客户端: " + SslUtil.getPeerIdentity(client) + " 成功连接!");
byte[] b = new byte[1024];
is.read(b);
System.out.println("接收到客户端消息:" + new String(b));
System.out.println("发送消息给客户端!");
os.write("Hello Client".getBytes());
os.flush();
System.out.println("发送完成!");
}
catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
new SslServer().run(19999);
}
}
以上是关于Qt&Java笔记-Qt与Java进行SSL双向认证(Qt客户端,Java服务端)的主要内容,如果未能解决你的问题,请参考以下文章
Qt持久性对象进行序列化(同时比较了MFC与Java的方法)
Qt文档阅读笔记-QAudioInput&QAudioFormat解析与实例
Qt文档阅读笔记-QAudioInput&QAudioFormat解析与实例
Qt笔记-QTcpSocket中调用readAll要注意的地方(Java中RestTemplate和Qt配合要注意的地方)
Qt笔记-QTcpSocket中调用readAll要注意的地方(Java中RestTemplate和Qt配合要注意的地方)