예제 #1
0
  public void mergeServerSalts(int date, ArrayList<TLRPC.TL_futureSalt> salts) {
    if (salts == null) {
      return;
    }
    ArrayList<Long> existingSalts = new ArrayList<Long>(authServerSaltSet.size());

    for (ServerSalt salt : authServerSaltSet) {
      existingSalts.add(salt.value);
    }
    for (TLRPC.TL_futureSalt saltDesc : salts) {
      long salt = saltDesc.salt;
      if (!existingSalts.contains(salt) && saltDesc.valid_until > date) {
        ServerSalt serverSalt = new ServerSalt();
        serverSalt.validSince = saltDesc.valid_since;
        serverSalt.validUntil = saltDesc.valid_until;
        serverSalt.value = salt;
        authServerSaltSet.add(serverSalt);
      }
    }
    Collections.sort(authServerSaltSet, new SaltComparator());
  }
예제 #2
0
  public Datacenter(SerializedData data, int version) {
    if (version == 0) {
      datacenterId = data.readInt32();
      String address = data.readString();
      addresses.add(address);
      int port = data.readInt32();
      ports.put(address, port);
      int len = data.readInt32();
      if (len != 0) {
        authKey = data.readData(len);
      }
      len = data.readInt32();
      if (len != 0) {
        authKeyId = data.readInt64();
      }
      authorized = data.readInt32() != 0;
      len = data.readInt32();
      for (int a = 0; a < len; a++) {
        ServerSalt salt = new ServerSalt();
        salt.validSince = data.readInt32();
        salt.validUntil = data.readInt32();
        salt.value = data.readInt64();
        if (authServerSaltSet == null) {
          authServerSaltSet = new ArrayList<ServerSalt>();
        }
        authServerSaltSet.add(salt);
      }
    } else if (version == 1) {
      int currentVersion = data.readInt32();
      if (currentVersion == 2 || currentVersion == 3 || currentVersion == 4) {
        datacenterId = data.readInt32();
        if (currentVersion >= 3) {
          lastInitVersion = data.readInt32();
        }
        int len = data.readInt32();
        for (int a = 0; a < len; a++) {
          String address = data.readString();
          addresses.add(address);
          ports.put(address, data.readInt32());
        }

        len = data.readInt32();
        if (len != 0) {
          authKey = data.readData(len);
        }
        if (currentVersion == 4) {
          authKeyId = data.readInt64();
        } else {
          len = data.readInt32();
          if (len != 0) {
            authKeyId = data.readInt64();
          }
        }
        authorized = data.readInt32() != 0;
        len = data.readInt32();
        for (int a = 0; a < len; a++) {
          ServerSalt salt = new ServerSalt();
          salt.validSince = data.readInt32();
          salt.validUntil = data.readInt32();
          salt.value = data.readInt64();
          if (authServerSaltSet == null) {
            authServerSaltSet = new ArrayList<ServerSalt>();
          }
          authServerSaltSet.add(salt);
        }
      }
    } else if (version == 2) {

    }
    readCurrentAddressAndPortNum();
  }
