Wi-Fi dan banyak lagi singkatan lain. Cara mendapatkan data tentang nod Wi-Fi dalam aplikasi Android tanpa bengkak

Suatu hari saya perlu mengimbas rangkaian Wi-Fi daripada aplikasi Android dan mendapatkan data terperinci tentang titik akses.

Di sini kami terpaksa menghadapi beberapa kesukaran: dimatikan. Dokumentasi Android banyak kelas yang diterangkan menjadi tidak digunakan (tahap API > 26), yang tidak ditunjukkan di dalamnya; penerangan beberapa perkara dalam dokumentasi adalah minimum (contohnya, medan keupayaan kelas ScanResult pada masa penulisan, hampir tiada apa yang diterangkan, walaupun ia mengandungi banyak data penting). Kesukaran ketiga mungkin terletak pada hakikat bahawa apabila anda mula-mula mendekati Wi-Fi, selain membaca teori dan menyediakan penghala melalui localhost, anda perlu berurusan dengan beberapa singkatan yang nampaknya boleh difahami secara individu. Tetapi mungkin tidak jelas cara mengaitkan dan menyusunnya (penghakiman adalah subjektif dan bergantung pada pengalaman sebelumnya).

Artikel ini membincangkan cara mendapatkan data komprehensif tentang persekitaran Wi-Fi daripada kod Android tanpa NDK, penggodaman, tetapi hanya menggunakan API Android dan memahami cara mentafsirnya.

Jangan berlengah dan mula menulis kod.

1. Buat projek

Nota ini ditujukan untuk mereka yang telah mencipta projek Android lebih daripada sekali, jadi kami meninggalkan butiran item ini. Kod di bawah akan dibentangkan dalam Kotlin, minSdkVersion=23.

2. Kebenaran akses

Untuk bekerja dengan Wi-Fi daripada aplikasi, anda perlu mendapatkan beberapa kebenaran daripada pengguna. Sesuai dengan dokumentasi, untuk mengimbas rangkaian pada peranti dengan versi OS selepas 8.0, sebagai tambahan kepada akses untuk melihat keadaan persekitaran rangkaian, anda memerlukan sama ada akses untuk menukar keadaan modul Wi-Fi peranti atau akses kepada koordinat (anggaran atau tepat). Bermula dengan versi 9.0, anda mesti menggesa pengguna untuk kedua-duanya, dan juga secara eksplisit meminta pengguna untuk menghidupkan perkhidmatan lokasi. Jangan lupa untuk menjelaskan dengan berani kepada pengguna bahawa ini adalah kehendak Google, dan bukan keinginan kami untuk mengintipnya :)

Jadi, dalam AndroidManifest.xml kami akan menambah:

    <uses-permission android_name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android_name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android_name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android_name="android.permission.ACCESS_FINE_LOCATION"/>

Dan dalam kod yang mengandungi pautan ke Aktiviti semasa:

import android.app.Activity
import android.content.Context
import android.location.LocationManager
import androidx.core.app.ActivityCompat

....

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
            makeEnableLocationServices(activity.applicationContext)
        } else {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
        }

    /* Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ экран Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ слуТбы ΠΏΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΡŽ мСстополоТСния */
    fun makeEnableLocationServices(context: Context) {
        // TODO: ΠΏΠ΅Ρ€Π΅Π΄ Π²Ρ‹Π·ΠΎΠ²ΠΎΠΌ этой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π½Π°Π΄ΠΎ Ρ€Π°ΡΡΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ, Π·Π°Ρ‡Π΅ΠΌ Π’Π°ΠΌ доступ ΠΊ ΠΌΠ΅ΡΡ‚ΠΎΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ
        val lm: LocationManager =
            context.applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager

        val gpsEnabled: Boolean = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        val networkEnabled: Boolean = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if (!gpsEnabled && !networkEnabled) {
            context.startActivity(Intent(ACTION_LOCATION_SOURCE_SETTINGS));
        }
    }

3. Cipta Penerima Siaran dan langgan acara kemas kini data tentang mengimbas persekitaran rangkaian Wi-Fi

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

val wifiScanReceiver = object : BroadcastReceiver() {

  override fun onReceive(context: Context, intent: Intent) {
    val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
    if (success) {
      scanSuccess()
    } 
  }
}

val intentFilter = IntentFilter()
/* подписываСмся Π½Π° сообщСния ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ Π½ΠΎΠ²Ρ‹Ρ… Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² сканирования */
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
context.registerReceiver(wifiScanReceiver, intentFilter)

