/**
   * * All the symmetric encryption and decryption occurs here. Ciphers must be instantiated and
   * executing using the derivated keys from p1 and p2. From a text corpus client and server
   * interchange some lines, all of them encrypted. The challenge for client is to decrypt and
   * answer accordingly to server expectations.
   *
   * @throws IOException Communication errors will throw this one
   * @throws ParseException Appears if something unexpected is received
   */
  private void communicationPhase() throws IOException, ParseException {
    // stream cipher is instantiated here!
    streamCipher = new StreamCipher(sharedKey, prime, p1, p2);

    // send ACK informing that we are ready to encrypt/decrypt
    SpecsDoneRequest request = new SpecsDoneRequest(++counter);
    log.debug("Message to send: [" + request.toJSON() + "]");
    writer.write(request.toJSON().getBytes("UTF-8"));
    writer.flush();

    // Receive all text from Server
    receiveAllLines();

    // Reset the Shift Register prior to sending out CLIENT_TEXT messages
    streamCipher.reset();

    // Send all text to Server
    sendAllLines();

    // Wait for last server message
    byte[] buff = new byte[BUFFER_SIZE];
    reader.read(buff);
    String reply = new String(buff, "UTF-8");

    log.debug("Message received: [" + reply + "]");
    CommDoneResponse response = new CommDoneResponse();
    response.fromJSON(StringParser.getUTFString(reply));

    // answers properly
    CommDoneRequest doneRequest = new CommDoneRequest();
    log.debug("Message to send: [" + doneRequest.toJSON() + "]");
    writer.write(doneRequest.toJSON().getBytes("UTF-8"));
  }
  private void sendLine(long id, String line) throws IOException, ParseException {
    String encrpytedMsg = streamCipher.encrypt(line);
    TextRequest msgRequest = new TextRequest(id, encrpytedMsg, ++counter);

    // Send TEXT Message Length
    NextMessageLengthRequest lenRequest =
        new NextMessageLengthRequest(id, msgRequest.toJSON(), ++counter);
    log.debug("Message to send: [" + lenRequest.toJSON() + "]");
    writer.write(lenRequest.toJSON().getBytes("UTF-8"));
    writer.flush();

    // Length Acknowledgement
    byte[] buff = new byte[BUFFER_SIZE];
    reader.read(buff);
    String reply = new String(buff, "UTF-8");
    log.debug("Message received: [" + reply + "]");

    MessageLengthReceivedResponse lenResponse = new MessageLengthReceivedResponse();
    lenResponse.fromJSON(StringParser.getUTFString(reply));

    // Send TEXT Message
    System.out.println("CLIENT_TEXT >>>>>>>>> ID: " + id);
    System.out.println("Plain Text: \n" + line);
    System.out.println("Cipher Text: \n" + encrpytedMsg);

    log.debug("Message to send: [" + msgRequest.toJSON() + "]");
    writer.write(msgRequest.toJSON().getBytes("UTF-8"));
    writer.flush();

    // Wait Acknowledgement of SERVER_TEXT_RECV
    buff = new byte[BUFFER_SIZE];
    reader.read(buff);
    reply = new String(buff, "UTF-8");
    log.debug("Message received: [" + reply + "]");

    TextReceivedResponse txtResponse = new TextReceivedResponse();
    txtResponse.fromJSON(StringParser.getUTFString(reply));
  }
 private String decrypt(String ciphertext) {
   return streamCipher.decrypt(ciphertext);
 }