如何将BlueZ配置为要求连接设备输入匹配的通行密钥? [英] How can BlueZ be configured to require a connecting device to enter a matching pass key?

查看:652
本文介绍了如何将BlueZ配置为要求连接设备输入匹配的通行密钥?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在嵌入式Linux设备上设置蓝牙,以便使用SSP模式,并且我的设备会在其显示屏上生成并显示密码,并且要求远端(例如用户的电话)输入匹配的密码



我已经编写/注册了一个代理,将其模式设置为DisplayOnly;我期望当设备连接 RequestPasskey回调时,我的代理将能够生成并返回新的密码,并且要求远程端输入相同的代码。我实际上看到的行为是远程端正在生成它自己的密码。



如果禁用SSP并使用旧式配对,我可以实现所需的行为。



使用BlueZ是否可以实现此行为?

解决方案

要在此处进行简单讨论,请考虑



因此,输入可以是无输入,是/否和键盘。输出可以是无输出和数值输出。



在您的情况下,您想在嵌入式设备中生成密码(我们可以将其命名为响应者),然后在启动连接的设备中输入密钥(我们可以将其命名为启动器)。



要实现这种情况,您需要指定



响应者(嵌入式设备):作为 KeyboardOnly
发起者:也作为 KeyboardOnly



要对此进行实验,请使用在下面的示例代理程序中,

  / * 