val success = wifiManager.startScan()
if (!success) {
  /* Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π½Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ ΠΏΡ€ΠΈ запускС сканирования, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ Π²Ρ‹Π΄Π°Π½Ρ‹Π΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ */
}

....

private fun scanSuccess() {
 /* Π²ΠΎΡ‚ ΠΎΠ½ΠΈ, Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ сканирования */
  val results: List<ScanResult> = wifiManager.scanResults
}

Kaedah WiFiManager.startScan dalam dokumentasi ditandakan sebagai tidak digunakan sejak API versi 28, tetapi dimatikan. membimbing mencadangkan menggunakannya.

Secara keseluruhan, kami menerima senarai objek ScanResult.

4. Lihat ScanResult dan fahami termanya

Mari lihat beberapa bidang kelas ini dan huraikan maksudnya:

SSID β€” Pengecam Set Perkhidmatan ialah nama rangkaian

BSSID – Pengecam Set Perkhidmatan Asas – Alamat MAC penyesuai rangkaian (titik Wi-Fi)

tahap β€” Penunjuk Kekuatan Isyarat Diterima [dBm (dBm Rusia) β€” Desibel, kuasa rujukan 1 mW.] β€” Penunjuk kekuatan isyarat yang diterima. Mengambil nilai dari 0 hingga -100, semakin jauh dari 0, semakin banyak kuasa isyarat hilang sepanjang perjalanan dari titik Wi-Fi ke peranti anda. Butiran lanjut boleh didapati, contohnya, di Wikipedia. Di sini saya akan memberitahu anda bahawa menggunakan kelas Android WifiManager anda boleh menentukur tahap isyarat pada skala daripada cemerlang kepada teruk dengan langkah yang anda pilih:

        val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val numberOfLevels = 5
        val level = WifiManager.calculateSignalLevel(level, numberOfLevels)

kekerapan β€” kekerapan operasi titik Wi-Fi [Hz]. Sebagai tambahan kepada kekerapan itu sendiri, anda mungkin berminat dengan saluran yang dipanggil. Setiap titik mempunyai ketulenan operasinya sendiri. Pada masa penulisan, julat titik Wi-Fi yang paling popular ialah 2.4 GHz. Tetapi, untuk menjadi lebih tepat, titik menghantar maklumat ke telefon anda pada frekuensi bernombor dekat dengan yang dinamakan. Bilangan saluran dan frekuensi yang sepadan diseragamkan. Ini dilakukan supaya titik berdekatan beroperasi pada frekuensi yang berbeza, dengan itu tidak mengganggu antara satu sama lain dan tidak saling mengurangkan kelajuan dan kualiti penghantaran. Dalam kes ini, titik beroperasi bukan pada satu frekuensi, tetapi pada julat frekuensi (parameter lebar saluran), dipanggil lebar saluran. Iaitu, mata yang beroperasi pada saluran bersebelahan (dan bukan sahaja bersebelahan, tetapi juga 3 dari mereka sendiri) mengganggu satu sama lain. Anda mungkin mendapati kod mudah ini berguna, yang membolehkan anda mengira nombor saluran daripada nilai kekerapan untuk titik dengan frekuensi 2.4 dan 5 Ghz:


    /* ΠΏΠΎ частотС опрСдСляСм Π½ΠΎΠΌΠ΅Ρ€ ΠΊΠ°Π½Π°Π»Π° */
    val channel: Int
        get() {
            return if (frequency in 2412..2484) {
                (frequency - 2412) / 5 + 1
            } else if (frequency in 5170..5825) {
                (frequency - 5170) / 5 + 34
            } else {
                -1
            }
        }

keupayaan - bidang yang paling menarik untuk analisis, kerja yang memerlukan banyak masa. Di sini "keupayaan" titik ditulis dalam baris. Dalam kes ini, anda tidak perlu mencari butiran tafsiran rentetan dalam dokumentasi. Berikut ialah beberapa contoh perkara yang mungkin terdapat dalam baris ini:

[WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][WPS][ESS]
[WPA2-PSK-CCMP][ESS]
[WPA2-PSK-CCMP+TKIP][ESS]
[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS]
[ESS][WPS]

5. Memahami singkatan dan keupayaan menghurai

Perlu dinyatakan bahawa kelas pakej android.net.wifi.* digunakan di bawah hud oleh utiliti Linux wpa_supplicant dan hasil output dalam medan keupayaan ialah salinan medan bendera semasa mengimbas.

Kami akan bertindak secara konsisten. Mari kita pertimbangkan dahulu output format di mana unsur-unsur dalam kurungan dipisahkan dengan tanda β€œ-β€œ:

[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]

