Example #1
0
 /**
  * Put a connection into the PLAINTEXT state, first sending the other side a notice that we're
  * doing so if we're currently ENCRYPTED, and we think he's logged in.
  *
  * @throws OTRException
  */
 public void disconnect(OTRCallbacks callback) throws OTRException {
   if (this.msgState.getCurState() == MsgState.ST_ENCRYPTED
       && this.their_keyid > 0
       && callback.isLoggedIn(accountName, protocol, recName) == 1) {
     TLV[] tlvs = new TLV[1];
     tlvs[0] = new TLV(TLV.DISCONNECTED, new byte[0]);
     DataMessage dm = Proto.createData(this, new byte[0], Proto.MSGFLAGS_IGNORE_UNREADABLE, tlvs);
     callback.injectMessage(accountName, protocol, recName, new String(dm.getContent()));
   }
   forceFinished();
   this.msgState.curState = MsgState.ST_UNENCRYPTED;
   callback.updateContextList();
 }
Example #2
0
  // Send a message to the network, fragmenting first if necessary.
  // All messages to be sent to the network should go through this
  // method immediately before they are sent, ie after encryption.
  String fragmentAndSend(String message, int fragPolicy, OTRCallbacks callback) {
    int mms = callback.maxMessageSize(this);
    // Don't incur overhead of fragmentation unless necessary
    if (mms == 0 || message.length() <= mms) {
      // No fragmentation necessary
      if (fragPolicy == Policy.FRAGMENT_SEND_ALL) {
        callback.injectMessage(this.accountName, this.protocol, this.recName, message);
        return null;
      } else {
        // return the entire given message.
        return message;
      }
    }
    int fragment_count = ((message.length() - 1) / (mms - 19)) + 1;
    // like ceil(msglen/(mms - 19))

    String[] frags = Proto.fragmentCreate(mms, fragment_count, message);
    String returnFragment = null;

    // Determine which fragments to send and which to return
    // based on given Fragment Policy.  If the first fragment
    // should be returned instead of sent, store it.
    if (fragPolicy == Policy.FRAGMENT_SEND_ALL_BUT_FIRST) {
      returnFragment = frags[0];
    } else {
      callback.injectMessage(accountName, protocol, recName, frags[0]);
    }

    // Prevent the demo receiver to receive all the messages in a single read
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    for (int i = 1; i < fragment_count - 1; i++) {
      callback.injectMessage(accountName, protocol, recName, frags[i]);
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    // If the last fragment should be stored instead of sent,
    // store it
    if (fragPolicy == Policy.FRAGMENT_SEND_ALL_BUT_LAST) {
      returnFragment = frags[fragment_count - 1];
    } else {
      callback.injectMessage(accountName, protocol, recName, frags[fragment_count - 1]);
    }
    return returnFragment;
  }
Example #3
0
 FingerPrint findFingerPrint(byte[] fingerprint, boolean add, OTRCallbacks callback) {
   String key = new String(fingerprint);
   FingerPrint ret = (FingerPrint) fingerprintTable.get(key);
   if (ret != null) return ret;
   if (!add) return null;
   ret = new FingerPrint();
   ret.fingerPrint = new byte[fingerprint.length];
   System.arraycopy(fingerprint, 0, ret.fingerPrint, 0, fingerprint.length);
   ret.context = this;
   fingerprintTable.put(key, ret);
   /* Inform the user of the new fingerprint */
   callback.newFingerprint(us, accountName, key, recName, ret.fingerPrint);
   /* Arrange that the new fingerprint be written to disk */
   callback.writeFingerprints();
   return ret;
 }
Example #4
0
  void sendOrErrorAuth(boolean err, OTRCallbacks callback) {

    if (!err) {
      String msg = this.auth.lastauthmsg;
      if (msg != null) {
        this.fragmentAndSend(msg, Policy.FRAGMENT_SEND_ALL, callback);
        this.lastSent = System.currentTimeMillis();
      }
    } else {
      callback.handleMsgEvent(OTRCallbacks.OTRL_MSGEVENT_SETUP_ERROR, this, null);
    }
  }
Example #5
0
  /**
   * Handle a message just received from the network. It is safe to pass all received messages to
   * this routine.
   *
   * <p>If no Exception is thrown, and the return value is not null, replace the received message
   * with msg in the returned StringTLV, and deliver that to the user instead.
   *
   * <p>If the return value is null, then the message you received was an internal protocol message,
   * and no message should be delivered to the user.
   */
  public StringTLV messageReceiving(String inMessage, OTRCallbacks callback) throws OTRException {

    OTRMessage message = OTRMessage.parse(inMessage);

    /* Check the policy */
    int policy = callback.getOtrPolicy(this);

    /* Should we go on at all? */
    if ((policy & Policy.VERSION_MASK) == 0) {
      return null;
    }

    // See if we have a fragment
    switch (Proto.fragmentAccumulate(this, new String(message.getContent()))) {
      case Proto.FRAGMENT_UNFRAGMENTED:
        // Do nothing
        break;
      case Proto.FRAGMENT_INCOMPLETE:
        // We've accumulated this fragment, but we don't have a
        // complete message yet
        return null;
      case Proto.FRAGMENT_COMPLETE:
        // We've got a new complete message, in unfragmessage.
        message = OTRMessage.parse(this.complete_msg);
        break;
    }

    byte msgtype = message.getType();

    /* See if they responded to our OTR offer */
    if ((policy & Policy.SEND_WHITESPACE_TAG) != 0) {
      if (msgtype != OTRMessage.MSG_NOTOTR) {
        otr_offer = OFFER_ACCEPTED;
      } else if (otr_offer == OFFER_SENT) {
        otr_offer = OFFER_REJECTED;
      }
    }

    gone_encrypted = 0;
    ignore_message = -1;

    switch (msgtype) {
      case OTRMessage.MSG_QUERY:

        /* Start AKE */
        try {
          auth.startAKE(null);
          this.sendOrErrorAuth(false, callback);
        } catch (OTRException e) {
          this.sendOrErrorAuth(true, callback);
        }
        if (auth.havemsgp != 0) {
          this.lastMessage = auth.lastauthmsg;
        }
        /* Don't display the Query message to the user. */
        if (ignore_message == -1) ignore_message = 1;
        break;
      case OTRMessage.MSG_DH_COMMIT:
        if ((policy & Policy.ALLOW_V2) != 0) {
          try {
            auth.handleCommit(message.getContent(), null);
            this.sendOrErrorAuth(false, callback);
          } catch (OTRException e) {
            this.sendOrErrorAuth(true, callback);
          }
        }
        if (ignore_message == -1) ignore_message = 1;
        break;
      case OTRMessage.MSG_DH_KEY:
        if ((policy & Policy.ALLOW_V2) != 0) {
          /* Get our private key */
          PrivKey privkey = us.getPrivKey(new Account(accountName, protocol), true);
          try {
            auth.handleKey(message.getContent(), privkey);
            this.sendOrErrorAuth(false, callback);
          } catch (OTRException e) {
            this.sendOrErrorAuth(true, callback);
          }
        }
        if (ignore_message == -1) ignore_message = 1;
        break;

      case OTRMessage.MSG_REVEAL_SIGNATURE:
        if ((policy & Policy.ALLOW_V2) != 0) {
          /* Get our private key */
          PrivKey privkey = us.getPrivKey(new Account(accountName, protocol), true);
          try {
            auth.handleRevealsig(message.getContent(), privkey);
            this.goEncrypted(callback);
            this.sendOrErrorAuth(false, callback);
          } catch (OTRException e) {
            this.sendOrErrorAuth(true, callback);
          }
        }
        if (ignore_message == -1) ignore_message = 1;
        break;
      case OTRMessage.MSG_SIGNATURE:
        if ((policy & Policy.ALLOW_V2) != 0) {
          /* Get our private key */
          try {
            auth.handleSignature(message.getContent());
            this.goEncrypted(callback);
            this.sendOrErrorAuth(false, callback);
          } catch (OTRException e) {
            this.sendOrErrorAuth(true, callback);
          }
        }
        if (ignore_message == -1) ignore_message = 1;
        break;
      case OTRMessage.MSG_DATA:
        switch (msgState.getCurState()) {
          case MsgState.ST_UNENCRYPTED:
          case MsgState.ST_FINISHED:
            callback.handleMsgEvent(OTRCallbacks.OTRL_ERRCODE_MSG_NOT_IN_PRIVATE, this, null);
            ignore_message = 1;
            String err_msg =
                callback.errorMessage(this, OTRCallbacks.OTRL_ERRCODE_MSG_NOT_IN_PRIVATE);
            callback.injectMessage(accountName, protocol, recName, err_msg);
            break;
          case MsgState.ST_ENCRYPTED:
            byte[] res;
            StringTLV stlv = new StringTLV();
            OTRTLV[] tlvs;
            try {
              DataMessage dm = (DataMessage) message;
              res = Proto.acceptData(this, dm, null);
            } catch (OTRException otre) {
              callback.handleMsgEvent(OTRCallbacks.OTRL_MSGEVENT_RCVDMSG_UNREADABLE, this, null);
              return null;
            }
            int end = 0;
            for (; end < res.length && res[end] != 0; end++) {}

            stlv.msg = new String(res, 0, end);
            if (end != res.length && end + 1 != res.length) {
              end++;
              tlvs = new TLV().parse(res, end, res.length - end);
              stlv.tlvs = tlvs;

              /* If the other side told us he's disconnected his
               * private connection, make a note of that so we
               * don't try sending anything else to him. */
              OTRTLV tlv = new TLV().find(tlvs, TLV.DISCONNECTED);
              if (tlv != null) {
                forceFinished();
              }

              /* If TLVs contain SMP data, process it */
              int nextMsg = this.smstate.nextExpected;
              tlv = new TLV().find(tlvs, TLV.SMP1Q);
              if (tlv != null && nextMsg == SM.EXPECT1) {
                /* We can only do the verification half now.
                 * We must wait for the secret to be entered
                 * to continue. */
                byte[] question = tlv.getValue();
                int qlen = 0;
                for (; qlen != question.length && question[qlen] != 0; qlen++) {}
                if (qlen == question.length) qlen = 0;
                else qlen++;
                byte[] input = new byte[question.length - qlen];
                System.arraycopy(question, qlen, input, 0, question.length - qlen);
                SM.step2a(this.smstate, input, 1, prov);
                if (qlen != 0) qlen--;
                byte[] plainq = new byte[qlen];
                System.arraycopy(question, 0, plainq, 0, qlen);
                if (this.smstate.smProgState != SM.PROG_CHEATED) {
                  callback.handleSmpEvent(
                      OTRCallbacks.OTRL_SMPEVENT_ASK_FOR_ANSWER, this, 25, new String(plainq));
                } else {
                  callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_CHEATED, this, 0, null);
                  this.smstate.nextExpected = SM.EXPECT1;
                  this.smstate.smProgState = SM.PROG_OK;
                }
              } else {
                callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_ERROR, this, 0, null);
              }

              tlv = new TLV().find(tlvs, TLV.SMP1);
              if (tlv != null) {
                if (nextMsg == SM.EXPECT1) {
                  /* We can only do the verification half now.
                   * We must wait for the secret to be entered
                   * to continue. */
                  SM.step2a(this.smstate, tlv.getValue(), 0, prov);
                  if (this.smstate.smProgState != SM.PROG_CHEATED) {
                    callback.handleSmpEvent(
                        OTRCallbacks.OTRL_SMPEVENT_ASK_FOR_SECRET, this, 25, null);
                  } else {
                    callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_CHEATED, this, 0, null);
                    this.smstate.nextExpected = SM.EXPECT1;
                    this.smstate.smProgState = SM.PROG_OK;
                  }
                } else {
                  callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_ERROR, this, 0, null);
                }
              }

              tlv = new TLV().find(tlvs, TLV.SMP2);
              if (tlv != null && nextMsg == SM.EXPECT2) {
                byte[] nextmsg = SM.step3(this.smstate, tlv.getValue(), prov);
                if (this.smstate.smProgState != SM.PROG_CHEATED) {
                  /* Send msg with next smp msg content */
                  OTRTLV sendtlv = new TLV(TLV.SMP3, nextmsg);
                  OTRTLV[] stlvs = new OTRTLV[1];
                  stlvs[0] = sendtlv;
                  DataMessage dm =
                      Proto.createData(this, new byte[0], Proto.MSGFLAGS_IGNORE_UNREADABLE, stlvs);
                  byte[] senddata = dm.getContent();
                  this.fragmentAndSend(new String(senddata), Policy.FRAGMENT_SEND_ALL, callback);
                  this.smstate.nextExpected = SM.EXPECT4;
                } else {
                  callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_CHEATED, this, 0, null);
                  this.smstate.nextExpected = SM.EXPECT1;
                  this.smstate.smProgState = SM.PROG_OK;
                }
              } else if (tlv != null) {
                callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_ERROR, this, 0, null);
              }

              tlv = new TLV().find(tlvs, TLV.SMP3);
              if (tlv != null && nextMsg == SM.EXPECT3) {
                byte[] nextmsg = SM.step4(this.smstate, tlv.getValue(), prov);
                /* Set trust level based on result */
                if (this.smstate.smProgState == SM.PROG_SUCCEEDED) {
                  this.setSmpTrust(callback, true);
                } else {
                  this.setSmpTrust(callback, false);
                }
                if (this.smstate.smProgState != SM.PROG_CHEATED) {
                  /* Send msg with next smp msg content */
                  OTRTLV[] stlvs = new TLV[1];
                  stlvs[0] = new TLV(TLV.SMP4, nextmsg);
                  DataMessage dm =
                      Proto.createData(this, new byte[0], Proto.MSGFLAGS_IGNORE_UNREADABLE, stlvs);
                  byte[] senddata = dm.getContent();
                  this.fragmentAndSend(new String(senddata), Policy.FRAGMENT_SEND_ALL, callback);
                  int succorfail =
                      this.smstate.smProgState == SM.PROG_SUCCEEDED
                          ? OTRCallbacks.OTRL_SMPEVENT_SUCCESS
                          : OTRCallbacks.OTRL_SMPEVENT_FAILURE;
                  callback.handleSmpEvent(succorfail, this, 100, null);
                  this.smstate.nextExpected = SM.EXPECT1;
                } else {
                  callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_CHEATED, this, 0, null);
                  this.smstate.nextExpected = SM.EXPECT1;
                  this.smstate.smProgState = SM.PROG_OK;
                }

              } else if (tlv != null) {
                callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_ERROR, this, 0, null);
              }

              tlv = new TLV().find(tlvs, TLV.SMP4);
              if (tlv != null && nextMsg == SM.EXPECT4) {

                SM.step5(this.smstate, tlv.getValue(), prov);
                if (this.smstate.smProgState == SM.PROG_SUCCEEDED) {
                  this.setSmpTrust(callback, true);
                } else {
                  this.setSmpTrust(callback, false);
                }
                if (this.smstate.smProgState != SM.PROG_CHEATED) {
                  int succorfail =
                      this.smstate.smProgState == SM.PROG_SUCCEEDED
                          ? OTRCallbacks.OTRL_SMPEVENT_SUCCESS
                          : OTRCallbacks.OTRL_SMPEVENT_FAILURE;
                  callback.handleSmpEvent(succorfail, this, 100, null);
                  this.smstate.nextExpected = SM.EXPECT1;
                } else {
                  callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_CHEATED, this, 0, null);
                  this.smstate.nextExpected = SM.EXPECT1;
                  this.smstate.smProgState = SM.PROG_OK;
                }

              } else if (tlv != null) {
                callback.handleSmpEvent(OTRCallbacks.OTRL_SMPEVENT_ERROR, this, 0, null);
              }

              tlv = new TLV().find(tlvs, TLV.SMP_ABORT);
              if (tlv != null) {
                this.smstate.nextExpected = SM.EXPECT1;
              }
            }
            return stlv;
        }
        break;
      case OTRMessage.MSG_TAGGED_WHITESPACE:
        /* Start AKE */
        if (msgState.getCurState() == MsgState.ST_UNENCRYPTED) {
          auth.startAKE(null);
          if (auth.havemsgp != 0) {
            this.lastMessage = new String(auth.lastauthmsg);
            fragmentAndSend(lastMessage, Policy.FRAGMENT_SEND_ALL, callback);
            StringTLV stlv = new StringTLV();
            stlv.msg = ((TaggedPlaintextMessage) message).getStripped();
            return stlv;
          }
        } else {
          StringTLV stlv = new StringTLV();
          stlv.msg = ((TaggedPlaintextMessage) message).getStripped();
          return stlv;
        }
        break;
      case OTRMessage.MSG_NOTOTR:
        if (this.msgState.getCurState() != MsgState.ST_UNENCRYPTED
            || (policy & Policy.REQUIRE_ENCRYPTION) != 0) {
          /* Not fine.  Let the user know. */
          callback.handleMsgEvent(
              OTRCallbacks.OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED, this, message.toString());
        }
        ignore_message = 1;
        break;
      default:
        /* We received an OTR message we didn't recognize.  Ignore
         * it, but make a log entry. */
        callback.handleMsgEvent(OTRCallbacks.OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED, this, null);
        ignore_message = 1;
        break;
    }
    return null;
  }