* gcc`pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/agent ./agent.c`pkg-config --libs glib-2.0 gio-2.0`
* /
#include< glib.h>
#include< gio / gio.h>
#include< stdio.h>

GMainLoop *循环;
GDBusConnection * con;
#define AGENT_PATH / org / bluez / AutoPinAgent

static void bluez_agent_method_call(GDBusConnection * conn,
const gchar * sender,
const gchar * path,
const gchar *接口,
const gchar *方法,
GVariant *参数,
GDBusMethodInvocation *调用,
void * userdata)
{
国际通行证;输入了
int;
char * opath;
GVariant * p = g_dbus_method_invocation_get_parameters(invocation);

g_print(代理方法调用:%s。%s()\n,接口,方法);
if(!strcmp(method, RequestPinCode)){
;
}
else if(!strcmp(method, DisplayPinCode)){
;
}
else if(!strcmp(method, RequestPasskey))){
g_print(从用户获取密码:);
fscanf(stdin,%d,& pass);
g_print( \n);
g_dbus_method_invocation_return_value(invocation,g_variant_new((u),pass));
}
else if(!strcmp(method, DisplayPasskey)){
g_variant_get(params,(ouq),& opath,& pass,& enter);
g_print(路径:%s通过:%d输入:%d\n,opath,通过,输入);
g_dbus_method_invocation_return_value(invocation,NULL);
}
else if(!strcmp(method, RequestConfirmation))){
g_variant_get(params,(ou),& opath,& pass);
g_print( Path:%s Pass:%d\n,opath,pass);
g_dbus_method_invocation_return_value(invocation,NULL);
}
else if(!strcmp(method, RequestAuthorization)){
;
}
else if(!strcmp(method, AuthorizeService)){
;
}
else if(!strcmp(method, Cancel)){
;
}
else
g_print(我们不应该来这里,未知方法\n);
}

静态常量GDBusInterfaceVTable agent_method_table = {
.method_call = bluez_agent_method_call,
};

int bluez_register_agent(GDBusConnection * con)
{
GError * error = NULL;
guint id = 0;
GDBusNodeInfo * info = NULL;

静态常量gchar bluez_agent_introspection_xml [] =
<节点名称='/ org / bluez / SampleAgent'>
< interface name =’org.bluez.Agent1’>
< method name ='Release'>
< / method>
< method name ='RequestPinCode'>
< arg type ='o'name ='设备'direction ='in'/>
< arg type ='s'name ='pincode'direction ='out'/>
< / method>
< method name ='DisplayPinCode'>
< arg type ='o'name ='设备'direction ='in'/>
< arg type ='s'name ='pincode'direction ='in'/>
< / method>
< method name ='RequestPasskey'>
< arg type ='o'name ='设备'direction ='in'/>
< arg type ='u'name ='密码'方向='out'/>
< / method>
< method name ='DisplayPasskey'>
< arg type ='o'name ='设备'direction ='in'/>
< arg type ='u'name ='密码'direction ='in'/>
< arg类型= q名称=输入方向=在/>中
< / method>
< method name ='RequestConfirmation'>
< arg type ='o'name ='设备'direction ='in'/>
< arg type ='u'name ='密码'direction ='in'/>
< / method>
< method name ='RequestAuthorization'>
< arg type ='o'name ='设备'direction ='in'/>
< / method>
< method name ='AuthorizeService'>
< arg type ='o'name ='设备'direction ='in'/>
< arg type ='s'name ='uuid'direction ='in’/>
< / method>
< method name =取消>
< / method>
< / interface>
< / node>;

info = g_dbus_node_info_new_for_xml(bluez_agent_introspection_xml,& error);
if(error){
g_printerr(无法创建节点:%s\n,错误->消息);
g_clear_error(& error);
返回0;
}

id = g_dbus_connection_register_object(con,
AGENT_PATH,
info-> interfaces [0],
& agent_method_table,
NULL,NULL和& error);
g_dbus_node_info_unref(info);
// g_dbus_connection_unregister_object(con,id);
/ * AgentManager1接口中的调用注册方法* /
返回ID;
}

static int bluez_agent_call_method(const gchar *方法,GVariant * param)
{
GVariant *结果;
GError * error = NULL;

结果= g_dbus_connection_call_sync(con,
org.bluez,
/ org / bluez,
org.bluez.AgentManager1,
方法,
参数,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
和错误);
if(error!= NULL){
g_print(寄存器%s:%s\n,AGENT_PATH,错误->消息);
返回1;
}

g_variant_unref(result);
返回0;
}

static int bluez_register_autopair_agent(const char * cap)
{
int rc;

rc = bluez_agent_call_method( RegisterAgent,g_variant_new((os),AGENT_PATH,cap));
if(rc)
返回1;

rc = bluez_agent_call_method( RequestDefaultAgent,g_variant_new((o),AGENT_PATH));
if(rc){
bluez_agent_call_method( UnregisterAgent,g_variant_new((o),AGENT_PATH));
返回1;
}

返回0;
}


静态无效cleanup_handler(int signo)
{
if(signo == SIGINT){
g_print(接收到SIGINT \n);
g_main_loop_quit(loop);
}
}

int main(int argc,char ** argv)
{
int id;
int rc;

if(argc< 2)
返回1;

if(signal(SIGINT,cleanup_handler)== SIG_ERR)
g_print(无法捕获SIGINT\n);

con = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL,NULL);
if(con == NULL){
g_print(无法连接到系统总线\n);
返回1;
}

loop = g_main_loop_new(NULL,FALSE);

id = bluez_register_agent(con);
if(id == 0)
失败;

rc = bluez_register_autopair_agent(argv [1]);
if(rc){
g_print(无法注册默认的自动配对代理\n);
失败;
}

g_main_loop_run(loop);

失败:
g_dbus_connection_unregister_object(con,id);
g_object_unref(con);
返回0;
}

要进行实验,您必须在bluetoothctl中禁用代理代理关闭并关闭

 响应者:./bin/agent KeyboardOnly 
发起方:./bin/agent KeyboardOnly

当您尝试从启动器端发起连接时,两端都会调用RequestPasskey 。您可以在最后输入相同的密钥。如果您要响应固定密钥PIN,请在功能 RequestPasskey 的响应者端编辑代理代码,方法是答复固定PIN并手动输入该PIN,或者从发起者自动输入相同的PIN结束。


I'm trying to setup Bluetooth on an embedded Linux device such that SSP mode is used, with my device generating and displaying a passcode on it's display, and the remote end (e.g. user's phone) being required to enter the matching passcode to be able to successfully pair.

I'm written/registered an agent that sets it's mode to DisplayOnly; I expected that when a device connects the "RequestPasskey" callback would be called and that my agent would then be able to generate and return a new passcode, and that the remote end would be required to enter this same code. The behaviour I actually see is that the remote end is generating it's own passcode.

I can achieve something like the required behaviour if I disable SSP and use legacy pairing, but I'd rather not have to do this.

Is it possible to achieve this behaviour with BlueZ?

解决方案

To simply the discussion here, please consider the explanation from Bluetooth Pairing blog from Bluetooth SIG.

To simplify, the below image is copied from the above mentioned blog.

So input can be three forms "No Input", "Yes/No" and "Keyboard". Output can be "No Output" and "Numeric Output".

In your case, you want to generate the passkey in Embedded Device (we can name this as responder) and enter the key in the device which initiates the connection (we can name this as initiator).

To achieve such case you need to specify,

Responder (Embedded Device): As "KeyboardOnly" Initiator: Also as "KeyboardOnly"

To experiment this, use the below example agent,

/*
 * gcc `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/agent ./agent.c `pkg-config --libs glib-2.0 gio-2.0`
 */