Makna pertama menerangkan apa yang dipanggil. kaedah pengesahan. Iaitu, urutan tindakan yang mesti dilakukan oleh peranti dan pusat akses agar titik akses membenarkan dirinya digunakan dan cara menyulitkan muatan. Pada masa menulis siaran ini, pilihan yang paling biasa ialah WPA dan WPA2, di mana sama ada setiap peranti yang disambungkan secara langsung atau melalui apa yang dipanggil. Pelayan RADIUS (WPA-Enterprice) menyediakan kata laluan melalui saluran yang disulitkan. Kemungkinan besar, titik akses di rumah anda menyediakan sambungan mengikut skema ini. Perbezaan antara versi kedua dan yang pertama ialah ia mempunyai sifir yang lebih kuat: AES berbanding TKIP yang tidak selamat. WPA3, yang lebih kompleks dan maju, juga secara beransur-ansur diperkenalkan. Secara teorinya, mungkin terdapat pilihan dengan penyelesaian enterprice CCKM (Cisco Centralized Key Management), tetapi saya tidak pernah menemuinya.

Titik akses mungkin telah dikonfigurasikan untuk mengesahkan dengan alamat MAC. Atau, jika pusat akses menyediakan data menggunakan algoritma WEP yang sudah lapuk, maka sebenarnya tiada pengesahan (kunci rahsia di sini ialah kunci penyulitan). Kami mengklasifikasikan pilihan tersebut sebagai LAIN.
Terdapat juga kaedah yang popular di wi-fi awam dengan Pengesanan Portal Tawanan tersembunyi - permintaan pengesahan melalui penyemak imbas. Titik capaian sedemikian kelihatan kepada pengimbas sebagai terbuka (yang mana ia adalah dari sudut pandangan sambungan fizikal). Oleh itu, kami mengklasifikasikannya sebagai TERBUKA.

Nilai kedua boleh ditandakan sebagai algoritma pengurusan utama. Ini ialah parameter kaedah pengesahan yang diterangkan di atas. Bercakap tentang cara pertukaran kunci penyulitan dengan tepat. Mari kita pertimbangkan pilihan yang mungkin. EAP - digunakan dalam WPA-Enterprice yang disebutkan, menggunakan pangkalan data untuk mengesahkan data pengesahan yang dimasukkan. SAE - digunakan dalam WPA3 lanjutan, lebih tahan terhadap kekerasan. PSK - pilihan yang paling biasa, melibatkan memasukkan kata laluan dan menghantarnya dalam bentuk yang disulitkan. IEEE8021X - mengikut piawaian antarabangsa (berbeza daripada yang disokong oleh keluarga WPA). OWE (Opportunistic Wireless Encryption) ialah lanjutan daripada standard IEEE 802.11 untuk mata yang kami klasifikasikan sebagai OPEN. OWE memastikan keselamatan data yang dihantar melalui rangkaian tidak terjamin dengan menyulitkannya. Pilihan juga boleh dilakukan apabila tiada kekunci akses, mari kita panggil pilihan ini TIADA.

Parameter ketiga ialah apa yang dipanggil. skim penyulitan β€” bagaimana sebenarnya sifir digunakan untuk melindungi data yang dihantar. Mari senaraikan pilihan. WEP - menggunakan sifir aliran RC4, kunci rahsia ialah kunci penyulitan, yang dianggap tidak boleh diterima dalam dunia kriptografi moden. TKIP - digunakan dalam WPA, CKIP - dalam WPA2. TKIP+CKIP - boleh ditentukan dalam mata yang mampu WPA dan WPA2 untuk keserasian ke belakang.

Daripada tiga elemen, anda boleh mencari tanda WEP yang sunyi:

[WEP]

Seperti yang kita bincangkan di atas, ini sudah cukup untuk tidak menentukan algoritma untuk menggunakan kunci, yang tidak wujud, dan kaedah penyulitan, yang sama secara lalai.

Sekarang pertimbangkan kurungan ini:

[ESS]

ini Mod pengendalian Wi-Fi atau Topologi rangkaian Wi-Fi. Anda mungkin menghadapi mod BSS (Set Perkhidmatan Asas) - apabila terdapat satu pusat akses yang melaluinya peranti yang disambungkan berkomunikasi. Boleh didapati di rangkaian tempatan. Sebagai peraturan, pusat akses diperlukan untuk menyambungkan peranti daripada rangkaian tempatan yang berbeza, jadi ia adalah sebahagian daripada Set Perkhidmatan Lanjutan - ESS. Jenis IBSS (Set Perkhidmatan Asas Bebas) menunjukkan bahawa peranti adalah sebahagian daripada rangkaian Peer-to-Peer.

