简体   繁体   English

在握手之前解密从 tls 上的 websocket 客户端收到的字节

[英]Decrypt bytes received from a websocket client on tls before the handshake

I have developed a sockets server compatible with websockets to communicate applications made in java and web.我开发了一个与 websockets 兼容的 sockets 服务器来通信用 java 和 web 制作的应用程序。 But the latest Chrome and Mozilla updates no longer allow insecure connections to websockets.但是最新的 Chrome 和 Mozilla 更新不再允许与 websockets 的不安全连接。 Then I am forced to decrypt the bytes that my server receives before proceeding with the handshake and the rest of the protocol https://www.rfc-editor.org/rfc/rfc6455然后我被迫在继续握手和协议的其余部分之前解密我的服务器收到的字节https://www.rfc-editor.org/rfc/rfc6455

I have achieved the following:我取得了以下成绩:

  1. Obtain the public key from a certificate signed by a CA.从 CA 签署的证书中获取公钥。 And the private key of my server还有我服务器的私钥

  2. With the Cipher class of Java I have managed to use these keys to encrypt and decrypt a test string使用 Java 的 Cipher 类,我设法使用这些密钥来加密和解密测试字符串

But what I still can not do is decrypt the bytes I receive from the websocket client before proceeding with the handshake.但是我仍然不能做的是在继续握手之前解密我从 websocket 客户端收到的字节。

I hope you can help me.我希望你能帮助我。 Thank you谢谢

The error I receive: Data must not be longer than 256 bytes我收到的错误:数据不得超过 256 字节

Solved!解决了! The decryption was entrusted to the SSLSocket class.解密委托给 SSLSocket 类。 In case someone wants to do it here the steps.如果有人想在这里做这些步骤。

Export the certificates issued by the CA and the private key to a p12 file将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 key store Java 密钥库

keytool -genkey -alias your_alias -keyalg RSA -keystore name_store.jks -keysize 2048

After entering a password(your_password) and confirm输入密码(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 must not be the same or similar to your_domain, the password is asked to enter (your_password) in each step that is always the same so that when decrypting there are no padding errors your_alias 不能与 your_domain 相同或相似,要求在每个步骤中输入的密码 (your_password) 始终相同,以便在解密时不会出现填充错误

The class in java 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);
    }

} 

}`

Something else, the connection to the websocket should be like this wss://your_domain:port An IP address must not be entered in the websocket url, it must be done with the domain registered in the certificate issued by the CA别的,websocket 的连接应该是这样的 wss://your_domain:port 不能在 websocket url 中输入 IP 地址,必须使用 CA 颁发的证书中注册的域来完成

With the decrypted bytes I can proceed with the RFC6455 protocol.使用解密的字节,我可以继续使用 RFC6455 协议。 This is only the test that I did, obviously for a sockets application, in addition, it is necessary to asynchronously handle the clients that connect to the server.这只是我做的测试,显然是针对sockets的应用,另外需要异步处理连接到服务器的客户端。 I do this with the ExecutorService class but that is another topic我用 ExecutorService 类来做这件事,但那是另一个话题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM