예제 #1
0
  /* Receive initial packet (key exchange). */
  public void receiveInitialPacket() throws DespotifyException {
    byte[] buffer = new byte[512];
    int ret, paddingLength, usernameLength;

    /* Save initial server packet for auth hmac generation. 1024 bytes should be enough. */
    ByteBuffer serverPacketBuffer = ByteBuffer.allocate(1024);

    /* Read server random (first 2 bytes). */
    if ((ret = this.receive(this.session.serverRandom, 0, 2, "server random packet")) == -1) {
      throw new DespotifyException("Failed to read server random.");
    }

    /* Check if we got a status message. */
    if (this.session.serverRandom[0] != 0x00 || ret != 2) {

      int errorCode;

      /*
       * Substatuses:
       * 0x01    : Client upgrade required.
       * 0x03    : Non-existant user.
       * 0x04    : Account has been disabled.
       * 0x06    : You need to complete your account details.
       * 0x09    : Your current country doesn't match that set in your profile.
       * Default : Unknown error
       */
      StringBuilder message = new StringBuilder(250);

      switch (this.session.serverRandom[1]) {
        case 0x01:
          message.append("Client upgrade required: ");
        case 0x03:
          message.append("Non-existant user.");
        case 0x04:
          message.append("Account has been disabled.");
        case 0x06:
          message.append("You need to complete your account details.");
        case 0x09:
          message.append("Your current country doesn't match that set in your profile.");
      }
      if (message.length() == 0) {
        message.append("Unknown error.");
      }

      /* If substatus is 'Client upgrade required', read upgrade URL. */
      if (this.session.serverRandom[1] == 0x01) {
        if ((ret = this.receive(buffer, 0x11a, "text message length")) > 0) {
          paddingLength = buffer[0x119] & 0xFF;

          if ((ret = this.receive(buffer, paddingLength, "text message")) > 0) {
            message.append(new String(Arrays.copyOfRange(buffer, 0, ret)));
          }
        }
      }

      message.append(" (").append(String.valueOf(ret)).append(")");

      throw new AuthenticationException(message.toString());
    }

    /* Read server random (next 14 bytes). */
    if ((ret = this.receive(this.session.serverRandom, 2, 14, "14 random  server bytes")) != 14) {
      throw new DespotifyException("Failed to read server random. (" + ret + ")");
    }

    /* Save server random to packet buffer. */
    serverPacketBuffer.put(this.session.serverRandom);

    /* Read server public key (Diffie Hellman key exchange). */
    if ((ret = this.receive(buffer, 96, "public server key")) != 96) {
      throw new DespotifyException("Failed to read server public key. (" + ret + ")");
    }

    /* Save DH public key to packet buffer. */
    serverPacketBuffer.put(buffer, 0, 96);

    /*
     * Convert key, which is in raw byte form to a DHPublicKey
     * using the DHParameterSpec (for P and G values) of our
     * public key. Y value is taken from raw bytes.
     */
    this.session.dhServerPublicKey =
        DH.bytesToPublicKey(
            this.session.dhClientKeyPair.getPublicKey().getParams(),
            Arrays.copyOfRange(buffer, 0, 96));

    /* Read server blob (256 bytes). */
    if ((ret = this.receive(this.session.serverBlob, 0, 256, "server blob")) != 256) {
      throw new DespotifyException("Failed to read server blob. (" + ret + ")");
    }

    /* Save RSA signature to packet buffer. */
    serverPacketBuffer.put(this.session.serverBlob);

    /* Read salt (10 bytes). */
    if ((ret = this.receive(this.session.salt, 0, 10, "salt")) != 10) {
      throw new DespotifyException("Failed to read salt. (" + ret + ")");
    }

    /* Save salt to packet buffer. */
    serverPacketBuffer.put(this.session.salt);

    /* Read padding length (1 byte). */
    if ((paddingLength = this.receive("padding length")) == -1) {
      throw new DespotifyException("Failed to read paddling length.");
    }

    /* Save padding length to packet buffer. */
    serverPacketBuffer.put((byte) paddingLength);

    /* Check if padding length is valid. */
    if (paddingLength <= 0) {
      throw new DespotifyException("Padding length is negative or zero.");
    }

    /* Read username length. */
    if ((usernameLength = this.receive("")) == -1) {
      throw new DespotifyException("Failed to read username length.");
    }

    /* Save username length to packet buffer. */
    serverPacketBuffer.put((byte) usernameLength);

    /* Read lengths of puzzle challenge and unknown fields */
    this.receive(buffer, 8, "length of puzzle challenge + length of 3 unknown fields");

    /* Save bytes to packet buffer. */
    serverPacketBuffer.put(buffer, 0, 8);

    /* Get lengths of puzzle challenge and unknown fields.  */
    ByteBuffer dataBuffer = ByteBuffer.wrap(buffer, 0, 8);
    int puzzleChallengeLength = dataBuffer.getShort();
    int unknownLength1 = dataBuffer.getShort();
    int unknownLength2 = dataBuffer.getShort();
    int unknownLength3 = dataBuffer.getShort();

    /* Read padding. */
    if ((ret = this.receive(buffer, paddingLength, "padding")) != paddingLength) {
      throw new DespotifyException("Failed to read padding. (" + ret + ")");
    }

    /* Save padding (random bytes) to packet buffer. */
    serverPacketBuffer.put(buffer, 0, paddingLength);

    /* Read username into buffer and copy it to 'session.username'. */
    if ((ret = this.receive(buffer, usernameLength, "username")) != usernameLength) {
      throw new DespotifyException("Failed to read username. (" + ret + ")");
    }

    /* Save username to packet buffer. */
    serverPacketBuffer.put(buffer, 0, usernameLength);

    /* Save username to session. */
    this.session.username = Arrays.copyOfRange(buffer, 0, usernameLength);

    /* Receive puzzle challenge and unknown bytes. */
    this.receive(buffer, 0, puzzleChallengeLength, "puzzle challange data");
    this.receive(buffer, puzzleChallengeLength, unknownLength1, "unknown field 1");
    this.receive(buffer, puzzleChallengeLength + unknownLength1, unknownLength2, "unknown field 2");
    this.receive(
        buffer,
        puzzleChallengeLength + unknownLength1 + unknownLength2,
        unknownLength3,
        "unknown field 3");

    /* Save to packet buffer. */
    serverPacketBuffer.put(
        buffer, 0, puzzleChallengeLength + unknownLength1 + unknownLength2 + unknownLength3);
    serverPacketBuffer.flip();

    /* Write data from packet buffer to byte array. */
    this.session.initialServerPacket = new byte[serverPacketBuffer.remaining()];

    serverPacketBuffer.get(this.session.initialServerPacket);

    /* Wrap buffer in order to get values. */
    dataBuffer =
        ByteBuffer.wrap(
            buffer, 0, puzzleChallengeLength + unknownLength1 + unknownLength2 + unknownLength3);

    /* Get puzzle denominator and magic. */
    if (dataBuffer.get() == 0x01) {
      this.session.puzzleDenominator = dataBuffer.get();
      this.session.puzzleMagic = dataBuffer.getInt();
    } else {
      throw new DespotifyException("Unexpected puzzle challenge.");
    }
  }