OpenHarmony解读之设备认证:sts协议-客户端发起sts end请求

一、概述

客户端收到来自服务端的响应消息之后,针对消息内容进行相关处理并再次发起sts end请求,目的在于发送可信认证数据,使得服务端可以验证客户端的身份。本文将对这个过程进行详细介绍。

二、源码分析

这一模块的源码位于:/base/security/deviceauth。

1. 首先是parse_auth_start_response函数,解析响应消息,用响应的结构体获取消息的关键字段数据。
scss 复制代码
/*
函数功能:解析认证start响应消息
函数参数:
    payload:消息负载
    data_type:数据类型
函数返回值:
    成功:返回解析完毕的数据结构
    失败:NULL
*/
void *parse_auth_start_response(const char *payload, enum json_object_data_type data_type)
{
    struct sts_start_response_data *auth_start_response =
        (struct sts_start_response_data *)MALLOC(sizeof(struct sts_start_response_data));//申请start响应数据结构体空间
    if (auth_start_response == NULL) {
        return NULL;
    }
    (void)memset_s(auth_start_response, sizeof(*auth_start_response), 0, sizeof(*auth_start_response));//清空该空间
    //如果消息负载为json格式的字符串,则将json格式的数据解析成cjson结构体对象
    json_handle obj = parse_payload(payload, data_type);
    if (obj == NULL) {
        LOGE("Parse AuthStart Response parse payload failed");//解析失败
        goto error;
    }
    /* authData */
    //获取authData,将原来的十六进制字符串格式转换为byte数组格式
    int32_t result = byte_convert(obj, FIELD_AUTH_DATA, auth_start_response->auth_data.auth_data,
                                  &auth_start_response->auth_data.length, HC_AUTH_DATA_BUFF_LEN);
    if (result != HC_OK) {//解析失败
        LOGE("Parse AuthStart Response failed, field is null in authData");
        goto error;
    }
    /* challenge */
    //获取challenge,将原来的十六进制字符串格式转换为byte数组格式
    result = byte_convert(obj, FIELD_CHALLENGE, auth_start_response->challenge.challenge,
                          &auth_start_response->challenge.length, CHALLENGE_BUFF_LENGTH);
    if (result != HC_OK) {//解析失败
        LOGE("Parse AuthStart Response failed, field is null in challenge");
        goto error;
    }
    /* salt */
    //获取salt,将原来的十六进制字符串格式转换为byte数组格式
    result = byte_convert(obj, FIELD_SALT, auth_start_response->salt.salt,
                          (uint32_t *)&auth_start_response->salt.length, HC_SALT_BUFF_LEN);
    if (result != HC_OK) {//解析失败
        LOGE("Parse AuthStart Response failed, field is null in salt");
        goto error;
    }
    /* epk */
    //获取epk,将原来的十六进制字符串格式转换为byte数组格式
    result = byte_convert(obj, FIELD_EPK, auth_start_response->epk.stpk,
                          &auth_start_response->epk.length, HC_ST_PUBLIC_KEY_LEN);
    if (result != HC_OK) {//解析失败
        LOGE("Parse AuthStart Response failed, field is null in epk");
        goto error;
    }
    /* version */
    json_pobject obj_ver = get_json_obj(obj, FIELD_VERSION);
    bool ret = parse_version(obj_ver, &auth_start_response->self_version, &auth_start_response->self_support_version);//解析版本号
    if (!ret) {
        LOGE("Parse AuthStart Response failed, field is null in version");
        goto error;
    }
    free_payload(obj, data_type);//释放内存
    return (void *)auth_start_response;//返回响应消息结构体
error:
    free_payload(obj, data_type);
    FREE(auth_start_response);
    return NULL;
}
2. 然后到消息处理阶段,执行proc_sts_response_message函数,处理sts响应消息。
rust 复制代码
/*
函数功能:处理sts响应消息
函数参数:
    handle:hichain实例
    nav:导航消息,消息头格式
    receive:接收的消息
    send:待发送消息
函数返回值:
    成功:0
    失败:error num
*/
static int32_t proc_sts_response_message(struct hichain *handle, struct header_analysis *nav,
    struct message *receive, struct message *send)