#include <glib.h>
#include <gio/gio.h>
#include <stdio.h>

GMainLoop *loop;
GDBusConnection *con;
#define AGENT_PATH  "/org/bluez/AutoPinAgent"

static void bluez_agent_method_call(GDBusConnection *conn,
                    const gchar *sender,
                    const gchar *path,
                    const gchar *interface,
                    const gchar *method,
                    GVariant *params,
                    GDBusMethodInvocation *invocation,
                    void *userdata)
{
    int pass;
    int entered;
    char *opath;
    GVariant *p= g_dbus_method_invocation_get_parameters(invocation);

    g_print("Agent method call: %s.%s()\n", interface, method);
    if(!strcmp(method, "RequestPinCode")) {
        ;
    }
    else if(!strcmp(method, "DisplayPinCode")) {
        ;
    }
    else if(!strcmp(method, "RequestPasskey")) {
        g_print("Getting the Pin from user: ");
        fscanf(stdin, "%d", &pass);
        g_print("\n");
        g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", pass));
    }
    else if(!strcmp(method, "DisplayPasskey")) {
        g_variant_get(params, "(ouq)", &opath, &pass, &entered);
        g_print("Path: %s Pass: %d Entered: %d\n", opath, pass, entered);
        g_dbus_method_invocation_return_value(invocation, NULL);
    }
    else if(!strcmp(method, "RequestConfirmation")) {
        g_variant_get(params, "(ou)", &opath, &pass);
        g_print("Path: %s Pass: %d\n", opath, pass);
        g_dbus_method_invocation_return_value(invocation, NULL);
    }
    else if(!strcmp(method, "RequestAuthorization")) {
        ;
    }
    else if(!strcmp(method, "AuthorizeService")) {
        ;
    }
    else if(!strcmp(method, "Cancel")) {
        ;
    }
    else
        g_print("We should not come here, unknown method\n");
}

static const GDBusInterfaceVTable agent_method_table = {
    .method_call = bluez_agent_method_call,
};