Anda juga mungkin melihat bendera WPS:

[WPS]

WPS (Wi-Fi Protected Setup) ialah protokol untuk permulaan separa automatik bagi rangkaian Wi-Fi. Untuk memulakan, pengguna sama ada memasukkan kata laluan 8 aksara atau menekan butang pada penghala. Jika pusat akses anda adalah jenis pertama dan kotak semak ini muncul di sebelah nama pusat akses anda, anda amat disyorkan untuk pergi ke panel pentadbir dan melumpuhkan akses WPS. Hakikatnya selalunya PIN 8 digit boleh didapati melalui alamat MAC, atau ia boleh diselesaikan dalam masa yang boleh dijangka, yang boleh dimanfaatkan oleh seseorang secara tidak jujur.

6. Buat model dan fungsi penghuraian

Berdasarkan apa yang kami dapati di atas, kami akan menerangkan apa yang berlaku menggunakan kelas data:

/* схСма Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ */
enum class AuthMethod {
    WPA3,
    WPA2,
    WPA, // Wi-Fi Protected Access
    OTHER, // Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π² сСбя Shared Key Authentication ΠΈ Π΄Ρ€. ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ mac-address-based ΠΈ WEP
    CCKM, // Cisco
    OPEN // Open Authentication. ΠœΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ со скрытым Captive Portal Detection - запрос Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ Ρ‡Π΅Ρ€Π΅Π· Π±Ρ€Π°ΡƒΠ·Π΅Ρ€
}

/* Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ Π²Π²ΠΎΠ΄Π° ΠΊΠ»ΡŽΡ‡Π΅ΠΉ */
enum class KeyManagementAlgorithm {
    IEEE8021X, // ΠΏΠΎ стандарту
    EAP, // Extensible Authentication Protocol, Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅ΠΌΡ‹ΠΉ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ» Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ
    PSK, // Pre-Shared Key β€” ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΡƒΠ·Π΅Π» Π²Π²ΠΎΠ΄ΠΈΡ‚ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ для доступа ΠΊ сСти
    WEP, // Π² WEP ΠΏΠ°Ρ€ΠΎΠ»ΡŒ являСтся ΠΊΠ»ΡŽΡ‡ΠΎΠΌ ΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Π½ΠΈΡ (No auth key)
    SAE, // Simultaneous Authentication of Equals - ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π² WPA3
    OWE, // Opportunistic Wireless Encryption - Π² Ρ€ΠΎΡƒΡ‚Π΅Ρ€Π°Ρ… Π½ΠΎΠ²Ρ‹Ρ… ΠΏΠΎΠΊΠΎΠ»Π΅Π½ΠΈΠΉ, ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Ρ… сСтях Ρ‚ΠΈΠΏΠ° OPEN
    NONE // ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π±Π΅Π· ΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Π½ΠΈΡ Π² OPEN, OTHER
}

/* ΠΌΠ΅Ρ‚ΠΎΠ΄ ΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Π½ΠΈΡ */
enum class CipherMethod {
    WEP, // Wired Equivalent Privacy, Аналог ΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Π½ΠΈΡ Ρ‚Ρ€Π°Ρ„ΠΈΠΊΠ° Π² ΠΏΡ€ΠΎΠ²ΠΎΠ΄Π½Ρ‹Ρ… сСтях
    TKIP, // Temporal Key Integrity Protocol
    CCMP, // Counter Mode with Cipher Block Chaining Message Authentication Code Protocol,
    // ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ» Π±Π»ΠΎΡ‡Π½ΠΎΠ³ΠΎ ΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Π½ΠΈΡ с ΠΊΠΎΠ΄ΠΎΠΌ аутСнтичности сообщСния ΠΈ Ρ€Π΅ΠΆΠΈΠΌΠΎΠΌ сцСплСния Π±Π»ΠΎΠΊΠΎΠ² ΠΈ счСтчика
    // на основС AES
    NONE // ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π±Π΅Π· ΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Π½ΠΈΡ Π² OPEN, OTHER
}

/* Π½Π°Π±ΠΎΡ€ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΡˆΠΈΡ„Ρ€ΠΎΠ²Π°Π½ΠΈΡ ΠΈ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»ΠΎΠ², ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΌΠΎΠΆΠ΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Ρ‚ΠΎΡ‡ΠΊΠ° */
data class Capability(
    var authScheme: AuthMethod? = null,
    var keyManagementAlgorithm: KeyManagementAlgorithm? = null,
    var cipherMethod: CipherMethod? = null
)

