一、概述
本文将详细分析auth_conn.c文件的源码,该文件主要为设备间的身份可信认证过程提供了数据发送、数据接收、认证、获取秘钥等功能,如认证数据的处理、构造回复消息、构造请求消息等。
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.鸿蒙版性能优化指南
.......
二、源码分析
auth_conn.c
scss
/*
* Copyright (c) 2020 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "auth_conn.h"
#include <string.h>
#include "aes_gcm.h"
#include "auth_interface.h"
#include "os_adapter.h"
#include "securec.h"
#include "tcp_socket.h"
/*发送身份认证连接消息*/
int AuthConnSend(int fd, const char *buf, int offset, int count, int timeout)
{
if ((buf == NULL) || (offset < 0) || (count <= 0) || (offset + count <= 0)) {
return -1;
}
return TcpSendData(fd, buf + offset, count, timeout);//发送数据
}
/*
函数功能:接收设备认证过程中传输的数据
函数参数:
fd:用于TCP通信的套接字fd
buf:数据缓冲区首地址
offset:缓冲区数据偏移
count:缓冲区剩余量
timeout:超时时间
函数返回值:
成功:返回收到的数据大小
失败:返回-1
详细:
*/
int AuthConnRecv(int fd, char *buf, int offset, int count, int timeout)
{
if ((buf == NULL) || (offset < 0) || (count <= 0) || (offset + count <= 0)) {//健壮性检查,越界检查
return -1;
}
return TcpRecvData(fd, buf + offset, count, timeout);//传入数据偏移后的地址,用于存储新收到的数据
}
/*
函数功能:根据module参数判断是否使用密文传输
函数参数:
module:数据包类型
函数返回值:
若数据包类型在MODULE_TRUST_ENGINE和MODULE_HICHAIN_SYNC之间,以及MODULE_AUTH_CHANNEL和MODULE_AUTH_MSG之间,则返回false,表示以明文传输
若数据包类型不在上述区间,则返回true,表示以密文传输
详细:
*/
bool ModuleUseCipherText(int module)
{
if (module >= MODULE_TRUST_ENGINE && module <= MODULE_HICHAIN_SYNC) {
return false;
}
if (module >= MODULE_AUTH_CHANNEL && module <= MODULE_AUTH_MSG) {
return false;
}
return true;
}
/*
函数功能:获取加密传输数据
函数参数:
seqNum:数据包序列号
dataIn:要传输的实际内容
data:数据包负载部分偏移地址
dataLen:数据包负载部分的长度
bufLen:用于存储整个数据包的缓冲区大小
函数返回值:
成功:返回0
失败:返回-1
详细:
*/
static int GetEncryptTransData(long long seqNum, const char *dataIn, unsigned char *data, unsigned int dataLen,
int *bufLen)
{
SessionKey *skey = AuthGetNewSessionKey();//获取一个新的会话密钥
if (skey == NULL) {
return -1;
}
if (memcpy_s(data, sizeof(int), &skey->index, sizeof(int)) != EOK) {//为负载部分加上index字段
return -1;
}
data += sizeof(int);
AesGcmCipherKey cipherKey = {0};
cipherKey.keybits = GCM_KEY_BITS_LEN_128;//密钥位数
int ret = memcpy_s(cipherKey.key, SESSION_KEY_LENGTH, skey->key, AUTH_SESSION_KEY_LEN);//将获取到的会话密钥赋给当前要进行加密的密钥
unsigned char* randomIv = GenerateRandomIv();//产生随机IV值
if (randomIv == NULL) {
return -1;
}
ret += memcpy_s(cipherKey.iv, IV_LEN, randomIv, IV_LEN);
free(randomIv);
ret += memcpy_s(cipherKey.iv, sizeof(seqNum), &seqNum, sizeof(seqNum));//???
if (ret != 0) {
return -1;
}
int cipherLen = EncryptTransData(&cipherKey, (const unsigned char*)dataIn, strlen(dataIn), data, dataLen);//加密传输数据
if (cipherLen <= 0) {
return -1;
}
*bufLen = cipherLen + PACKET_HEAD_SIZE + MESSAGE_INDEX_LEN;//更新bufLen的值,代表整个数据包的大小
return 0;
}
/*
函数参数:按字节构造设备身份认证数据包
函数参数:
module:数据包类型
flags:数据包头部标志位
seqNum:数据包序列号
str:实际要传输的数据内容
bufLen:保存数据包的缓冲区大小,整个数据包大小(传输层以上)
函数返回值:
成功:返回数据包缓冲区首地址
失败:返回NULL
详细:
*/
unsigned char* AuthConnPackBytes(int module, int flags, long long seqNum, const char *str, int *bufLen)
{
if ((str == NULL) || (bufLen == NULL)) {
return NULL;
}
bool isCipherText = ModuleUseCipherText(module);//根据module参数判断是否使用密文传输
int dataLen = isCipherText ? (strlen(str) + MESSAGE_ENCRYPT_OVER_HEAD_LEN) : strlen(str);
int len = dataLen + PACKET_HEAD_SIZE;//数据包总长度
unsigned char *buf = (unsigned char *)calloc(1, sizeof(unsigned char) * len);//申请保存数据包的内存空间
if (buf == NULL) {
return NULL;
}
unsigned char *data = buf;//用一个局部指针变量来作为偏移地址
//构造认证数据包头部
int identifier = PKG_HEADER_IDENTIFIER;
unsigned int ret = (unsigned int)memcpy_s(data, sizeof(int), &identifier, sizeof(int));
data += sizeof(int);
ret |= (unsigned int)memcpy_s(data, sizeof(int), &module, sizeof(int));
data += sizeof(int);
ret |= (unsigned int)memcpy_s(data, sizeof(long long), &seqNum, sizeof(long long));
data += sizeof(long long);
ret |= (unsigned int)memcpy_s(data, sizeof(int), &flags, sizeof(int));
data += sizeof(int);
ret |= (unsigned int)memcpy_s(data, sizeof(int), &dataLen, sizeof(int));
data += sizeof(int);
if (ret != 0) {
free(buf);
return NULL;
}
if (isCipherText) {//若使用密文传输
if (GetEncryptTransData(seqNum, str, data, dataLen, bufLen) != 0) {
free(buf);
return NULL;
}
} else {
if (memcpy_s(data, dataLen, str, dataLen) != EOK) {
free(buf);
return NULL;
}
*bufLen = len;//更新bufLen的值,代表整个数据包的大小
}
return buf;
}
/*
函数功能:按字节构造身份认证连接的POST消息并通过TCP协议发送
函数参数:
fd:通信fd
module:数据包类型
flags:消息类型标记
seq:数据包序列号
data:负载数据
函数返回值:
成功:返回0
失败:返回-1
详细:
*/
int AuthConnPostBytes(int fd, int module, int flags, long long seq, const char *data)
{
if (data == NULL) {
return -1;
}
int bufLen = 0;
unsigned char *buf = AuthConnPackBytes(module, flags, seq, data, &bufLen);//构造身份认证数据包
if (buf == NULL) {
return -1;
}
int ret = AuthConnSend(fd, (char *)buf, 0, bufLen, 0);//通过TCP发送认证消息
free(buf);
buf = NULL;
if (ret != bufLen) {
SOFTBUS_PRINT("[AUTH] AuthConnPostBytes send fail\n");
return -1;
}
return 0;
}
/*
函数功能:构造/封装身份认证Post消息并发送给对端
函数参数:
fd:通信fd
module:数据包类型
flags:消息类型标记
seqNum:数据包序列号
msg:cJSON格式的数据负载
函数返回值:
成功:返回0
失败:返回-1
详细:
*/
int AuthConnPostMessage(int fd, int module, int flags, long long seqNum, const cJSON *msg)
{
if (msg == NULL) {
return -1;
}
char *msgStr = cJSON_PrintUnformatted(msg);//将cJSON对象输出为无格式的字符串
if (msgStr == NULL) {
return -1;
}
int ret = AuthConnPostBytes(fd, module, flags, seqNum, msgStr);//按字节构造身份认证连接的POST消息并通过TCP协议发送
free(msgStr);
msgStr = NULL;
return ret;
}