Несогласованность SSL-квитирования в Android по сравнению с JVMAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Несогласованность SSL-квитирования в Android по сравнению с JVM

Сообщение Anonymous »

Я новичок в программировании сокетов и пытаюсь подключиться к WhatsApp WebSocket в приложении Android. Ниже приведен код Kotlin, который я написал для выполнения SSL-квитирования. Тот же код успешно выполняется в среде JVM, но не выполняется при выполнении на Android. Я пробую это только на устройствах Android 14.
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import java.io.EOFException
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.AsynchronousSocketChannel
import java.nio.channels.CompletionHandler
import java.util.Base64
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLEngine
import javax.net.ssl.SSLEngineResult
import javax.net.ssl.SSLEngineResult.Status

object WhatsappTryHandshake {

const val WEB_SOCKET_HOST: String = "web.whatsapp.com"
const val WEB_SOCKET_PORT: Int = 443
const val KEY_LENGTH = 16

lateinit var socketChannel: AsynchronousSocketChannel
lateinit var sslEngine: SSLEngine
lateinit var clientKey: String
lateinit var sslReadBuffer: ByteBuffer
lateinit var netDataWrite: ByteBuffer
lateinit var sslOutputBuffer: ByteBuffer
private var isHandshakeCompleted = false

suspend fun connectToWhatsAppWebSocket() {

clientKey = Base64.getEncoder().encodeToString(ByteArray(KEY_LENGTH).apply { java.util.Random().nextBytes(this) })

// SSL context for secure connection
val sslContext = SSLContext.getInstance("TLSv1.3")
sslContext.init(null, null, null)

socketChannel = AsynchronousSocketChannel.open()
val address = InetSocketAddress(WEB_SOCKET_HOST, WEB_SOCKET_PORT)
socketChannel.connect(address).get()

// Set up SSL Engine
sslEngine = sslContext.createSSLEngine(WEB_SOCKET_HOST, WEB_SOCKET_PORT)
sslEngine.useClientMode = true
sslEngine.beginHandshake()

// SSL Handshake
netDataWrite = ByteBuffer.allocate(sslEngine.session.packetBufferSize)
sslReadBuffer = ByteBuffer.allocate(sslEngine.session.packetBufferSize)
sslReadBuffer.position(sslReadBuffer.limit())
sslOutputBuffer = ByteBuffer.allocate(sslEngine.session.packetBufferSize)
doHandshake()
}

private fun doHandshake(status: Status? = null) {

println("${sslEngine.handshakeStatus}")
when (sslEngine.handshakeStatus) {
SSLEngineResult.HandshakeStatus.NEED_WRAP -> {
netDataWrite.clear()
val result = sslEngine.wrap(sslOutputBuffer, netDataWrite)
val isHandshakeFinished = isHandshakeFinished(result, true)
netDataWrite.flip()

socketChannel.write(netDataWrite, null, object : CompletionHandler{
override fun completed(result: Int?, attachment: Any?) {
println("completed: $result")

if (isHandshakeFinished){
finishSslHandshake()
}else{
doHandshake()
}
}

override fun failed(exc: Throwable?, attachment: Any?) {
println("failed: ${exc?.message}")
}
})

}
SSLEngineResult.HandshakeStatus.NEED_UNWRAP -> {
sslReadBuffer.compact()
if (status != Status.BUFFER_UNDERFLOW && sslReadBuffer.position() != 0){
sslReadBuffer.flip()
doSSlHandshakeUnwrapOperation()
}else{

readPlain(sslReadBuffer, true){
doSSlHandshakeUnwrapOperation()
}
}

}
SSLEngineResult.HandshakeStatus.FINISHED -> {
finishSslHandshake()
}
SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING -> {
finishSslHandshake()
println("Cannot complete Handshake")
}
SSLEngineResult.HandshakeStatus.NEED_TASK -> {
var runnable: Runnable? = sslEngine.delegatedTask
while (runnable != null) {
runnable.run()
runnable = sslEngine.delegatedTask
}

println("Handshake Status " + sslEngine.handshakeStatus )
doHandshake()
}
else -> throw IllegalStateException("Unknown handshake status")
}
}

private fun doSSlHandshakeUnwrapOperation() {
try {
val result: SSLEngineResult = sslEngine.unwrap(sslReadBuffer, sslOutputBuffer)
println(result.toString())
if (isHandshakeFinished(result, false)) {
finishSslHandshake()
} else {
doHandshake(result.status)
}
} catch (throwable: Throwable) {
throwable.printStackTrace()
finishSslHandshake()
}
}

private fun finishSslHandshake() {
isHandshakeCompleted = true
sslOutputBuffer.clear()
}

private fun isHandshakeFinished(result: SSLEngineResult, wrap: Boolean): Boolean {
val sslEngineStatus = result.status
check(!(sslEngineStatus != SSLEngineResult.Status.OK && (wrap || sslEngineStatus != SSLEngineResult.Status.BUFFER_UNDERFLOW))) { "SSL handshake operation failed with status: $sslEngineStatus" }

check(!(wrap && result.bytesConsumed() != 0)) {
throw IllegalStateException("SSL handshake operation failed with status: no bytes consumed")
}

check(!(!wrap && result.bytesProduced() != 0)) { throw IllegalStateException("SSL handshake operation failed with status: no bytes produced") }

val sslHandshakeStatus = result.handshakeStatus
return sslHandshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED
}

private fun readPlain(buffer: ByteBuffer, lastRead: Boolean, proceed: () -> Unit) {
val outerCaller = RuntimeException()
socketChannel.read(buffer, null, object : CompletionHandler {
override fun completed(bytesRead: Int, attachment: Any?) {
if (bytesRead == -1) {
val eof = EOFException()
eof.addSuppressed(outerCaller)
println("Failed: ${eof.message}")
return
}

if (lastRead) {
buffer.flip()
}
proceed()
}

override fun failed(exc: Throwable, attachment: Any?) {
exc.addSuppressed(outerCaller)
println("Failed: ${exc.message}")
}
})
}

}

