Ejemplo n.º 1
0
  private String handleDataMessage(DataMessage data, List<TLV> tlvs) throws OtrException {
    logger.finest(
        getSessionID().getAccountID()
            + " received a data message from "
            + getSessionID().getUserID()
            + ".");

    switch (this.getSessionStatus()) {
      case ENCRYPTED:
        logger.finest("Message state is ENCRYPTED. Trying to decrypt message.");

        // Find matching session keys.
        int senderKeyID = data.senderKeyID;
        int receipientKeyID = data.recipientKeyID;
        SessionKeys matchingKeys = this.getSessionKeysByID(receipientKeyID, senderKeyID);

        if (matchingKeys == null) {
          throw new OtrException("no matching keys found");
        }

        // Verify received MAC with a locally calculated MAC.
        logger.finest("Transforming T to byte[] to calculate it's HmacSHA1.");

        byte[] serializedT;
        try {
          serializedT = SerializationUtils.toByteArray(data.getT());
        } catch (IOException e) {
          throw new OtrException(e);
        }

        OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl();

        byte[] computedMAC =
            otrCryptoEngine.sha1Hmac(
                serializedT,
                matchingKeys.getReceivingMACKey(),
                SerializationConstants.TYPE_LEN_MAC);

        if (!Arrays.equals(computedMAC, data.mac)) {
          throw new OtrException("MAC verification failed, ignoring message");
        }

        logger.finest("Computed HmacSHA1 value matches sent one.");

        // Mark this MAC key as old to be revealed.
        matchingKeys.setIsUsedReceivingMACKey(true);

        matchingKeys.setReceivingCtr(data.ctr);

        byte[] dmc =
            otrCryptoEngine.aesDecrypt(
                matchingKeys.getReceivingAESKey(),
                matchingKeys.getReceivingCtr(),
                data.encryptedMessage);
        String decryptedMsgContent;
        try {
          // Expect bytes to be text encoded in UTF-8.
          decryptedMsgContent = new String(dmc, "UTF-8");
        } catch (UnsupportedEncodingException e) {
          throw new OtrException(e);
        }

        logger.finest("Decrypted message: \"" + decryptedMsgContent + "\"");
        // FIXME extraKey = authContext.getExtraSymmetricKey();

        // Rotate keys if necessary.
        SessionKeys mostRecent = this.getMostRecentSessionKeys();
        if (mostRecent.getLocalKeyID() == receipientKeyID) this.rotateLocalSessionKeys();

        if (mostRecent.getRemoteKeyID() == senderKeyID) this.rotateRemoteSessionKeys(data.nextDH);

        // Handle TLVs
        if (tlvs == null) {
          tlvs = new ArrayList<TLV>();
        }

        int tlvIndex = decryptedMsgContent.indexOf((char) 0x0);
        if (tlvIndex > -1) {
          decryptedMsgContent = decryptedMsgContent.substring(0, tlvIndex);
          tlvIndex++;
          byte[] tlvsb = new byte[dmc.length - tlvIndex];
          System.arraycopy(dmc, tlvIndex, tlvsb, 0, tlvsb.length);

          ByteArrayInputStream tin = new ByteArrayInputStream(tlvsb);
          while (tin.available() > 0) {
            int type;
            byte[] tdata;
            OtrInputStream eois = new OtrInputStream(tin);
            try {
              type = eois.readShort();
              tdata = eois.readTlvData();
              eois.close();
            } catch (IOException e) {
              throw new OtrException(e);
            }

            tlvs.add(new TLV(type, tdata));
          }
        }
        if (tlvs.size() > 0) {
          for (TLV tlv : tlvs) {
            switch (tlv.getType()) {
              case TLV.DISCONNECTED:
                this.setSessionStatus(SessionStatus.FINISHED);
                return null;
              default:
                for (OtrTlvHandler handler : tlvHandlers) {
                  handler.processTlv(tlv);
                }
            }
          }
        }

        return decryptedMsgContent;

      case FINISHED:
      case PLAINTEXT:
        showError("Unreadable encrypted message was received.");

        injectMessage(
            new ErrorMessage(
                AbstractMessage.MESSAGE_ERROR, "You sent me an unreadable encrypted message"));
        throw new OtrException("Unreadable encrypted message received");
    }

    return null;
  }