/** Encrypts a command to be sent to the recipient. */ public EncryptedCommand(Server sender, byte[] senderKey, Server recipient, String data) { try { this.iv = ByteUtilities.toHexString(Aes.generateIv()); // Nonce lists will be reset on app restart, but the serverID should be a new public key. This // means the nonce lists should all be trying to talk to a new entry, and should all agree on // the nonce. // Set up the nonce DecryptedPayload decryptedPayload = new DecryptedPayload(); if (!outgoingNonces.containsKey(recipient.getServerId())) { outgoingNonces.put(recipient.getServerId(), 1L); } decryptedPayload.setNonce(outgoingNonces.get(recipient.getServerId())); this.nonce = decryptedPayload.getNonce(); outgoingNonces.put(recipient.getServerId(), decryptedPayload.getNonce() + 1L); decryptedPayload.setPayload(data); data = ByteUtilities.toHexString(decryptedPayload.toJson().getBytes("UTF-8")); this.sender = sender; byte[] otherKey = ByteUtilities.toByteArray(recipient.getServerId()); byte[] sharedKey = Secp256k1.generateSharedSecret(senderKey, otherKey); this.payload = Aes.encrypt(sharedKey, ByteUtilities.toByteArray(iv), data); } catch (Exception e) { LOGGER.error(null, e); } }
/** Attempt to handle the request in a cluster command. */ public static String handleCommand(byte[] recipientKey, EncryptedCommand command) { try { byte[] senderKey = ByteUtilities.toByteArray(command.getSender().getServerId()); byte[] sharedKey = Secp256k1.generateSharedSecret(recipientKey, senderKey); // Decrypt the payload String data = Aes.decrypt(sharedKey, ByteUtilities.toByteArray(command.getIv()), command.getPayload()); data = new String(ByteUtilities.toByteArray(data), "UTF-8"); DecryptedPayload payload = DecryptedPayload.parseData(data); // Validate the nonce. if (!incomingNonces.containsKey(command.sender.getServerId())) { incomingNonces.put(command.sender.getServerId(), 0L); } long expectedNonce = incomingNonces.get(command.sender.getServerId()); if (payload.getNonce() <= expectedNonce) { // Nonce is too low. throw new Exception("NONCE is too low from server: " + command.sender.getServerId()); } // Update so we only accept newer nonces after this command. incomingNonces.put(command.sender.getServerId(), payload.getNonce()); return payload.getPayload(); } catch (Exception e) { LOGGER.error(null, e); return ""; } }