package network.thunder.core.communication.processor.implementations; import network.thunder.core.communication.Message; import network.thunder.core.communication.objects.messages.MessageExecutor; import network.thunder.core.communication.objects.messages.impl.message.authentication.AuthenticationMessage; import network.thunder.core.communication.objects.messages.interfaces.factories.AuthenticationMessageFactory; import network.thunder.core.communication.objects.messages.interfaces.factories.ContextFactory; import network.thunder.core.communication.objects.messages.interfaces.helper.LNEventHelper; import network.thunder.core.communication.objects.messages.interfaces.message.authentication.Authentication; import network.thunder.core.communication.processor.interfaces.AuthenticationProcessor; import network.thunder.core.etc.crypto.CryptoTools; import network.thunder.core.mesh.NodeClient; import network.thunder.core.mesh.NodeServer; import org.bitcoinj.core.ECKey; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; public class AuthenticationProcessorImpl extends AuthenticationProcessor { AuthenticationMessageFactory messageFactory; LNEventHelper eventHelper; NodeClient node; NodeServer nodeServer; MessageExecutor messageExecutor; public boolean sentAuth; public boolean authFinished; public AuthenticationProcessorImpl (ContextFactory contextFactory, NodeClient node) { this.messageFactory = contextFactory.getAuthenticationMessageFactory(); this.eventHelper = contextFactory.getEventHelper(); this.node = node; this.nodeServer = contextFactory.getServerSettings(); } @Override public void onLayerActive (MessageExecutor messageExecutor) { this.messageExecutor = messageExecutor; if (shouldSendAuthenticationFirst()) { sendAuthentication(); } } @Override public void onInboundMessage (Message message) { if (message instanceof Authentication) { processMessage(message); } else if (!authenticationExchangeFinished()) { sendAuthenticatedErrorMessage("Not authenticated.."); } else { passMessageToNextLayer(message); } } @Override public void onOutboundMessage (Message message) { if (allowOutboundMessage(message)) { messageExecutor.sendMessageUpwards(message); } else { throw new RuntimeException("Should not happen, which class is this? " + message); } } public boolean shouldSendAuthenticationFirst () { return !node.isServer; } public void sendAuthentication () { if (!sentAuth) { messageExecutor.sendMessageUpwards(getAuthenticationMessage()); sentAuth = true; } } public void processMessage (Message message) { if (authenticationExchangeFinished()) { messageExecutor.sendMessageUpwards(messageFactory.getFailureMessage("Already authenticated")); } else { processAuthenticationMessage(message); } } public boolean allowOutboundMessage (Message message) { return message instanceof Authentication || authFinished; } public void processAuthenticationMessage (Message message) { AuthenticationMessage authObject = (AuthenticationMessage) message; try { checkAuthenticationMessage(authObject, node); sendAuthentication(); authFinished = true; eventHelper.onConnectionOpened(node); messageExecutor.sendNextLayerActive(); } catch (Exception e) { e.printStackTrace(); messageExecutor.sendMessageUpwards(messageFactory.getFailureMessage(e.getMessage())); } } @Override public void onLayerClose () { eventHelper.onConnectionClosed(node); } public AuthenticationMessage getAuthenticationMessage () { try { ECKey keyServer = nodeServer.pubKeyServer; ECKey keyClient = node.ephemeralKeyClient; byte[] data = new byte[keyServer.getPubKey().length + keyClient.getPubKey().length]; System.arraycopy(keyServer.getPubKey(), 0, data, 0, keyServer.getPubKey().length); System.arraycopy(keyClient.getPubKey(), 0, data, keyServer.getPubKey().length, keyClient.getPubKey().length); byte[] pubkeyServer = keyServer.getPubKey(); byte[] signature = CryptoTools.createSignature(keyServer, data); return messageFactory.getAuthenticationMessage(pubkeyServer, signature); } catch (NoSuchProviderException | NoSuchAlgorithmException e) { throw new RuntimeException(e); } } public void checkAuthenticationMessage (AuthenticationMessage authentication, NodeClient node) throws NoSuchProviderException, NoSuchAlgorithmException { //TODO: Check whether the pubkeyClient is actually the pubkey we are expecting node.pubKeyClient = ECKey.fromPublicOnly(authentication.pubKeyServer); ECKey pubKeyClient = node.pubKeyClient; ECKey pubKeyTempServer = node.ephemeralKeyServer; byte[] data = new byte[pubKeyClient.getPubKey().length + pubKeyTempServer.getPubKey().length]; System.arraycopy(pubKeyClient.getPubKey(), 0, data, 0, pubKeyClient.getPubKey().length); System.arraycopy(pubKeyTempServer.getPubKey(), 0, data, pubKeyClient.getPubKey().length, pubKeyTempServer.getPubKey().length); CryptoTools.verifySignature(pubKeyClient, data, authentication.signature); } private boolean authenticationExchangeFinished () { return authFinished; } private void sendAuthenticatedErrorMessage (String error) { messageExecutor.sendMessageUpwards(messageFactory.getFailureMessage(error)); } private void passMessageToNextLayer (Message message) { messageExecutor.sendMessageDownwards(message); } }