Example #6
0
 /* Set the trust level based on the result of the SMP */
 void setSmpTrust(OTRCallbacks callback, boolean trusted) {
   this.activeFingerprint.trust = trusted ? "smp" : "";
   /* Write the new info to disk, redraw the ui, and redraw the
    * OTR buttons. */
   callback.writeFingerprints();
 }
Example #7
0
  /**
   * Handle a message about to be sent to the network. It is safe to pass all messages about to be
   * sent to this routine.
   *
   * <p>tlvs is an array of OTRTLVs to append to the private message. It is usually correct to just
   * pass null here.
   */
  public String messageSending(String message, OTRTLV[] tlvs, int fragPolicy, OTRCallbacks callback)
      throws OTRException {

    int policy = Policy.DEFAULT;

    if (message == null) throw new OTRException("MessageSending: Null argument");

    // Check the policy
    policy = callback.getOtrPolicy(this);

    // Should we go on at all?
    if ((policy & Policy.VERSION_MASK) == 0) {
      throw new OTRException("Invalid protocol");
    }

    // If this is an OTR Query message, don't encrypt it.
    OTRMessage otrmessage = OTRMessage.parse(message);
    if (otrmessage.getType() == OTRMessage.MSG_QUERY) {
      // Replace the "?OTR?" with a custom message
      QueryMessage bettermsg = defaultQueryMessage(accountName, policy);
      String ret = new String(bettermsg.getContent());
      if (fragPolicy == Policy.FRAGMENT_SEND_SKIP) return ret;
      return this.fragmentAndSend(ret, fragPolicy, callback);
    }

    switch (msgState.getCurState()) {
      case MsgState.ST_UNENCRYPTED:
        if ((policy & Policy.REQUIRE_ENCRYPTION) != 0) {
          /*
           * We're trying to send an unencrypted message with a policy
           * that disallows that. Don't do that, but try to start up OTR
           * instead.
           */
          callback.handleMsgEvent(OTRCallbacks.OTRL_MSGEVENT_ENCRYPTION_REQUIRED, this, null);
          QueryMessage bettermsg = defaultQueryMessage(accountName, policy);
          lastMessage = new String(bettermsg.getContent());
          lastSent = System.currentTimeMillis() % 1000;
          mayRetransmit = 2;
          String ret = new String(bettermsg.getContent());
          if (fragPolicy == Policy.FRAGMENT_SEND_SKIP) return ret;
          return this.fragmentAndSend(ret, fragPolicy, callback);
        } else {
          if ((policy & Policy.SEND_WHITESPACE_TAG) != 0 && otr_offer != OFFER_REJECTED) {
            /*
             * See if this user can speak OTR. Append the
             * OTR_MESSAGE_TAG to the plaintext message, and see if he
             * responds.
             */
            String taggedmsg = message + OTRL_MESSAGE_TAG_BASE + OTRL_MESSAGE_TAG_V2;
            otr_offer = OFFER_SENT;
            if (fragPolicy == Policy.FRAGMENT_SEND_SKIP) return taggedmsg;
            return this.fragmentAndSend(taggedmsg, fragPolicy, callback);
          }
        }
        break;
      case MsgState.ST_ENCRYPTED:
        // Create the new, encrypted message
        try {
          DataMessage dm = Proto.createData(this, message.getBytes(), (byte) 0, tlvs);
          lastMessage = new String(dm.getContent());
          lastSent = System.currentTimeMillis() % 1000;
          String ret = new String(dm.getContent());
          if (fragPolicy == Policy.FRAGMENT_SEND_SKIP) return ret;
          return this.fragmentAndSend(ret, fragPolicy, callback);
        } catch (OTRException e) {
          /* Uh, oh.  Whatever we do, *don't* send the message in the
           * clear. */
          callback.handleMsgEvent(OTRCallbacks.OTRL_ERRCODE_ENCRYPTION_ERROR, this, null);
          callback.errorMessage(this, OTRCallbacks.OTRL_ERRCODE_ENCRYPTION_ERROR);
          return null;
        }

      case MsgState.ST_FINISHED:
        callback.handleMsgEvent(OTRCallbacks.OTRL_MSGEVENT_CONNECTION_ENDED, this, null);
        String ret = new String(new ErrorMessage("").getContent());
        if (fragPolicy == Policy.FRAGMENT_SEND_SKIP) return ret;
        return this.fragmentAndSend(ret, fragPolicy, callback);
    }
    return null;
  }