#if !(defined(_CUT_STS_) || defined(_CUT_STS_CLIENT_))
{
    DBG_OUT("Object %u proc sts %d response message.", sts_client_sn(handle->sts_client), nav->msg_type);
    int32_t ret;
    if (nav->msg_type == STS_START_MSG) {//根据消息类型选择不同的处理接口
        ret = send_sts_end_request(handle->sts_client, receive, send);//构造sts end请求数据
    } else if (nav->msg_type == STS_END_MSG) {
        ret = receive_sts_end_response(handle->sts_client, receive);//处理sts end响应消息
        if (ret == HC_OK) {
            handle->cb.set_session_key(&handle->identity, &handle->sts_client->service_key);//设置会话密钥service_key
        }
    } else {
        return HC_UNKNOW_MESSAGE;
    }
    return ret;
}
3. send_sts_end_request函数,构造sts协议的end请求,为该请求准备相关数据。
scss 复制代码
/*
函数功能:构造sts协议的end请求,为该请求准备相关数据
函数参数:
    sts_client:sts客户端对象
    receive:接收到的消息
    send:待发送消息体
函数返回值:
    成功:0
    失败:error num
*/
int32_t send_sts_end_request(struct sts_client *sts_client, const struct message *receive, struct message *send)
{
    DBG_OUT("Receive data send_sts_start_response");
    check_ptr_return_val(sts_client, HC_INPUT_ERROR);//检查参数有效性
    check_ptr_return_val(receive, HC_INPUT_ERROR);
    check_ptr_return_val(send, HC_INPUT_ERROR);
    struct sts_start_response_data *receive_data = (struct sts_start_response_data *)receive->payload;//用sts_start_response_data结构接收消息负载
    struct sts_end_request_data *send_data =
        (struct sts_end_request_data *)MALLOC(sizeof(struct sts_end_request_data));//定义end请求结构体对象并申请内存空间
    if (send_data == NULL) {
        LOGE("Malloc struct STS_END_REQUEST_DATA failed");
        return HC_MALLOC_FAILED;
    }
    (void)memset_s(send_data, sizeof(*send_data), 0, sizeof(*send_data));//清空该空间
    int32_t ret = send_end_request(sts_client, receive_data, send_data);//构造end请求数据
    if (ret != HC_OK) {//执行失败
        LOGE("Called send_end_request failed, error code is %d", ret);
        FREE(send_data);
        send->msg_code = INFORM_MESSAGE;
    } else {//执行成功
        DBG_OUT("Called send_end_request success");
        send->msg_code = AUTH_ACK_REQUEST;//置待发送的消息码为AUTH_ACK_REQUEST
        send->payload = send_data;//赋值消息负载
    }
    return ret;
}
/*
函数功能:准备待发送的end请求数据
函数参数:
    handle:句柄,可用相关结构体获取
    receive_data:接收到的消息数据
    send_data:待发送数据地址
函数返回值:
    成功:0
    失败:error num
*/
int32_t send_end_request(void *handle, void *receive_data, void *send_data)
{
    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性
    check_ptr_return_val(receive_data, HC_INPUT_ERROR);
    check_ptr_return_val(send_data, HC_INPUT_ERROR);
    struct key_agreement_client *client = (struct key_agreement_client *)handle;//用密钥协商客户端接收该对象
    struct key_agreement_protocol *base = &client->protocol_base_info;//定义密钥协商协议基础信息
    DBG_OUT("Object %u begin receive start response data and send end request data", base->sn);
    if (is_state_error(client, SEND_END_REQUEST)) {//判断协议状态和协议动作是否对应错误
        LOGE("Object %u state error", base->sn);
        return PROTOCOL_STATE_ERROR;
    }
    struct client_virtual_func_group *funcs = &client->package_funcs;//客户端虚函数组,定义打包函数
    int32_t ret = funcs->parse_start_response_data(handle, receive_data);//解析start响应数据
    if (ret != HC_OK) {
        set_state(base, PROTOCOL_ERROR);
        LOGE("Object %u parse start response data failed, error code is %d", base->sn, ret);
        return ret;
    }
    ret = funcs->build_end_request_data(handle, send_data);//构造end请求数据保存在send_data中
    if (ret != HC_OK) {
        set_state(base, PROTOCOL_ERROR);
        LOGE("Object %u build end request data failed, error code is %d", base->sn, ret);
        return ret;
    }
    set_state(base, END_REQUEST);//设置协议状态为END_REQUEST
    set_last_time_sec(base);//设置上一次的时间
    DBG_OUT("Object %u receive start response data and send end request data success", base->sn);
    return HC_OK;
}
4. 在上述函数中调用parse_start_response_data函数,解析start响应数据。
rust 复制代码
/*
函数功能:解析start响应数据
函数参数:
    handle:sts客户端对象
    data:接收到的数据
函数返回值:
    成功:0
    失败:error num
详细:
    解析出相关数据填充sts_client对象,然后根据相关数据基于hkdf算法生成客户端会话密钥。
*/
static int32_t parse_start_response_data(void *handle, void *data)
{
    struct sts_client *sts_client = (struct sts_client *)handle;//接收sts客户端对象
    struct sts_start_response_data *receive = (struct sts_start_response_data *)data;//同sts_start_response_data结构接收数据
    sts_client->salt = receive->salt;//赋值salt
    sts_client->peer_public_key = receive->epk;//赋值对端临时公钥
    sts_client->peer_challenge = receive->challenge;//赋值对端challenge
    sts_client->peer_auth_data = receive->auth_data;//保存对端认证数据
    sts_client->peer_user_type = receive->peer_user_type;//赋值对端用户类型
    struct sts_shared_secret shared_secret;//定义sts共享密钥
    //根据本端临时私钥self_private_key和对端临时公钥peer_public_key计算sts共享密钥shared_secret
    int32_t ret = compute_sts_shared_secret(&sts_client->self_private_key,
                                            &sts_client->peer_public_key, &shared_secret);
    if (ret != HC_OK) {
        LOGE("Object %u compute_shared_secret failed, error code is %d", sts_client_sn(sts_client), ret);
        return ret;
    }
    //共享密钥shared_secret作为种子+salt+"hichain_auth_info"根据hkdf算法计算出一个派生密钥作为会话密钥session_key
    ret = compute_hkdf((struct var_buffer *)&shared_secret, &sts_client->salt, HICHAIN_AUTH_INFO,
                       STS_SESSION_KEY_LENGTH, (struct var_buffer *)&sts_client->session_key);
    if (ret != HC_OK) {//生成失败
        LOGE("Object %u compute_hkdf failed, error code is %d", sts_client_sn(sts_client), ret);
        return HC_STS_OBJECT_ERROR;
    }
    return HC_OK;
}