예제 #3
0
  void processMessage(TLObject message, long messageId) {
    if (message instanceof TLRPC.TL_resPQ) {
      if (processedPQRes) {
        TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
        msgsAck.msg_ids = new ArrayList<Long>();
        msgsAck.msg_ids.add(messageId);
        sendMessageData(msgsAck, generateMessageId());
        return;
      }

      processedPQRes = true;
      final TLRPC.TL_resPQ resPq = (TLRPC.TL_resPQ) message;
      if (Arrays.equals(authNonce, resPq.nonce)) {
        final HashMap<String, Object> publicKey =
            selectPublicKey(resPq.server_public_key_fingerprints);
        if (publicKey == null) {
          Log.e("tmessages", "***** Couldn't find valid server public key");
          beginHandshake(false);
          return;
        }

        authServerNonce = resPq.server_nonce;

        ByteBuffer data = ByteBuffer.wrap(resPq.pq);
        final long pqf = data.getLong();
        final long messageIdf = messageId;
        Utilities.globalQueue.postRunnable(
            new Runnable() {
              @Override
              public void run() {
                final Utilities.TPFactorizedValue factorizedPq = Utilities.getFactorizedValue(pqf);

                Utilities.stageQueue.postRunnable(
                    new Runnable() {
                      @Override
                      public void run() {
                        ByteBuffer pBytes = ByteBuffer.allocate(4);
                        pBytes.putInt((int) factorizedPq.p);
                        byte[] pData = pBytes.array();

                        ByteBuffer qBytes = ByteBuffer.allocate(4);
                        qBytes.putInt((int) factorizedPq.q);
                        byte[] qData = qBytes.array();

                        TLRPC.TL_req_DH_params reqDH = new TLRPC.TL_req_DH_params();
                        reqDH.nonce = authNonce;
                        reqDH.server_nonce = authServerNonce;
                        reqDH.p = pData;
                        reqDH.q = qData;
                        reqDH.public_key_fingerprint = (Long) publicKey.get("fingerprint");

                        SerializedData os = new SerializedData();

                        TLRPC.TL_p_q_inner_data innerData = new TLRPC.TL_p_q_inner_data();
                        innerData.nonce = authNonce;
                        innerData.server_nonce = authServerNonce;
                        innerData.pq = resPq.pq;
                        innerData.p = reqDH.p;
                        innerData.q = reqDH.q;

                        byte[] nonceBytes = new byte[32];
                        for (int a = 0; a < 32; a++) {
                          nonceBytes[a] = (byte) (MessagesController.random.nextDouble() * 255);
                        }
                        innerData.new_nonce = authNewNonce = nonceBytes;
                        innerData.serializeToStream(os);

                        byte[] innerDataBytes = os.toByteArray();

                        SerializedData dataWithHash = new SerializedData();
                        dataWithHash.writeRaw(Utilities.computeSHA1(innerDataBytes));
                        dataWithHash.writeRaw(innerDataBytes);
                        while (dataWithHash.length() < 255) {
                          dataWithHash.writeByte(0);
                        }

                        byte[] encryptedBytes =
                            Utilities.encryptWithRSA(
                                (BigInteger[]) publicKey.get("key"), dataWithHash.toByteArray());
                        SerializedData encryptedData = new SerializedData();
                        encryptedData.writeRaw(encryptedBytes);
                        if (encryptedData.length() < 256) {
                          SerializedData newEncryptedData = new SerializedData();
                          for (int i = 0; i < 256 - encryptedData.length(); i++) {
                            newEncryptedData.writeByte(0);
                          }
                          newEncryptedData.writeRaw(encryptedData.toByteArray());
                          encryptedData = newEncryptedData;
                        }
                        reqDH.encrypted_data = encryptedData.toByteArray();

                        TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
                        msgsAck.msg_ids = new ArrayList<Long>();
                        msgsAck.msg_ids.add(messageIdf);
                        sendMessageData(msgsAck, generateMessageId());

                        reqPQMsgData = null;
                        reqDHMsgData = sendMessageData(reqDH, generateMessageId());
                      }
                    });
              }
            });
      } else {
        Log.e("tmessages", "***** Error: invalid handshake nonce");
        beginHandshake(false);
      }
    } else if (message instanceof TLRPC.Server_DH_Params) {
      if (message instanceof TLRPC.TL_server_DH_params_ok) {
        TLRPC.TL_server_DH_params_ok serverDhParams = (TLRPC.TL_server_DH_params_ok) message;

        SerializedData tmpAesKey = new SerializedData();

        SerializedData newNonceAndServerNonce = new SerializedData();
        newNonceAndServerNonce.writeRaw(authNewNonce);
        newNonceAndServerNonce.writeRaw(authServerNonce);

        SerializedData serverNonceAndNewNonce = new SerializedData();
        serverNonceAndNewNonce.writeRaw(authServerNonce);
        serverNonceAndNewNonce.writeRaw(authNewNonce);
        tmpAesKey.writeRaw(Utilities.computeSHA1(newNonceAndServerNonce.toByteArray()));

        byte[] serverNonceAndNewNonceHash =
            Utilities.computeSHA1(serverNonceAndNewNonce.toByteArray());
        byte[] serverNonceAndNewNonceHash0_12 = new byte[12];
        System.arraycopy(serverNonceAndNewNonceHash, 0, serverNonceAndNewNonceHash0_12, 0, 12);

        tmpAesKey.writeRaw(serverNonceAndNewNonceHash0_12);

        SerializedData tmpAesIv = new SerializedData();

        byte[] serverNonceAndNewNonceHash12_8 = new byte[8];
        System.arraycopy(serverNonceAndNewNonceHash, 12, serverNonceAndNewNonceHash12_8, 0, 8);
        tmpAesIv.writeRaw(serverNonceAndNewNonceHash12_8);

        SerializedData newNonceAndNewNonce = new SerializedData();
        newNonceAndNewNonce.writeRaw(authNewNonce);
        newNonceAndNewNonce.writeRaw(authNewNonce);
        tmpAesIv.writeRaw(Utilities.computeSHA1(newNonceAndNewNonce.toByteArray()));

        byte[] newNonce0_4 = new byte[4];
        System.arraycopy(authNewNonce, 0, newNonce0_4, 0, 4);
        tmpAesIv.writeRaw(newNonce0_4);

        byte[] answerWithHash =
            Utilities.aesIgeEncryption(
                serverDhParams.encrypted_answer,
                tmpAesKey.toByteArray(),
                tmpAesIv.toByteArray(),
                false,
                false);
        byte[] answerHash = new byte[20];
        System.arraycopy(answerWithHash, 0, answerHash, 0, 20);

        byte[] answerData = new byte[answerWithHash.length - 20];
        System.arraycopy(answerWithHash, 20, answerData, 0, answerWithHash.length - 20);
        boolean hashVerified = false;
        for (int i = 0; i < 16; i++) {
          byte[] computedAnswerHash = Utilities.computeSHA1(answerData);
          if (Arrays.equals(computedAnswerHash, answerHash)) {
            hashVerified = true;
            break;
          }
          byte[] answerData2 = new byte[answerData.length - 1];
          System.arraycopy(answerData, 0, answerData2, 0, answerData.length - 1);
          answerData = answerData2;
        }

        if (!hashVerified) {
          Log.e("tmessages", "***** Couldn't decode DH params");
          beginHandshake(false);
          return;
        }

        SerializedData answerIs = new SerializedData(answerData);
        int constructor = answerIs.readInt32();
        TLRPC.TL_server_DH_inner_data dhInnerData =
            (TLRPC.TL_server_DH_inner_data)
                TLClassStore.Instance().TLdeserialize(answerIs, constructor);

        if (!(dhInnerData instanceof TLRPC.TL_server_DH_inner_data)) {
          Log.e("tmessages", "***** Couldn't parse decoded DH params");
          beginHandshake(false);
          return;
        }

        if (!Arrays.equals(authNonce, dhInnerData.nonce)) {
          Log.e("tmessages", "***** Invalid DH nonce");
          beginHandshake(false);
          return;
        }
        if (!Arrays.equals(authServerNonce, dhInnerData.server_nonce)) {
          Log.e("tmessages", "***** Invalid DH server nonce");
          beginHandshake(false);
          return;
        }

        byte[] b = new byte[256];
        for (int a = 0; a < 256; a++) {
          b[a] = (byte) (MessagesController.random.nextDouble() * 255);
        }

        BigInteger i_g_b = BigInteger.valueOf(dhInnerData.g);
        i_g_b = i_g_b.modPow(new BigInteger(1, b), new BigInteger(1, dhInnerData.dh_prime));
        byte[] g_b = i_g_b.toByteArray();

        BigInteger i_authKey = new BigInteger(1, dhInnerData.g_a);
        i_authKey = i_authKey.modPow(new BigInteger(1, b), new BigInteger(1, dhInnerData.dh_prime));

        authKey = i_authKey.toByteArray();
        if (authKey.length > 256) {
          byte[] correctedAuth = new byte[256];
          System.arraycopy(authKey, 1, correctedAuth, 0, 256);
          authKey = correctedAuth;
        } else if (authKey.length < 256) {
          byte[] correctedAuth = new byte[256];
          System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length);
          for (int a = 0; a < 256 - authKey.length; a++) {
            authKey[a] = 0;
          }
          authKey = correctedAuth;
        }
        byte[] authKeyHash = Utilities.computeSHA1(authKey);
        authKeyId = new byte[8];
        System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8);

        SerializedData serverSaltData = new SerializedData();
        for (int i = 7; i >= 0; i--) {
          byte a_ = authNewNonce[i];
          byte b_ = authServerNonce[i];
          byte x = (byte) (a_ ^ b_);
          serverSaltData.writeByte(x);
        }
        ByteBuffer saltBuffer = ByteBuffer.wrap(serverSaltData.toByteArray());

        timeDifference = dhInnerData.server_time - (int) (System.currentTimeMillis() / 1000);

        serverSalt = new ServerSalt();
        serverSalt.validSince = (int) (System.currentTimeMillis() / 1000) + timeDifference;
        serverSalt.validUntil =
            (int) (System.currentTimeMillis() / 1000) + timeDifference + 30 * 60;
        serverSalt.value = saltBuffer.getLong();

        if (ConnectionsManager.DEBUG_VERSION) {
          Log.d("tmessages", String.format(Locale.US, "===== Time difference: %d", timeDifference));
        }

        TLRPC.TL_client_DH_inner_data clientInnerData = new TLRPC.TL_client_DH_inner_data();
        clientInnerData.nonce = authNonce;
        clientInnerData.server_nonce = authServerNonce;
        clientInnerData.g_b = g_b;
        clientInnerData.retry_id = 0;
        SerializedData os = new SerializedData();
        clientInnerData.serializeToStream(os);
        byte[] clientInnerDataBytes = os.toByteArray();

        SerializedData clientDataWithHash = new SerializedData();
        clientDataWithHash.writeRaw(Utilities.computeSHA1(clientInnerDataBytes));
        clientDataWithHash.writeRaw(clientInnerDataBytes);
        while (clientDataWithHash.length() % 16 != 0) {
          clientDataWithHash.writeByte(0);
        }

        TLRPC.TL_set_client_DH_params setClientDhParams = new TLRPC.TL_set_client_DH_params();
        setClientDhParams.nonce = authNonce;
        setClientDhParams.server_nonce = authServerNonce;
        setClientDhParams.encrypted_data =
            Utilities.aesIgeEncryption(
                clientDataWithHash.toByteArray(),
                tmpAesKey.toByteArray(),
                tmpAesIv.toByteArray(),
                true,
                false);

        TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
        msgsAck.msg_ids = new ArrayList<Long>();
        msgsAck.msg_ids.add(messageId);
        sendMessageData(msgsAck, generateMessageId());

        reqDHMsgData = null;
        setClientDHParamsMsgData = sendMessageData(setClientDhParams, generateMessageId());
      } else {
        Log.e("tmessages", "***** Couldn't set DH params");
        beginHandshake(false);
      }
    } else if (message instanceof TLRPC.Set_client_DH_params_answer) {
      TLRPC.Set_client_DH_params_answer dhAnswer = (TLRPC.Set_client_DH_params_answer) message;

      if (!Arrays.equals(authNonce, dhAnswer.nonce)) {
        Log.e("tmessages", "***** Invalid DH answer nonce");
        beginHandshake(false);
        return;
      }
      if (!Arrays.equals(authServerNonce, dhAnswer.server_nonce)) {
        Log.e("tmessages", "***** Invalid DH answer server nonce");
        beginHandshake(false);
        return;
      }

      reqDHMsgData = null;

      TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
      msgsAck.msg_ids = new ArrayList<Long>();
      msgsAck.msg_ids.add(messageId);
      sendMessageData(msgsAck, generateMessageId());

      byte[] authKeyAuxHashFull = Utilities.computeSHA1(authKey);
      byte[] authKeyAuxHash = new byte[8];
      System.arraycopy(authKeyAuxHashFull, 0, authKeyAuxHash, 0, 8);

      SerializedData newNonce1 = new SerializedData();
      newNonce1.writeRaw(authNewNonce);
      newNonce1.writeByte(1);
      newNonce1.writeRaw(authKeyAuxHash);
      byte[] newNonceHash1Full = Utilities.computeSHA1(newNonce1.toByteArray());
      byte[] newNonceHash1 = new byte[16];
      System.arraycopy(newNonceHash1Full, newNonceHash1Full.length - 16, newNonceHash1, 0, 16);

      SerializedData newNonce2 = new SerializedData();
      newNonce2.writeRaw(authNewNonce);
      newNonce2.writeByte(2);
      newNonce2.writeRaw(authKeyAuxHash);
      byte[] newNonceHash2Full = Utilities.computeSHA1(newNonce2.toByteArray());
      byte[] newNonceHash2 = new byte[16];
      System.arraycopy(newNonceHash2Full, newNonceHash2Full.length - 16, newNonceHash2, 0, 16);

      SerializedData newNonce3 = new SerializedData();
      newNonce3.writeRaw(authNewNonce);
      newNonce3.writeByte(3);
      newNonce3.writeRaw(authKeyAuxHash);
      byte[] newNonceHash3Full = Utilities.computeSHA1(newNonce3.toByteArray());
      byte[] newNonceHash3 = new byte[16];
      System.arraycopy(newNonceHash3Full, newNonceHash3Full.length - 16, newNonceHash3, 0, 16);

      if (message instanceof TLRPC.TL_dh_gen_ok) {
        TLRPC.TL_dh_gen_ok dhGenOk = (TLRPC.TL_dh_gen_ok) message;
        if (!Arrays.equals(newNonceHash1, dhGenOk.new_nonce_hash1)) {
          Log.e("tmessages", "***** Invalid DH answer nonce hash 1");
          beginHandshake(false);
          return;
        }

        Log.d("tmessages", String.format("Handshake with DC%d completed", datacenter.datacenterId));
        datacenter.connection.delegate = null;

        final Action parent = this;
        Utilities.stageQueue.postRunnable(
            new Runnable() {
              @Override
              public void run() {
                datacenter.authKey = authKey;
                datacenter.authKeyId = authKeyId;
                datacenter.addServerSalt(serverSalt);
                HashMap<String, Object> resultDict = new HashMap<String, Object>();
                resultDict.put("timeDifference", timeDifference);
                if (delegate != null) {
                  delegate.ActionDidFinishExecution(parent, resultDict);
                }
              }
            });
      } else if (message instanceof TLRPC.TL_dh_gen_retry) {
        TLRPC.TL_dh_gen_retry dhRetry = (TLRPC.TL_dh_gen_retry) message;
        if (!Arrays.equals(newNonceHash2, dhRetry.new_nonce_hash2)) {
          Log.e("tmessages", "***** Invalid DH answer nonce hash 2");
          beginHandshake(false);
          return;
        }
        Log.d("tmessages", "***** Retry DH");
        beginHandshake(false);
      } else if (message instanceof TLRPC.TL_dh_gen_fail) {
        TLRPC.TL_dh_gen_fail dhFail = (TLRPC.TL_dh_gen_fail) message;
        if (!Arrays.equals(newNonceHash3, dhFail.new_nonce_hash3)) {
          Log.e("tmessages", "***** Invalid DH answer nonce hash 3");
          beginHandshake(false);
          return;
        }
        Log.d("tmessages", "***** Server declined DH params");
        beginHandshake(false);
      } else {
        Log.e("tmessages", "***** Unknown DH params response");
        beginHandshake(false);
      }
    } else {
      TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
      msgsAck.msg_ids = new ArrayList<Long>();
      msgsAck.msg_ids.add(messageId);
      sendMessageData(msgsAck, generateMessageId());
    }
  }