Example #8
0
  void goEncrypted(OTRCallbacks callback) throws OTRException {

    // See if we're talking to ourselves
    byte[] theiry = auth.their_pub.serialize();
    byte[] their_trim = new byte[theiry.length - 4];
    System.arraycopy(theiry, 4, their_trim, 0, their_trim.length);
    byte[] oury = auth.our_dh.getPublicKey().serialize();
    byte[] our_trim = new byte[oury.length - 4];
    System.arraycopy(oury, 4, our_trim, 0, our_trim.length);

    if (prov.compareMPI(new MPI(their_trim), new MPI(our_trim)) == 0) {
      // Yes, we are.
      callback.handleMsgEvent(OTRCallbacks.OTRL_MSGEVENT_MSG_REFLECTED, this, null);
      throw new OTRException("Message reflected");
    }

    // Find the fingerprint
    FingerPrint found_print = this.findFingerPrint(auth.their_fingerprint, true, callback);

    /* Is this a new session or just a refresh of an existing one? */
    if (this.msgState.getCurState() == MsgState.ST_ENCRYPTED
        && Util.arrayEquals(this.activeFingerprint.fingerPrint, found_print.fingerPrint)
        && this.our_keyid - 1 == this.auth.our_keyid
        && prov.compareMPI(
                MPI.readMPI(new InBuf(this.our_old_dh_key.getPublicKey().serialize())),
                MPI.readMPI(new InBuf(this.auth.our_dh.getPublicKey().serialize())))
            == 0
        && ((this.their_keyid > 0
                && this.their_keyid == auth.their_keyid
                && prov.compareMPI(
                        MPI.readMPI(new InBuf(this.their_y.serialize())),
                        MPI.readMPI(new InBuf(this.auth.their_pub.serialize())))
                    == 0)
            || (this.their_keyid > 1
                && this.their_keyid - 1 == this.auth.their_keyid
                && this.their_old_y != null
                && prov.compareMPI(
                        MPI.readMPI(new InBuf(this.their_y.serialize())),
                        MPI.readMPI(new InBuf(this.auth.their_pub.serialize())))
                    == 0))) {
      /* This is just a refresh of the existing session. */
      callback.stillSecure(this, auth.initiated);
      ignore_message = 1;
      return;
    }

    // Copy the information from the auth into the context
    System.arraycopy(auth.secure_session_id, 0, this.sessionId, 0, 20);
    this.sessionid_len = auth.sessionid_len;

    // Copy the keys
    this.their_keyid = auth.their_keyid;
    this.their_y = auth.their_pub;
    this.their_old_y = null;

    if (our_keyid - 1 != auth.our_keyid) {
      this.our_old_dh_key = auth.our_dh;
      this.our_dh_key = prov.getDHKeyPairGenerator().generateKeyPair();
      this.our_keyid = auth.our_keyid + 1;
    }

    // Create the session keys from the DH keys
    this.sesskeys[0][0] = new DHSesskeys(prov);
    this.sesskeys[1][0] = new DHSesskeys(prov);
    this.sesskeys[0][0].computeSession(this.our_dh_key, this.their_y);
    this.sesskeys[1][0].computeSession(this.our_old_dh_key, this.their_y);

    this.generation++;
    this.activeFingerprint = found_print;
    int oldstate = msgState.getCurState();
    msgState.processEvent(MsgState.EVT_AUTHENTICATED);
    callback.updateContextList();
    if (oldstate == MsgState.ST_ENCRYPTED
        && Util.arrayEquals(this.activeFingerprint.fingerPrint, found_print.fingerPrint)) {
      callback.stillSecure(this, this.auth.initiated);
    } else {
      callback.goneSecure(this);
    }
    this.gone_encrypted = 1;
  }