fun main(){

CoroutineScope(IO).launch {
WhatsappTryHandshake.connectToWhatsAppWebSocket()
}

while (true){
//..
}

}

Описание проблемы
  • Поведение среды JVM
    • Код успешно выполняется в автономной среде Kotlin/JVM.
    • Переходы состояний рукопожатия включают NEED_WRAP, NEED_UNWRAP и NEED_TASK > как ожидается.
    • Окончательное рукопожатие завершается успешно, как показано в журналах ниже.
    < li>Поведение среды Android
    • При подтверждении связи возникает исключение на последнем этапе NEED_WRAP.
    • Байты, полученные в результате Операция переноса различается в JVM и Android.

      JVM: 74 байта.
    • Android: 16470 байтов .
Это несоответствие приводит к исключению IllegalStateException, при котором операция подтверждения SSL не удалась. статус: байты не израсходованы.
Журналы JVM
NEED_WRAP
completed: 489
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_TASK
bytesConsumed = 127 bytesProduced = 0
NEED_TASK
Handshake Status NEED_WRAP
NEED_WRAP
completed: 6
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_UNWRAP
bytesConsumed = 6 bytesProduced = 0
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_TASK
bytesConsumed = 1022 bytesProduced = 0
NEED_TASK
Handshake Status NEED_UNWRAP
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_UNWRAP
bytesConsumed = 1522 bytesProduced = 0
NEED_UNWRAP
Status = BUFFER_UNDERFLOW HandshakeStatus = NEED_UNWRAP
bytesConsumed = 0 bytesProduced = 0
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_TASK
bytesConsumed = 492 bytesProduced = 0
NEED_TASK
Handshake Status NEED_WRAP
NEED_WRAP
completed: 74