int bluez_register_agent(GDBusConnection *con)
{
    GError *error = NULL;
    guint id = 0;
    GDBusNodeInfo *info = NULL;

    static const gchar bluez_agent_introspection_xml[] =
        "<node name='/org/bluez/SampleAgent'>"
        "   <interface name='org.bluez.Agent1'>"
        "       <method name='Release'>"
        "       </method>"
        "       <method name='RequestPinCode'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='pincode' direction='out' />"
        "       </method>"
        "       <method name='DisplayPinCode'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='pincode' direction='in' />"
        "       </method>"
        "       <method name='RequestPasskey'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='out' />"
        "       </method>"
        "       <method name='DisplayPasskey'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='in' />"
        "           <arg type='q' name='entered' direction='in' />"
        "       </method>"
        "       <method name='RequestConfirmation'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='in' />"
        "       </method>"
        "       <method name='RequestAuthorization'>"
        "           <arg type='o' name='device' direction='in' />"
        "       </method>"
        "       <method name='AuthorizeService'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='uuid' direction='in' />"
        "       </method>"
        "       <method name='Cancel'>"
        "       </method>"
        "   </interface>"
        "</node>";

    info = g_dbus_node_info_new_for_xml(bluez_agent_introspection_xml, &error);
    if(error) {
        g_printerr("Unable to create node: %s\n", error->message);
        g_clear_error(&error);
        return 0;
    }

    id = g_dbus_connection_register_object(con, 
            AGENT_PATH,
            info->interfaces[0],
            &agent_method_table,
            NULL, NULL, &error);
    g_dbus_node_info_unref(info);
    //g_dbus_connection_unregister_object(con, id);
    /* call register method in AgentManager1 interface */
    return id;
}

static int bluez_agent_call_method(const gchar *method, GVariant *param)
{
    GVariant *result;
    GError *error = NULL;

    result = g_dbus_connection_call_sync(con,
            "org.bluez",
            "/org/bluez",
            "org.bluez.AgentManager1",
            method,
            param,
            NULL,
            G_DBUS_CALL_FLAGS_NONE,
            -1,
            NULL,
            &error);
    if(error != NULL) {
        g_print("Register %s: %s\n", AGENT_PATH, error->message);
        return 1;
    }

    g_variant_unref(result);
    return 0;
}

static int bluez_register_autopair_agent(const char *cap)
{
    int rc;

    rc = bluez_agent_call_method("RegisterAgent", g_variant_new("(os)", AGENT_PATH, cap));
    if(rc)
        return 1;

    rc = bluez_agent_call_method("RequestDefaultAgent", g_variant_new("(o)", AGENT_PATH));
    if(rc) {
        bluez_agent_call_method("UnregisterAgent", g_variant_new("(o)", AGENT_PATH));
        return 1;
    }

    return 0;
}


static void cleanup_handler(int signo)
{
    if (signo == SIGINT) {
        g_print("received SIGINT\n");
        g_main_loop_quit(loop);
    }
}

int main(int argc, char **argv)
{
    int id;
    int rc;

    if(argc < 2)
        return 1;

    if(signal(SIGINT, cleanup_handler) == SIG_ERR)
        g_print("can't catch SIGINT\n");

    con = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
    if(con == NULL) {
        g_print("Not able to get connection to system bus\n");
        return 1;
    }

    loop = g_main_loop_new(NULL, FALSE);

    id = bluez_register_agent(con);
    if(id == 0)
        goto fail;

    rc = bluez_register_autopair_agent(argv[1]);
    if(rc) {
        g_print("Not able to register default autopair agent\n");
        goto fail;
    }

    g_main_loop_run(loop);

fail:
    g_dbus_connection_unregister_object(con, id);
    g_object_unref(con);
    return 0;
}

To experiment this, you must disable agent in bluetoothctl "agent off" and turn on the agent as,

Responder: ./bin/agent "KeyboardOnly"
Initiator: ./bin/agent "KeyboardOnly"

When you try to initiate the connection from initiator end, RequestPasskey is called at both the end. Where you can enter the same key in both the end. If you want to respond Fixed Key PIN, you edit the agent code in "Responder" end for the function "RequestPasskey" by replying the Fixed PIN and entering the same PIN manually or again automatically from "Initiator" end as well.

这篇关于如何将BlueZ配置为要求连接设备输入匹配的通行密钥?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