private void handleRevealSignatureMessage(RevealSignatureMessage m) throws OtrException {
    Session session = getSession();
    SessionID sessionID = session.getSessionID();
    logger.finest(
        sessionID.getLocalUserId()
            + " received a reveal signature message from "
            + sessionID.getRemoteUserId()
            + " throught "
            + sessionID.getProtocolName()
            + ".");

    if (!session.getSessionPolicy().getAllowV2()) {
      logger.finest("Policy does not allow OTRv2, ignoring message.");
      return;
    }

    switch (this.getAuthenticationState()) {
      case AWAITING_REVEALSIG:
        // Use the received value of r to decrypt the value of gx
        // received
        // in the D-H Commit Message, and verify the hash therein.
        // Decrypt
        // the encrypted signature, and verify the signature and the
        // MACs.
        // If everything checks out:

        // * Reply with a Signature Message.
        // * Transition authstate to AUTHSTATE_NONE.
        // * Transition msgstate to MSGSTATE_ENCRYPTED.
        // * TODO If there is a recent stored message, encrypt it and
        // send
        // it as a Data Message.

        OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl();
        // Uses r to decrypt the value of gx sent earlier
        byte[] remoteDHPublicKeyDecrypted =
            otrCryptoEngine.aesDecrypt(m.revealedKey, null, this.getRemoteDHPublicKeyEncrypted());

        // Verifies that HASH(gx) matches the value sent earlier
        byte[] remoteDHPublicKeyHash = otrCryptoEngine.sha256Hash(remoteDHPublicKeyDecrypted);
        if (!Arrays.equals(remoteDHPublicKeyHash, this.getRemoteDHPublicKeyHash())) {
          logger.finest("Hashes don't match, ignoring message.");
          return;
        }

        // Verifies that Bob's gx is a legal value (2 <= gx <=
        // modulus-2)
        BigInteger remoteDHPublicKeyMpi;
        try {
          remoteDHPublicKeyMpi = SerializationUtils.readMpi(remoteDHPublicKeyDecrypted);
        } catch (IOException e) {
          throw new OtrException(e);
        }

        this.setRemoteDHPublicKey(otrCryptoEngine.getDHPublicKey(remoteDHPublicKeyMpi));

        // Verify received Data.
        if (!m.verify(this.getM2())) {
          logger.finest("Signature MACs are not equal, ignoring message.");
          return;
        }

        // Decrypt X.
        byte[] remoteXDecrypted = m.decrypt(this.getC());
        SignatureX remoteX;
        try {
          remoteX = SerializationUtils.toMysteriousX(remoteXDecrypted);
        } catch (IOException e) {
          throw new OtrException(e);
        }

        // Compute signature.
        PublicKey remoteLongTermPublicKey = remoteX.longTermPublicKey;
        SignatureM remoteM =
            new SignatureM(
                this.getRemoteDHPublicKey(),
                (DHPublicKey) this.getLocalDHKeyPair().getPublic(),
                remoteLongTermPublicKey,
                remoteX.dhKeyID);

        // Verify signature.
        byte[] signature;
        try {
          signature =
              otrCryptoEngine.sha256Hmac(SerializationUtils.toByteArray(remoteM), this.getM1());
        } catch (IOException e) {
          throw new OtrException(e);
        }

        if (!otrCryptoEngine.verify(signature, remoteLongTermPublicKey, remoteX.signature)) {
          session.showWarning("Bad revealed signature");
          logger.finest("Signature verification failed.");
          return;
        }

        logger.finest("Signature verification succeeded.");

        this.setAuthenticationState(AuthContext.NONE);
        this.setIsSecure(true);
        this.setRemoteLongTermPublicKey(remoteLongTermPublicKey);
        getSession().injectMessage(messageFactory.getSignatureMessage());
        break;
      default:
        logger.finest("Ignoring message.");
        break;
    }
  }
  private void handleSignatureMessage(SignatureMessage m) throws OtrException {
    Session session = getSession();
    SessionID sessionID = session.getSessionID();
    logger.finest(
        sessionID.getLocalUserId()
            + " received a signature message from "
            + sessionID.getRemoteUserId()
            + " throught "
            + sessionID.getProtocolName()
            + ".");
    if (!session.getSessionPolicy().getAllowV2()) {
      logger.finest("Policy does not allow OTRv2, ignoring message.");
      return;
    }

    switch (this.getAuthenticationState()) {
      case AWAITING_SIG:
        // Verify MAC.
        if (!m.verify(this.getM2p())) {
          logger.finest("Signature MACs are not equal, ignoring message.");
          return;
        }

        // Decrypt X.
        byte[] remoteXDecrypted = m.decrypt(this.getCp());
        SignatureX remoteX;
        try {
          remoteX = SerializationUtils.toMysteriousX(remoteXDecrypted);
        } catch (IOException e) {
          throw new OtrException(e);
        }
        // Compute signature.
        PublicKey remoteLongTermPublicKey = remoteX.longTermPublicKey;
        SignatureM remoteM =
            new SignatureM(
                this.getRemoteDHPublicKey(),
                (DHPublicKey) this.getLocalDHKeyPair().getPublic(),
                remoteLongTermPublicKey,
                remoteX.dhKeyID);
        OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl();
        // Verify signature.
        byte[] signature;
        try {
          signature =
              otrCryptoEngine.sha256Hmac(SerializationUtils.toByteArray(remoteM), this.getM1p());
        } catch (IOException e) {
          throw new OtrException(e);
        }
        if (!otrCryptoEngine.verify(signature, remoteLongTermPublicKey, remoteX.signature)) {
          session.showWarning("Bad signature");
          logger.finest("Signature verification failed.");
          return;
        }

        this.setIsSecure(true);
        this.setRemoteLongTermPublicKey(remoteLongTermPublicKey);
        break;
      default:
        logger.finest("We were not expecting a signature, ignoring message.");
        return;
    }
  }