Hello there
I am trying to implement ssl encryption with tcp server socket. I could achieve it using streams but I am not sure how to achieve it using Actors. For now I am using sslengine.unwrap on the Received.class object I received. Unfortunately I am unable to figure out how to read the decrypted text. Any help or advice will be appreciated.
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;
import org.apache.logging.log4j.*;
import akka.actor.*;
import akka.io.Tcp.*;
import akka.stream.TLSRole;
import akka.io.TcpMessage;
import akka.util.ByteString;
import scala.concurrent.duration.Duration;
public class TcpConnectionHandlerActor extends AbstractActor {
private final static Logger log = LogManager.getLogger(TcpConnectionHandlerActor.class);
private final String clientIP;
private ActorRef sender;
private final SSLEngine engine;
public TcpConnectionHandlerActor(String clientIP) {
this.clientIP = clientIP;
this.engine = createSSLEngine(getSSLContext(), TLSRole.server());
}
public static Props props(String clientIP) {
return Props.create(TcpConnectionHandlerActor.class, clientIP);
}
@Override
public void preStart() throws Exception {
log.trace("=============================START---OF---LOG================================");
log.trace(getSelf().path().name()+" starting tcp-handler");
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(Received.class, msg->{
sender = getSender();
ByteBuffer buff = msg.data().asByteBuffer();
ByteBuffer dest = ByteBuffer.allocate(2024);
try{
engine.beginHandshake();
ByteBuffer inb = msg.data().toByteBuffer();
ByteBuffer outb = ByteBuffer.allocate(
engine.getSession().getPacketBufferSize());
inb.put(msg.data().toArray());
//inb.flip();
SSLEngineResult result = engine.unwrap(inb, outb);
log.trace("Wrapped " + outb.position() + " octets ("
+ result + ").");
outb.flip();
log.trace("Cyphertext: " + outb);
}catch(SSLException e) {
log.error(e.getMessage());
log.error(e.getCause());
getContext().stop(getSelf());
}
String sslmessageX = ByteString.fromByteBuffer(dest).utf8String();
log.info(getSelf().path().name()+" received-tcp: "+ sslmessageX);
})
.match(String.class, s->{
if(s.contains("Error")){
log.info(getSelf().path().name()+" sending out NACK to "+clientIP.toString()+" : "+s); //if not ack then kill the ips actor
}
sender.tell(TcpMessage.write(ByteString.fromString(s)), getSelf());
})
.match(ReceiveTimeout.class, r -> {
getContext().setReceiveTimeout(Duration.Undefined());
})
.match(ConnectionClosed.class, closed->{
log.debug(getSelf().path().name()+" Server: Connection Closure "+closed);
getContext().stop(getSelf());
})
.match(CommandFailed.class, conn->{
log.fatal(getSelf().path().name()+" Server: Connection Failed "+conn);
getContext().stop(getSelf());
})
.match(Terminated.class,s->{
})
.build();
}
@Override
public void postStop() throws Exception {
log.trace(getSelf().path().name()+" stopping tcp-handler");
log.trace("=============================END---OF---LOG================================");
}
private static SSLContext getSSLContext(){
SSLContext context;
try {
// Don't hardcode your password in actual code
char[] password = "abcd1234".toCharArray();
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("config/ssl/mykeystore.p12"), password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, password);
context = SSLContext.getInstance("TLSv1.2");
context.init(
keyManagerFactory.getKeyManagers(),
trustManagerFactory.getTrustManagers(),
new SecureRandom());
} catch (KeyStoreException
| IOException
| NoSuchAlgorithmException
| CertificateException
| UnrecoverableKeyException
| KeyManagementException e) {
throw new RuntimeException(e);
}
return context;
}
private static SSLEngine createSSLEngine(SSLContext context,TLSRole role) {
SSLEngine engine = context.createSSLEngine();
engine.setUseClientMode(role.equals(akka.stream.TLSRole.client()));
engine.setEnabledCipherSuites(new String[] {"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"});
engine.setEnabledProtocols(new String[] {"TLSv1.2"});
return engine;
}
}