Telegram TCP obfuscated transport not receiving data

268 Views Asked by At

I'm trying to implement the MTProto transport obfuscation capability described here.
I've followed instructions letter per letter, to no avail: data is sent, e.g. for ReqPqMulti, but upon reading the response, e.g. ResPQ, the input stream blocks forever, which means no data is received.

The initialization payload and the AES Cipher are created as follow. See also comments.

fun buildInitPayload(header: Byte?): Pair<AES, ByteArray> {
   // Add the padded transport header to the reserved words
   val reservedWords = if (header != null) {
      reservedWords + byteArrayOf(header, header, header, header)
   } else {
      reservedWords
   }
   
   val primaryPayload = ByteArray(64)
   val secureRandom = SecureRandom()

   // Generate 64-byte random initialization payload
   do {
      secureRandom.nextBytes(primaryPayload)
   } while (!isInitPayloadValid(reservedWords, primaryPayload))

   if (header != null) {
      primaryPayload[56] = header
      primaryPayload[57] = header
      primaryPayload[58] = header
      primaryPayload[59] = header
   }

   // Extract two keys from both initialization payloads, using bytes at offsets 8-40:
   // the key extracted from the primary payload is used as encryption key
   val encryptionKey = primaryPayload.copyOfRange(8, 40)

   // Generate a secondary initialization payload by reversing the primary payload
   val secondaryPayload = ByteArray(48)
   for (i in 0..47) secondaryPayload[i] = primaryPayload[55 - i]

   // The key extracted from the secondary payload is used as decryption key
   val decryptionKey = secondaryPayload.copyOf(32)

   // Extract two IVs from both initialization payloads, using bytes at offsets 40-56:
   // the IV extracted from the primary payload is used as encryption IV,
   // the IV extracted from the secondary payload is used as decryption IV.
   val encryptionIV = primaryPayload.copyOfRange(40, 56)
   val decryptionIV = secondaryPayload.copyOfRange(32, 48)

   val aes = AES(encryptionKey, encryptionIV, decryptionKey, decryptionIV)
   val encryptedPayload = aes.encryptCTR(primaryPayload)

   return aes to primaryPayload.copyOf(56) + encryptedPayload.copyFrom(56)
}

The AES-CTR Cipher is initialized using

private val encryptionCipher = Cipher.getInstance("AES/CTR/NoPadding")

init {
   encryptionCipher.init(
      Cipher.ENCRYPT_MODE,
      SecretKeySpec(encryptionKey, "AES"),
      IvParameterSpec(encryptionIV)
   )
}

Using the Abridged transport (non-obfuscated) works fine.

1

There are 1 best solutions below

0
On

If using the abridged transport works and the obfuscated transport simply never respond it's likely you've missed the padding needed for the padded intermediate transport with obfuscation as described here: https://core.telegram.org/mtproto/mtproto-transports#padded-intermediate