DD一下: 欢迎大家关注公众号<程序猿百晓生>,可以了解到以下知识点。

erlang 复制代码
`欢迎大家关注公众号<程序猿百晓生>,可以了解到以下知识点。`
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案) 
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.【OpenHarmony】Uboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......
5. build_end_request_data函数,构造end请求数据。
scss 复制代码
/*
函数功能:构造end请求数据
函数参数:
    handle:sts_client对象
    data:待发送数据
函数返回值:
    成功:0
    失败:error num
详细:
    首先验证对端签名数据,即验证对端身份是否可信,然后产生本端签名数据作为本端验证数据,利用本端私钥签名。
然后进行对称密钥加密。
*/
static int32_t build_end_request_data(void *handle, void *data)
{
    struct sts_client *sts_client = (struct sts_client *)handle;//接收sts客户端对象
    struct sts_end_request_data *send = (struct sts_end_request_data *)data;//sts end请求数据结构接收该数据
    int32_t ret = verify_data(handle);//验证响应签名数据,即验证对端身份
    if (ret != HC_OK) {
        return ret;
    }
    struct signature request_sign = { 0, {0} };//定义请求签名缓冲区
    ret = generate_sts_request_sign(handle, &request_sign);//生成sts请求签名
    if (ret != HC_OK) {
        return ret;
    }
    struct uint8_buff out_auth_data;//定义输出认证数据缓冲区
    ret = init_auth_data(&out_auth_data);//初始化认证数据,申请缓冲区并清零
    if (ret != HC_OK) {
        return ret;
    }
    struct aes_aad aes_aad;//aes GCM附加验证数据
    if (memcpy_s(aes_aad.aad, sizeof(aes_aad.aad), sts_client->peer_challenge.challenge,
        sts_client->peer_challenge.length) != EOK) {//将对端challenge值拷贝到aes_aad
        FREE(out_auth_data.val);
        return memory_copy_error(__func__, __LINE__);
    }
    aes_aad.length = sts_client->peer_challenge.length;//获取长度
    //定义明文缓冲区,信息为签名数据
    struct uint8_buff plain = {request_sign.signature, request_sign.length, request_sign.length};
    //用会话密钥对该明文进行aes_gcm加密,输出密文保存在auth_data中
    ret = aes_gcm_encrypt((struct var_buffer *)&sts_client->session_key, &plain, &aes_aad, &out_auth_data);
    if (ret != HC_OK) {//加密失败
        FREE(out_auth_data.val);
        LOGE("Object %u aes_gcm_encrypt failed, error code is %d", sts_client_sn(sts_client), ret);
        return HC_ENCRYPT_FAILED;
    }
    //将加密后的auth_data拷贝到待发送的响应消息体中
    if (memcpy_s(send->auth_data.auth_data, sizeof(send->auth_data.auth_data),
        out_auth_data.val, out_auth_data.length) != EOK) {
        FREE(out_auth_data.val);
        return memory_copy_error(__func__, __LINE__);
    }
    send->auth_data.length = out_auth_data.length;//赋值加密认证数据长度
    FREE(out_auth_data.val);
    return HC_OK;
}
/*
函数功能:验证签名数据,即验证对端身份
函数参数:
    handle:hichain子对象
函数返回值:
    ok:0
    not ok:error num
*/
static int32_t verify_data(void *handle)
{
    struct signature signature = { 0, {0} };//定义签名
    int32_t ret = init_signature(handle, &signature);//初始化签名数据,解密对端认证数据作为签名数据
    if (ret != HC_OK) {
        return ret;
    }
    struct uint8_buff message;//定义消息缓冲区
    (void)memset_s(&message, sizeof(message), 0, sizeof(message));//清空该消息缓冲区
    //生成本端的签名消息:{服务端公钥、服务端认证id、客户端公钥、客户端认证id}
    ret = generate_sign_message(handle, &message);
    if (ret != HC_OK) {
        return ret;
    }
    ret = verify_response_data(handle, &message, &signature);//验证响应数据是否正确,即验证对端身份
    FREE(message.val);//释放签名消息缓冲区
    message.val = NULL;
    if (ret != HC_OK) {
        return ret;
    }
    return HC_OK;
}
/*
函数功能:初始化签名数据,解密对端认证数据作为签名数据
函数参数:
    handle:sts_client对象
    signature:输出参数,签名
函数返回值:
    成功:0
    失败:error num
*/
static int32_t init_signature(void *handle, struct signature *signature)
{
    struct sts_client *sts_client = (struct sts_client *)handle;//接收sts客户端对象
    struct aes_aad aes_aad;//aes GCM附加验证数据
    if (memcpy_s(aes_aad.aad, sizeof(aes_aad.aad), sts_client->my_challenge.challenge,
                 sts_client->my_challenge.length) != EOK) {//将本端challenge值拷贝到aes_aad
        return memory_copy_error(__func__, __LINE__);
    }
    aes_aad.length = sts_client->my_challenge.length;//获取长度
    struct uint8_buff out_plain = { 0, 0, 0 };//定义明文输出缓冲区,用于保存解密后的数据
    out_plain.val = (uint8_t *)MALLOC(sts_client->peer_auth_data.length);//为该缓冲区申请空间
    if (out_plain.val == NULL) {
        LOGE("Malloc peer_auth_data failed");
        return HC_MALLOC_FAILED;
    }
    (void)memset_s(out_plain.val, sts_client->peer_auth_data.length, 0, sts_client->peer_auth_data.length);//清空该空间
    out_plain.size = sts_client->peer_auth_data.length;//缓冲区大小为对端认证数据长度
    //定义一个认证数据缓冲区保存对端发来的auth_data
    struct uint8_buff auth_data = {sts_client->peer_auth_data.auth_data, sts_client->peer_auth_data.length,
                                   sts_client->peer_auth_data.length};
    //利用会话密钥对对端auth_data进行解密,解密后的数据保存在out_plain
    int32_t ret = aes_gcm_decrypt((struct var_buffer *)&sts_client->session_key, &auth_data, &aes_aad, &out_plain);
    if (ret != HC_OK) {
        FREE(out_plain.val);
        LOGE("Object %u aes_gcm_decrypt failed, error code is %d", sts_client_sn(sts_client), ret);
        return HC_DECRYPT_FAILED;//解密失败返回错误码
    }
    if (memcpy_s(signature->signature, sizeof(signature->signature), out_plain.val, out_plain.length) != EOK) {//将解密后的auth_data拷贝给signature签名
        FREE(out_plain.val);
        return memory_copy_error(__func__, __LINE__);
    }
    signature->length = out_plain.length;
    FREE(out_plain.val);
    return HC_OK;
}
/*
函数功能:生成签名消息:{服务端公钥、服务端认证id、客户端公钥、客户端认证id}
函数参数:
    handle:sts_client对象
    message:输出参数,签名消息缓冲区
函数返回值:
    成功:0
    失败:error num
*/
static int32_t generate_sign_message(void *handle, struct uint8_buff *message)
{
    DBG_OUT("Called generate sign message");
    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性
    check_ptr_return_val(message, HC_INPUT_ERROR);
    struct sts_client *sts_client = (struct sts_client *)handle;//接收sts客户端对象
    //服务端公钥、服务端认证id、客户端公钥、客户端认证id长度之和
    int len = sts_client->peer_public_key.length + sts_client->peer_id.length +
              sts_client->self_public_key.length + sts_client->self_id.length;
    uint8_t *info = (uint8_t *)MALLOC(len);//申请len长度的缓冲区info
    if (info == NULL) {
        LOGE("Malloc info failed");
        return HC_MALLOC_FAILED;
    }
    int32_t pos = 0;
    //将服务端公钥、服务端认证id、客户端公钥、客户端认证id按顺序拷贝到info缓冲区中
    (void)memcpy_s(info + pos, len - pos, sts_client->peer_public_key.stpk, sts_client->peer_public_key.length);
    pos += sts_client->peer_public_key.length;
    (void)memcpy_s(info + pos, len - pos, sts_client->peer_id.auth_id, sts_client->peer_id.length);
    pos += sts_client->peer_id.length;
    (void)memcpy_s(info + pos, len - pos, sts_client->self_public_key.stpk, sts_client->self_public_key.length);
    pos += sts_client->self_public_key.length;
    (void)memcpy_s(info + pos, len - pos, sts_client->self_id.auth_id, sts_client->self_id.length);
    //即 info = {服务端公钥、服务端认证id、客户端公钥、客户端认证id}
    message->val = info;//将上述内容赋给签名消息缓冲区
    message->length = len;
    message->size = len;
    return HC_OK;
}
/*
函数功能:验证响应数据
函数参数:
    handle:sts_client对象
    message:待验证的消息
    signature:对比签名
函数返回值:
    ok:0
    not ok:error num
*/
static int32_t verify_response_data(void *handle, const struct uint8_buff *message, struct signature *signature)
{
    DBG_OUT("Called verify request data");
    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性
    check_ptr_return_val(message, HC_INPUT_ERROR);
    check_ptr_return_val(signature, HC_INPUT_ERROR);
    struct sts_client *sts_client = (struct sts_client *)handle;//接收sts客户端对象
    struct hichain *hichain_handle = sts_client->hichain_handle;//获取hichain实例
    enum huks_key_alias_type alias_type;//密钥别名类型
    if (hichain_handle->type == HC_CENTRE) {//根据hc类型决定密钥别名(密钥对)类型
        if (sts_client->peer_user_type == HC_USER_TYPE_CONTROLLER) { /* center(as phone identity) -> phone */
            alias_type = KEY_ALIAS_LT_KEY_PAIR;
        } else { /* center -> accessory */
            alias_type = KEY_ALIAS_ACCESSOR_PK;
        }
    } else { /* accessory -> center/phone */
        alias_type = KEY_ALIAS_CONTROLLER_PK;
    }
    //利用会话标识符的HC包名称和HC服务类型通过sha256哈希算法计算出哈希值,作为服务id
    struct service_id service_id = generate_service_id(sts_client->identity);
    if (service_id.length == 0) {
        LOGE("Generate service id failed");
        return HC_GEN_SERVICE_ID_FAILED;
    }
    struct hc_key_alias key_alias = generate_key_alias(&service_id, &sts_client->peer_id, alias_type);//根据服务id和对端认证id生成密钥别名
    if (key_alias.length == 0) {
        LOGE("Generate key alias failed");
        return HC_GEN_ALIAS_FAILED;
    }
    //通过ED25519长期公钥验证签名是否正确(用对端公钥解密)
    int32_t ret = verify(&key_alias, sts_client->peer_user_type, message, signature);
    if (ret != HC_OK) {
        LOGE("Object %u verify failed, error code is %d", sts_client_sn(sts_client), ret);
        return HC_VERIFY_PROOF_FAILED;
    }
    return HC_OK;
}
/*
函数功能:生成sts请求签名
函数参数:
    handle:sts_client对象
    signature:签名数据
函数返回值:
    成功:0
    失败:error num
*/
static int32_t generate_sts_request_sign(void *handle, struct signature *signature)
{
    struct sts_client *sts_client = (struct sts_client *)handle;//接收sts客户端对象
    //客户端公钥、客户端认证id、服务端公钥、服务端认证id 长度之和
    int32_t len = sts_client->self_public_key.length + sts_client->self_id.length +
                  sts_client->peer_public_key.length + sts_client->peer_id.length;
    uint8_t *info = (uint8_t *)MALLOC(len);//申请len长度的缓冲区info
    if (info == NULL) {
        LOGE("Malloc info failed");
        return HC_MALLOC_FAILED;
    }
    int32_t pos = 0;
    //将客户端公钥、客户端认证id、服务端公钥、服务端认证id按顺序拷贝到info2缓冲区中
    (void)memcpy_s(info + pos, len - pos, sts_client->self_public_key.stpk, sts_client->self_public_key.length);
    pos += sts_client->self_public_key.length;
    (void)memcpy_s(info + pos, len - pos, sts_client->self_id.auth_id, sts_client->self_id.length);
    pos += sts_client->self_id.length;
    (void)memcpy_s(info + pos, len - pos, sts_client->peer_public_key.stpk, sts_client->peer_public_key.length);
    pos += sts_client->peer_public_key.length;
    (void)memcpy_s(info + pos, len - pos, sts_client->peer_id.auth_id, sts_client->peer_id.length);
    //即 info = {客户端公钥、客户端认证id、服务端公钥、服务端认证id}
    struct service_id service_id = generate_service_id(sts_client->identity);//利用会话标识符的HC包名称和HC服务类型通过sha256哈希算法计算出哈希值,作为服务id
    if (service_id.length == 0) {
        LOGE("Generate service id failed");
        FREE(info);
        return HC_GEN_SERVICE_ID_FAILED;
    }
#if (defined(_SUPPORT_SEC_CLONE_) || defined(_SUPPORT_SEC_CLONE_SERVER_))
    struct hc_key_alias key_alias = generate_key_alias(&service_id, &sts_client->self_id, KEY_ALIAS_LT_KEY_PAIR);
#else
    //通过服务id和认证id生成密钥别名
    struct hc_key_alias key_alias = generate_key_alias(&service_id, &sts_client->self_id, KEY_ALIAS_ACCESSOR_PK);
#endif
    if (key_alias.length == 0) {
        LOGE("Generate key alias failed");
        FREE(info);
        return HC_GEN_ALIAS_FAILED;//生成别名失败
    }
    //定义签名消息缓冲区并初始化为 {客户端公钥、客户端认证id、服务端公钥、服务端认证id}
    struct uint8_buff sign_message = { info, len, len };
    //将{客户端公钥、客户端认证id、服务端公钥、服务端认证id}信息利用ED25519算法进行私钥签名,输出结果保存在signature中
    int32_t ret = sign(&key_alias, &sign_message, signature);
    if (ret != HC_OK) {
        LOGE("Object %u sign failed, error code is %d", sts_client_sn(sts_client), ret);
        FREE(info);
        return HC_SIGN_EXCHANGE_FAILED;
    }
    FREE(info);
    return ret;
}
6. 最后执行make_auth_ack_request函数,构造json格式的认证ack请求消息。
scss 复制代码
/*
函数功能:构造json格式的认证ack请求消息
函数参数:
    data:待发送数据
函数返回值:
    成功:json格式的字符串
    失败:NULL
*/
char *make_auth_ack_request(void *data)
{
    struct sts_end_request_data *auth_ack_request = data;
    /* authdata */
    uint8_t *tmp_data_hex = raw_byte_to_hex_string(auth_ack_request->auth_data.auth_data,
                                                   auth_ack_request->auth_data.length);//将原始的authdata字节数据转换为十六进制的字符串
    if (tmp_data_hex == NULL) {
        return NULL;
    }
    char *ret_str = (char *)MALLOC(RET_STR_LENGTH);//为json字符串申请空间
    if (ret_str == NULL) {
        FREE(tmp_data_hex);
        return NULL;
    }
    (void)memset_s(ret_str, RET_STR_LENGTH, 0, RET_STR_LENGTH);//清空该空间
    if (snprintf_s(ret_str, RET_STR_LENGTH, RET_STR_LENGTH - 1, "{\"%s\":%d,\"%s\":%d,\"%s\":{\"%s\":\"%s\"}}",
        FIELD_AUTH_FORM, AUTH_FORM, FIELD_MESSAGE, AUTH_ACK_REQUEST, FIELD_PAYLOAD,
        FIELD_AUTH_DATA, tmp_data_hex) < 0) {
        LOGE("String generate failed");
        FREE(ret_str);
        ret_str = NULL;
    }//生成json格式的请求消息
    FREE(tmp_data_hex);
    return ret_str;
}