/* Π Π΅ΠΆΠΈΠΌ Ρ€Π°Π±ΠΎΡ‚Ρ‹ WiFi (ΠΈΠ»ΠΈ топология сСтСй WiFi) */
enum class TopologyMode {
    IBSS, // ЭпизодичСская ΡΠ΅Ρ‚ΡŒ (Ad-Hoc ΠΈΠ»ΠΈ IBSS – Independent Basic Service Set).
    BSS, // Основная Π·ΠΎΠ½Π° обслуТивания Basic Service Set (BSS) ΠΈΠ»ΠΈ Infrastructure Mode.
    ESS // Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Π°Ρ Π·ΠΎΠ½Π° обслуТивания ESS – Extended Service Set.
}

Sekarang mari kita tulis fungsi yang akan menghuraikan medan keupayaan:


private fun parseCapabilities(capabilitiesString: String): List < Capability > {
    val capabilities: List < Capability > = capabilitiesString
        .splitByBrackets()
        .filter {
            !it.isTopology() && !it.isWps()
        }
        .flatMap {
            parseCapability(it)
        }
    return
        if (!capabilities.isEmpty()) {
            capabilities
        } else {
            listOf(Capability(AuthMethod.OPEN, KeyManagementAlgorithm.NONE, CipherMethod.NONE))
        }
}

private fun parseCapability(part: String): List < Capability > {
    if (part.contains("WEP")) {
        return listOf(Capability(
            AuthMethod.OTHER,
            KeyManagementAlgorithm.WEP,
            CipherMethod.WEP
        ))
    }

    val authScheme = when {
        part.contains("WPA3") - > AuthMethod.WPA3
        part.contains("WPA2") - > AuthMethod.WPA2
        part.contains("WPA") - > AuthMethod.WPA
        else - > null
    }

    val keyManagementAlgorithm = when {
        part.contains("OWE") - > KeyManagementAlgorithm.OWE
        part.contains("SAE") - > KeyManagementAlgorithm.SAE
        part.contains("IEEE802.1X") - > KeyManagementAlgorithm.IEEE8021X
        part.contains("EAP") - > KeyManagementAlgorithm.EAP
        part.contains("PSK") - > KeyManagementAlgorithm.PSK
        else - > null
    }

    val capabilities = ArrayList < Capability > ()
    if (part.contains("TKIP") || part.contains("CCMP")) {
        if (part.contains("TKIP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.TKIP
            ))
        }
        if (part.contains("CCMP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.CCMP
            ))
        }
    } else if (authScheme != null || keyManagementAlgorithm != null) {
        capabilities.add(Capability(
            authScheme ? : AuthMethod.OPEN,
            keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
            CipherMethod.NONE
        ))
    }

    return capabilities
}

private fun parseTopologyMode(capabilitiesString: String): TopologyMode ? {
    return capabilitiesString
        .splitByBrackets()
        .mapNotNull {
            when {
                it.contains("ESS") - > TopologyMode.ESS
                it.contains("BSS") - > TopologyMode.BSS
                it.contains("IBSS") - > TopologyMode.IBSS
                else - > null
            }
        }
        .firstOrNull()
}

private fun parseWPSAvailable(capabilitiesString: String): Boolean {
    return capabilitiesString
        .splitByBrackets()
        .any {
            it.isWps()
        }
}

private fun String.splitByBrackets(): List < String > {
    val m = Pattern.compile("[(.*?)]").matcher(this)
    val parts = ArrayList < String > ()
    while (m.find()) {
        parts.add(m.group().replace("[", "").replace("]", ""))
    }
    return parts
}

private fun String.isTopology(): Boolean {
    return TopologyMode.values().any {
        this == it.name
    }
}

private fun String.isWps(): Boolean {
    return this == "WPS"
}

8. Lihat hasilnya

Saya akan mengimbas rangkaian dan menunjukkan kepada anda perkara yang saya temui. Ditunjukkan ialah hasil keluaran mudah melalui Log.d:

Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true

Isu menyambung ke rangkaian daripada kod aplikasi kekal tidak diselidiki. Saya hanya akan mengatakan bahawa untuk membaca kata laluan yang disimpan daripada OS peranti mudah alih, anda memerlukan hak akar dan kesediaan untuk menyelongkar sistem fail untuk membaca wpa_supplicant.conf. Jika logik aplikasi memerlukan memasukkan kata laluan dari luar, sambungan boleh dibuat melalui kelas android.net.wifi.WifiManager.

Terima kasih Egor Ponomarev untuk tambahan yang berharga.

Jika anda rasa sesuatu perlu ditambah atau diperbetulkan, tulis dalam komen :)

Sumber: www.habr.com

Tambah komen