java - 在握手之前解密从 tls 上的 websocket 客户端接收到的字节
问题描述
我已经开发了一个与 websockets 兼容的 sockets 服务器来通信用 java 和 web 制作的应用程序。但是最新的 Chrome 和 Mozilla 更新不再允许不安全的 websocket 连接。然后我被迫解密我的服务器收到的字节,然后再继续握手和协议的其余部分https://www.rfc-editor.org/rfc/rfc6455
我实现了以下目标:
从 CA 签署的证书中获取公钥。还有我服务器的私钥
使用 Java 的 Cipher 类,我设法使用这些密钥来加密和解密测试字符串
但我仍然不能做的是在继续握手之前解密我从 websocket 客户端收到的字节。
我希望你能帮助我。谢谢
我收到的错误:数据不得超过 256 字节
解决方案
解决了!解密委托给 SSLSocket 类。如果有人想在这里做这些步骤。
将 CA 颁发的证书和私钥导出到 p12 文件
openssl pkcs12 -export -in certificate/path/certificate.crt -inkey /path/privatekey/private.key -out filep12.p12 -name your_domain -CAfile /path/ca.crt -caname your_ca
Java 密钥库
keytool -genkey -alias your_alias -keyalg RSA -keystore name_store.jks -keysize 2048
输入密码(your_password)并确认后
keytool -importkeystore -srckeystore name_store.jks -destkeystore name_store.jks -deststoretype pkcs12 -srcstorepass your_password
keytool -delete -alias your_alias -keystore name_store.jks -storepass your_password
keytool -importkeystore -deststorepass your_password -destkeypass your_password -destkeystore name_store.jks -srckeystore filep12.p12 -srcstoretype PKCS12 -srcstorepass your_password -alias your_domain
your_alias 不能与 your_domain 相同或相似,在每个步骤中都要求输入密码 (your_password) 始终相同,以便在解密时没有填充错误
java中的类
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
public class SServidor {
public SServidor(){
try {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
File keystrorefile = new File("/path/name_store.jks");
System.out.println(keystrorefile.getAbsolutePath());
InputStream keystoreStream = new FileInputStream(keystrorefile);
char[] passphrase="your_password".toCharArray();
keystore.load(keystoreStream, passphrase);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, passphrase);
makeSSLSocketFactory(keystore, keyManagerFactory);
} catch (KeyStoreException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (FileNotFoundException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (CertificateException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnrecoverableKeyException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void log(Object msj){
System.out.println(msj.toString());
}
public void makeSSLSocketFactory(KeyStore loadedKeyStore, KeyManagerFactory key){
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(loadedKeyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(key.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
SSLServerSocketFactory sslssf = ctx.getServerSocketFactory();
ServerSocket conexion = sslssf.createServerSocket(your_port);
SSLSocket cliente=(SSLSocket) conexion.accept();
cliente.startHandshake();
InputStream in = cliente.getInputStream();
OutputStream out = cliente.getOutputStream();
int byte_recibido=-1;
while(cliente.isConnected() && (byte_recibido=in.read())>-1){
Integer n=byte_recibido & 0xFF;
String s=new String(String.valueOf(Character.toChars(n)));
log(s);
}
out.close();
bin.close();
in.close();
cliente.close();
conexion.close();
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (KeyStoreException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (KeyManagementException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(SServidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}`
其他的,到websocket的连接应该是这样的 wss://your_domain:port websocket url中不能输入IP地址,必须用CA颁发的证书中注册的域来完成
使用解密的字节,我可以继续使用 RFC6455 协议。这只是我所做的测试,显然对于套接字应用程序,此外,还需要异步处理连接到服务器的客户端。我使用 ExecutorService 类执行此操作,但这是另一个主题
推荐阅读
- android - 在 Android 上使用 libgdx 加载大量点模型需要大量时间
- java - 通过 Android PDFDocument 生成的 PDF 尺寸太大。在使用 pdfbox 时,它会在输出中剪切图像
- javascript - 如何根据其他标签数组对带有标签的对象数组进行排序?
- php - 语法错误或访问冲突:1066 不是唯一的表/别名:
- javascript - 使用 Append 添加的项目无法被 querySelectorAll 识别
- jquery - 选择 2 Webpack-encore
- javascript - 在javascript Themezy模板中向地图添加标记
- xcode - 在 Xcode 11 中将分支合并到 master 中?
- r - R Leaflet PopupGraph - 在 map_marker_click 上添加 PopupGraphs
- java - 具有复杂键的 SpringData Redis 存储库