def peap_challenge_gtc_password(cls, request: AuthRequest, eap: EapPacket,
                                    peap: EapPeapPacket,
                                    session: EapPeapSession):
        assert peap.tls_data

        # 解密
        tls_decrypt_data = libhostapd.decrypt(session.tls_connection,
                                              peap.tls_data)
        eap_identity = EapPacket.parse(packet=tls_decrypt_data)
        account_name = eap_identity.type_data.decode()
        # 保存用户名
        session.auth_user.set_peap_username(account_name)

        # 查找用户密码
        account = Account.get(username=account_name)
        if not account or account.is_expired():
            raise AccessReject()
        # 保存用户密码
        session.auth_user.set_user_password(account.radius_password)

        # 返回数据
        response_data = b'Password'
        type_data = struct.pack(f'!{len(response_data)}s', response_data)
        eap_password = EapPacket(code=EapPacket.CODE_EAP_REQUEST,
                                 id=session.current_eap_id,
                                 type_dict={
                                     'type': EapPacket.TYPE_EAP_GTC,
                                     'type_data': type_data
                                 })
        tls_plaintext = eap_password.ReplyPacket()

        # 加密
        tls_out_data = libhostapd.encrypt(session.tls_connection,
                                          tls_plaintext)
        #
        peap_reply = EapPeapPacket(code=EapPeapPacket.CODE_EAP_REQUEST,
                                   id=session.current_eap_id,
                                   tls_data=tls_out_data)
        reply = AuthResponse.create_peap_challenge(
            request=request, peap=peap_reply, session_id=session.session_id)
        request.reply_to(reply)
        session.set_reply(reply)

        # judge next move
        session.next_state = cls.PEAP_CHALLENGE_SUCCESS
        return
    def peap_challenge_success(cls, request: AuthRequest, eap: EapPacket,
                               peap: EapPeapPacket, session: EapPeapSession):
        # 解密.
        # v0: EAP-PEAP: Decrypted Phase 2 EAP - hexdump(len=2): 1a 03
        # v1: EAP-PEAP: Decrypted Phase 2 EAP - hexdump(len=6): 02 08 00 06 1a 03
        tls_decrypt_data = libhostapd.decrypt(session.tls_connection,
                                              peap.tls_data)

        # 返回数据 eap_tlv_success
        if session.peap_version == 0:
            type_data = struct.pack(f'!B B H H', 0x80,
                                    EapPacket.TYPE_RESULT_TLV, 2,
                                    EapPacket.TYPE_RESULT_TLV_SUCCESS)
            eap_tlv_success = EapPacket(code=EapPacket.CODE_EAP_REQUEST,
                                        id=session.current_eap_id,
                                        type_dict={
                                            'type': EapPacket.TYPE_EAP_TLV,
                                            'type_data': type_data
                                        })
            tls_plaintext: bytes = eap_tlv_success.ReplyPacket()
        else:
            # 返回数据 eap_success
            eap_success = EapPacket(code=EapPacket.CODE_EAP_SUCCESS,
                                    id=session.current_eap_id)
            tls_plaintext = eap_success.ReplyPacket()

        # 加密.
        # v0: EAP-PEAP: Encrypting Phase 2 TLV data - hexdump(len=11): 01 08 00 0b 21 80 03 00 02 00 01
        # v1: EAP-PEAP: Encrypting Phase 2 data - hexdump(len=4): 03 09 00 04
        tls_out_data: bytes = libhostapd.encrypt(session.tls_connection,
                                                 tls_plaintext)
        #
        peap_reply = EapPeapPacket(code=EapPeapPacket.CODE_EAP_REQUEST,
                                   id=session.current_eap_id,
                                   tls_data=tls_out_data,
                                   flag_version=session.peap_version)
        reply = AuthResponse.create_peap_challenge(
            request=request, peap=peap_reply, session_id=session.session_id)
        request.reply_to(reply)
        session.set_reply(reply)

        # judge next move
        session.next_state = cls.PEAP_ACCESS_ACCEPT
        return
    def peap_challenge_success(cls, request: AuthRequest, eap: EapPacket,
                               peap: EapPeapPacket, session: EapPeapSession):
        # 解密
        tls_decrypt_data = libhostapd.decrypt(session.tls_connection,
                                              peap.tls_data)
        eap_password = EapPacket.parse(packet=tls_decrypt_data)
        auth_password = eap_password.type_data.decode()
        log.debug(
            f'PEAP account: {session.auth_user.peap_username}, packet_password: {auth_password}'
        )

        def is_correct_password() -> bool:
            return session.auth_user.user_password == auth_password

        if not is_correct_password():
            log.error(
                f'user_password: {session.auth_user.user_password} not correct'
            )
            # 返回数据 eap_failure
            eap_failure = EapPacket(code=EapPacket.CODE_EAP_FAILURE,
                                    id=session.current_eap_id)
            tls_plaintext = eap_failure.ReplyPacket()
        else:
            # 返回数据 eap_success
            eap_success = EapPacket(code=EapPacket.CODE_EAP_SUCCESS,
                                    id=session.current_eap_id)
            tls_plaintext = eap_success.ReplyPacket()

        # 加密
        tls_out_data = libhostapd.encrypt(session.tls_connection,
                                          tls_plaintext)
        #
        peap_reply = EapPeapPacket(code=EapPeapPacket.CODE_EAP_REQUEST,
                                   id=session.current_eap_id,
                                   tls_data=tls_out_data)
        reply = AuthResponse.create_peap_challenge(
            request=request, peap=peap_reply, session_id=session.session_id)
        request.reply_to(reply)
        session.set_reply(reply)

        # judge next move
        session.next_state = cls.PEAP_ACCESS_ACCEPT
        return
    def peap_challenge_mschapv2_nt(cls, request: AuthRequest, eap: EapPacket,
                                   peap: EapPeapPacket,
                                   session: EapPeapSession):
        assert peap.tls_data
        # 解密
        # v0: EAP-PEAP: Decrypted Phase 2 EAP - hexdump(len=63): 1a 02 06 00 3e 31 b1 3a 4c 4f 8d 2a 09 3d 89 b2 f8 eb c1 ec 53 f0 00 00
        # 00 00 00 00 00 00 e5 39 9d 11 d6 06 0b b9 95 8e 16 f2 20 fc 4b c9 b0 ab 4e fd bc 62 01 39 00 74 65 73 74 75 73 65 72
        # v1: EAP-PEAP: Decrypted Phase 2 EAP - hexdump(len=67): 02 07 00 43 1a 02 07 00 3e 31 16 79 ba 65 ad 16 7f 92 5c 74 c9 80 53 d6
        # fc 4c 00 00 00 00 00 00 00 00 72 0e 3d a8 8d bd f8 a9 e8 bd 1a 95 d9 5f 08 03 7e 10 db 9f 01 d4 a5 fc 00 74 65 73 74 75 73 65 72
        tls_decrypt_data = libhostapd.decrypt(session.tls_connection,
                                              peap.tls_data)
        # MSCHAPV2_OP_RESPONSE(02) + 与EAP_id相同(07) + MSCHAPV2_OP 到结束的长度(00 3e) +
        # 随机数长度(31) +
        # 24位随机数内含8位0(16 79 ba 65 ad 16 7f 92 5c 74 c9 80 53 d6 fc 4c + 00 00 00 00 00 00 00 00) +
        # 24位NT-Response(72 0e 3d a8 8d bd f8 a9 e8 bd 1a 95 d9 5f 08 03 7e 10 db 9f 01 d4 a5 fc) +
        # Flags(00) +
        # 用户名(74 65 73 74 75 73 65 72)
        mschapv2_random: EapMschapv2Packet = EapMschapv2Packet.parse(
            packet=tls_decrypt_data, peap_version=session.peap_version)
        log.trace(f'mschapv2_random: {mschapv2_random}')
        if mschapv2_random.type != EapPacket.TYPE_EAP_MSCHAPV2:
            log.error('not receive mschapv2_random')
            raise AccessReject()
        mschapv2_type, eap_id, mschapv2_length, fix_length = struct.unpack(
            '!B B H B', mschapv2_random.type_data[:5])
        assert fix_length == 0x31 == 49
        username_len = mschapv2_length - 5 - fix_length
        peer_challenge: bytes
        nt_response: bytes
        flag: bytes
        identity: bytes
        peer_challenge, nt_response, flag, identity = struct.unpack(
            f'!24s 24s B {username_len}s', mschapv2_random.type_data[5:])
        peer_challenge = peer_challenge[:16]
        # 保存客户端随机数
        session.auth_user.set_peer_challenge(peer_challenge)

        assert identity.decode() == session.auth_user.peap_username
        # 计算期望密码哈希值
        p_username = ctypes.create_string_buffer(
            session.auth_user.peap_username.encode())
        l_username_len = ctypes.c_ulonglong(username_len)
        p_password = ctypes.create_string_buffer(
            session.auth_user.user_password.encode())
        l_password_len = ctypes.c_ulonglong(
            len(session.auth_user.user_password))
        p_expect = libhostapd.call_generate_nt_response(
            p_auth_challenge=session.auth_user.server_challenge,
            p_peer_challenge=session.auth_user.peer_challenge,
            p_username=p_username,
            l_username_len=l_username_len,
            p_password=p_password,
            l_password_len=l_password_len,
        )
        expect: bytes = ctypes.string_at(p_expect, len(p_expect))
        log.trace(f'nt_response: {nt_response}')
        log.trace(f'expect: {expect}')

        # 判断密码是否正确
        def is_correct_password() -> bool:
            return nt_response == expect

        if not is_correct_password():
            # 密码整错
            log.error(f'user_password not correct')
            # 返回数据 eap_failure
            eap_failure = EapPacket(code=EapPacket.CODE_EAP_FAILURE,
                                    id=session.current_eap_id)
            tls_plaintext: bytes = eap_failure.ReplyPacket()
        else:
            # 计算 md4(password)
            p_password_md4 = libhostapd.call_nt_password_hash(
                p_password=p_password, l_password_len=l_password_len)
            # 计算返回报文中的 authenticator_response
            p_peer_challenge = ctypes.create_string_buffer(
                session.auth_user.peer_challenge)
            p_auth_challenge = ctypes.create_string_buffer(
                session.auth_user.server_challenge)
            p_nt_response = ctypes.create_string_buffer(nt_response)
            p_out_auth_response = libhostapd.call_generate_authenticator_response_pwhash(
                p_password_md4=p_password_md4,
                p_peer_challenge=p_peer_challenge,
                p_auth_challenge=p_auth_challenge,
                p_username=p_username,
                l_username_len=l_username_len,
                p_nt_response=p_nt_response,
            )
            authenticator_response: bytes = ctypes.string_at(
                p_out_auth_response, len(p_out_auth_response))
            authenticator_response: bytes = authenticator_response.hex().upper(
            ).encode()
            # 返回数据
            # MSCHAPV2_OP_SUCCESS(03) + EAP_id减一(07) + MSCHAPV2_OP 到结束的长度(00 33) +
            # S=(53 3d) +
            # 40个字符: generate_authenticator_response_pwhash 计算出来的哈希值再换成hex大写(37 43 36 39 38 34 37 38 39 44 34 39 44 30 38 32 33 34 35 45 35 31 43 44 45 38 46 35 36 30 33 42 41 44 31 43 34 34 37 33)
            # + 空格(20) +
            # M=(4d 3d) +
            # OK(4f 4b)
            response_msg = b'OK'
            response_msg_len = len(response_msg)
            size_of_auth_response = 20
            size_of_mschapv2_hdr = 4
            message = ''
            type_data_length = size_of_mschapv2_hdr + 2 + (
                2 * size_of_auth_response) + 1 + 2 + response_msg_len
            type_data = struct.pack(
                f'!B B H 2s {2 * size_of_auth_response}s 3s {response_msg_len}s',
                EapPacket.CODE_MSCHAPV2_SUCCESS, session.current_eap_id - 1,
                type_data_length, b'S=', authenticator_response, b' M=',
                response_msg)
            eap_ok = EapPacket(code=EapPacket.CODE_EAP_REQUEST,
                               id=session.current_eap_id,
                               type_dict={
                                   'type': EapPacket.TYPE_EAP_MSCHAPV2,
                                   'type_data': type_data
                               })
            tls_plaintext: bytes = eap_ok.ReplyPacket()
        # 加密
        # v0, v1: EAP-PEAP: Encrypting Phase 2 data - hexdump(len=56): 01 07 00 38 1a 03 06 00 33 53 3d 45 37 35 35 44 37 30 42 43 42 42 35 44 31
        # 43 38 41 45 33 35 35 42 30 38 41 42 31 39 36 42 37 45 33 44 42 43 38 46 31 36 20 4d 3d 4f 4b
        tls_out_data: bytes = libhostapd.encrypt(
            session.tls_connection,
            tls_plaintext,
            peap_version=session.peap_version)
        #
        peap_reply = EapPeapPacket(code=EapPeapPacket.CODE_EAP_REQUEST,
                                   id=session.current_eap_id,
                                   tls_data=tls_out_data,
                                   flag_version=session.peap_version)
        reply = AuthResponse.create_peap_challenge(
            request=request, peap=peap_reply, session_id=session.session_id)
        request.reply_to(reply)
        session.set_reply(reply)

        # judge next move
        session.next_state = cls.PEAP_CHALLENGE_SUCCESS
        return
    def peap_challenge_mschapv2_random(cls, request: AuthRequest,
                                       eap: EapPacket, peap: EapPeapPacket,
                                       session: EapPeapSession):
        assert peap.tls_data
        # 解密
        # v0: EAP-PEAP: Decrypted Phase 2 EAP - hexdump(len=9): 01 74 65 73 74 75 73 65 72
        # v1: EAP-PEAP: Decrypted Phase 2 EAP - hexdump(len=13): 02 06 00 0d 01 74 65 73 74 75 73 65 72
        tls_decrypt_data = libhostapd.decrypt(session.tls_connection,
                                              peap.tls_data)
        eap_identity = EapMschapv2Packet.parse(
            packet=tls_decrypt_data, peap_version=session.peap_version)
        log.trace(f'eap_identity: {eap_identity}')
        if eap_identity.type != EapPacket.TYPE_EAP_IDENTITY:
            log.error('not receive eap_identity')
            raise AccessReject()
        account_name = eap_identity.type_data.decode()
        # 保存用户名
        session.auth_user.set_peap_username(account_name)
        # 查找用户密码
        account = Account.get(username=account_name)
        if not account or account.is_expired():
            raise AccessReject()
        # 保存用户密码
        session.auth_user.set_user_password(account.radius_password)

        # 返回数据
        # MSCHAPV2_OP_CHALLENGE(01) + 与EAP_id相同(07) + MSCHAPV2_OP 到结束的长度(00 1c) +
        # 随机数长度固定值(10) +
        # 16位随机数(2d ae 52 bf 07 d0 de 7b 28 c4 d8 d9 8f 87 da 6a) + server_id(68 6f 73 74 61 70 64)
        size_of_mschapv2_hdr = 4
        server_id = b'hostapd'
        server_id_len = len(server_id)
        server_challenge_len = 16
        server_challenge: bytes = EapPeapPacket.random_string(
            length=server_challenge_len)
        type_data_length = size_of_mschapv2_hdr + 1 + server_challenge_len + server_id_len
        type_data = struct.pack(f'!B B H B 16s {server_id_len}s',
                                EapPacket.CODE_MSCHAPV2_CHALLENGE,
                                session.current_eap_id, type_data_length,
                                server_challenge_len, server_challenge,
                                server_id)
        eap_random = EapPacket(code=EapPacket.CODE_EAP_REQUEST,
                               id=session.current_eap_id,
                               type_dict={
                                   'type': EapPacket.TYPE_EAP_MSCHAPV2,
                                   'type_data': type_data
                               })
        tls_plaintext: bytes = eap_random.ReplyPacket()
        # 保存服务端随机数
        session.auth_user.set_server_challenge(server_challenge)

        # 加密.
        # v0, v1: EAP-PEAP: Encrypting Phase 2 data - hexdump(len=33): 01 07 00 21 1a 01 07 00 1c 10 2d ae 52 bf 07 d0 de 7b 28 c4 d8 d9 8f 87 da 6a 68
        # 6f 73 74 61 70 64
        tls_out_data: bytes = libhostapd.encrypt(
            session.tls_connection,
            tls_plaintext,
            peap_version=session.peap_version)
        #
        peap_reply = EapPeapPacket(code=EapPeapPacket.CODE_EAP_REQUEST,
                                   id=session.current_eap_id,
                                   tls_data=tls_out_data,
                                   flag_version=session.peap_version)
        reply = AuthResponse.create_peap_challenge(
            request=request, peap=peap_reply, session_id=session.session_id)
        request.reply_to(reply)
        session.set_reply(reply)

        # judge next move
        session.next_state = cls.PEAP_CHALLENGE_MSCHAPV2_NT
        return