Журналы Android
NEED_WRAP
completed: 517
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_UNWRAP
bytesConsumed = 127 bytesProduced = 0
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_UNWRAP
bytesConsumed = 6 bytesProduced = 0
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_UNWRAP
bytesConsumed = 1022 bytesProduced = 0
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_UNWRAP
bytesConsumed = 1522 bytesProduced = 0
NEED_UNWRAP
Status = OK HandshakeStatus = NEED_WRAP
bytesConsumed = 492 bytesProduced = 0
NEED_WRAP
java.lang.IllegalStateException: SSL handshake operation failed with status: no bytes consumed
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.isHandshakeFinished(Whatsapp_transport_handshake.kt:145)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doHandshake(Whatsapp_transport_handshake.kt:64)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doSSlHandshakeUnwrapOperation(Whatsapp_transport_handshake.kt:127)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doHandshake(Whatsapp_transport_handshake.kt:89)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doSSlHandshakeUnwrapOperation(Whatsapp_transport_handshake.kt:127)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doHandshake(Whatsapp_transport_handshake.kt:89)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doSSlHandshakeUnwrapOperation(Whatsapp_transport_handshake.kt:127)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doHandshake(Whatsapp_transport_handshake.kt:89)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doSSlHandshakeUnwrapOperation(Whatsapp_transport_handshake.kt:127)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doHandshake(Whatsapp_transport_handshake.kt:89)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.doSSlHandshakeUnwrapOperation(Whatsapp_transport_handshake.kt:127)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake.access$doSSlHandshakeUnwrapOperation(Whatsapp_transport_handshake.kt:17)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake$doHandshake$2.invoke(Whatsapp_transport_handshake.kt:93)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake$doHandshake$2.invoke(Whatsapp_transport_handshake.kt:92)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake$readPlain$1.completed(Whatsapp_transport_handshake.kt:168)
at com.example.whatsappwrapperdemo.whatsapp.WhatsappTryHandshake$readPlain$1.completed(Whatsapp_transport_handshake.kt:156)
at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
at sun.nio.ch.UnixAsynchronousSocketChannelImpl.finishRead(UnixAsynchronousSocketChannelImpl.java:454)
at sun.nio.ch.UnixAsynchronousSocketChannelImpl.finish(UnixAsynchronousSocketChannelImpl.java:201)
at sun.nio.ch.UnixAsynchronousSocketChannelImpl.onEvent(UnixAsynchronousSocketChannelImpl.java:223)
at sun.nio.ch.EPollPort$EventHandlerTask.run(EPollPort.java:293)
at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)

Наблюдения
  • В среде JVM рукопожатие включает NEED_TASK, который не отображается в Android .
  • Байты, полученные в результате окончательной операции переноса, значительно различаются между JVM и Android.
  • Я думал, что могут быть проблемы с сертификатами поэтому я также добавил файлы сертификатов в приложение, добавив сеть файл конфигурации ниже.


web.whatsapp.com












Подробнее здесь: https://stackoverflow.com/questions/792 ... red-to-jvm
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Исключение NPGSQL при выполнении SSL-квитирования
    Anonymous » » в форуме Android
    0 Ответы
    51 Просмотры
    Последнее сообщение Anonymous
  • Ошибка прерывания SSL-квитирования с катушкой в ​​Котлине
    Anonymous » » в форуме Android
    0 Ответы
    10 Просмотры
    Последнее сообщение Anonymous
  • Как я могу получить отладочные сообщения из SSL-квитирования Java?
    Anonymous » » в форуме JAVA
    0 Ответы
    14 Просмотры
    Последнее сообщение Anonymous
  • Javax.net.ssl.sslprotocolexception: SSL Handshake прерван: ssl = 0x7fa2258640: сбой в библиотеке SSL, обычно ошибка прот
    Anonymous » » в форуме JAVA
    0 Ответы
    57 Просмотры
    Последнее сообщение Anonymous
  • Javax.net.ssl.sslprotocolexception: SSL Handshake прерван: ssl = 0x7fa2258640: сбой в библиотеке SSL, обычно ошибка прот
    Anonymous » » в форуме Android
    0 Ответы
    46 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Android»