Я пытаюсь реализовать возможность обфускации транспорта MTProto, описанную здесь . Я следовал инструкциям по буквам, но безрезультатно: данные отправляются, например, для ReqPqMulti
, но после прочтения ответа, например, ResPQ
, входной поток блокируется навсегда, что означает, что данные не принимаются.
Полезные данные инициализации и шифр AES создаются следующим образом. См. Также комментарии.
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)
}
Шифр AES-CTR инициализируется с использованием
private val encryptionCipher = Cipher.getInstance("AES/CTR/NoPadding")
init {
encryptionCipher.init(
Cipher.ENCRYPT_MODE,
SecretKeySpec(encryptionKey, "AES"),
IvParameterSpec(encryptionIV)
)
}
Использование сокращенного транспорта (не обфусцированного) работает нормально.