-2

I have developed a sockets server compatible with websockets to communicate applications made in java and web. But the latest Chrome and Mozilla updates no longer allow insecure connections to 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

I have achieved the following:

  1. Obtain the public key from a certificate signed by a 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

But what I still can not do is decrypt the bytes I receive from the websocket client before proceeding with the handshake.

I hope you can help me. Thank you

The error I receive: Data must not be longer than 256 bytes

Community
  • 1
  • 1
  • 3
    "Secure" websockets is just the websocket protocol but over TLS. This means it is more than just "encrypting" and "decrypting" strings, TLS is a whole protocol, with defined exchanges, framing, padding, error handling, etc. You should not attempt to write it from scratch, use a library that handles TLS operations for you. You can find many in any programming languages. – Patrick Mevzek Jun 21 '19 at 21:51
  • I'm not sure what you're asking. Are you saying you can't get TLS to work on your server? – President James K. Polk Jun 21 '19 at 23:59
  • There are no bytes transmitted before the handshake. Your question doesn't make sense. – user207421 Jun 22 '19 at 00:30
  • @PatrickMevzek Thank you, I'm going to find out one that I can use – Diego Borrovich Jun 22 '19 at 07:05
  • @JamesKPolk I have a websocket server, which is also a Sockets server, which now I need to make encrypted connections. And connect from the client in this way "wss: // address: port". The problem is that the bytes coming from the client I can not decrypt them, consequently the server can not send the answer to perform the handshake – Diego Borrovich Jun 22 '19 at 07:13
  • @user207421 With "handshake" I mean the term of the handshake process. When I say before the handshake, I mean the moment when the client sends the handshake request. When I say the bytes that arrive before the handshake, I want to refer to the bytes that the client sends as a request to start the process. These are the bytes that I can not decrypt – Diego Borrovich Jun 22 '19 at 07:19
  • 'The term of the handshake process' is meaningless. If you're referring to the `ClientHello` message, (a) it is *part* of the handshake! and (b) it isn't encrypted, unless there had been a prior handshake. If you're referring to something else,what? Still doesn't make sense. – user207421 Jun 24 '19 at 00:06
  • @user207421 I see you mean the protocol https://tools.ietf.org/html/rfc5246. I refer to the handshake for websockets indicated in https://tools.ietf.org/html/rfc6455#section-4 Section 4 "Opening Handshake" – Diego Borrovich Jun 24 '19 at 00:35

1 Answers1

-1

Solved! The decryption was entrusted to the SSLSocket class. 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

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

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

After entering a password(your_password) and confirm

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

The class in 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

With the decrypted bytes I can proceed with the RFC6455 protocol. 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. I do this with the ExecutorService class but that is another topic