三、小结

经过分析,客户端发起的ack请求消息格式如下:

json 复制代码
{
    "authForm":0,
    "message":0x0012,           //消息码:AUTH_ACK_REQUEST
    "payload":
    {
        "authData":"十六进制格式的字符串"       //加密的签名消息,ED25519算法进行私钥签名
    }
}

这个过程主要是对来自服务端的签名消息进行一个身份验证,然后再发送自身的签名消息给到服务端。

相关推荐
TDengine (老段)28 分钟前
TDengine 在金融领域的应用
大数据·数据库·物联网·金融·时序数据库·tdengine·涛思数据
雪芽蓝域zzs1 小时前
鸿蒙Next开发 获取APP缓存大小和清除缓存
缓存·华为·harmonyos
猎板阿权1 小时前
出于PCB设计层面考虑,连排半孔需要注意哪些事项?
单片机·物联网·平面
TDengine (老段)2 小时前
TDengine 做为 Spark 数据源
大数据·数据库·物联网·ajax·spark·时序数据库·tdengine
欢乐熊嵌入式编程2 小时前
智能手表整机装配作业指导书(SOP)
嵌入式硬件·物联网·目标跟踪·智能手表
清月电子4 小时前
KT148A语音芯片发码很难播放_将4脚对地一下再发正常,什么原因?
单片机·嵌入式硬件·物联网·音视频
鸿蒙布道师5 小时前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
欢乐熊嵌入式编程7 小时前
智能手表软件架构设计文档初稿
嵌入式硬件·物联网·开源软件·智能手表
dzzzs11 小时前
科技创业园共享会议室线上预约及智能密码锁系统搭建指南
物联网
忧虑的乌龟蛋12 小时前
嵌入式Linux I2C驱动开发详解
linux·驱动开发·嵌入式·iic·i2c·读数据·写数据