一.简介
设备之间互联是基于系统的IoT设备(如AI音箱、智能家居、智能穿戴等设备)与IoT主控设备(手机、平板等)间建立点对点的信任关系,并在具备信任关系的设备间,搭建安全的连接通道,实现用户数据端到端加密传输。
IoT主控设备和IoT设备建立点对点信任关系的过程,实际上是相互交换IoT设备的身份标识的过程。
authmanager是openharmony为设备提供认证机制的模块,模块内的处理流程为
二.HiChan(设备互联安全)
为了实现用户数据在设备互联场景下,在各个设备之间的安全流转,实现用户数据的安全传输。设备之间的信任关系指的是本文档中涉及IoT主控设备和IoT设备之间建立的可信关系。
三.加密框架mbedtls
AES-GCM加密算法:AES是一种对称加密算法,GCM是对该对称加密采用Counter模式,并带有GMAC消息认证码。AES-GCM算法是带认证和加密的算法,同时可以对给定的原文,生成加密数据和认证码。
首先调用intmbedtls_gcm_setkey(mbedtls_gcm_context*ctx,mbedtls_cipher_id_tcipher,constunsignedchar*key,unsignedintkeybits),该函数将GCM上下文与密码算法和密钥相关联。
加密调用:intmbedtls_gcm_crypt_and_tag(mbedtls_gcm_context*ctx,intmode,size_tlength,constunsignedchar*iv,size_tiv_len,constunsignedchar*add,size_tadd_len,constunsignedchar*input,unsignedchar*output,size_ttag_len,unsignedchar*tag),加密后的数据以出参形式传出。
解密调用:intmbedtls_gcm_auth_decrypt(mbedtls_gcm_context*ctx,size_tlength,constunsignedchar*iv,size_tiv_len,constunsignedchar*add,size_tadd_len,constunsignedchar*tag,size_ttag_len,constunsignedchar*input,unsignedchar*output),解密后的数据以出参形式传出。
四.流程详解与关键代码数据结构:
1初始化代码流程如下图所示:
该部分主要由discover模块调用BusManager函数开始,若flag=1,则进行StartBus函数的执行,它的实现主要是调用了StartListener函数及StartSession函数,实现对设备进行认证及加解密的过程。
关键数据结构
注册回调函数的全局变量g_baseLister
typedefstruct{
OnConnectEventProconConnectEvent;
OnDataEventProconDataEvent;
}BaseListener;
关键接口StartListener
StartSession
StartSession该函数只有一个参数,即constchar*ip,也就是一个IP,和StartListener函数中的IP是一样的。该函数是为全局变量g_sessionMgr申请空间及初始化,然后根据所给的参数创建socket文件描述符并监听,之后通过调用StartSelectLoop函数创建SelectSessionLoop的线程,该线程将socket文件描述符加入集合,并调用select函数进行监控,若函数的返回值大于0,则调用ProcessData函数,该函数有两个分支,若socket未创建session则为其创建session;若已创建session,则处理其数据部分。
2.工作流程(消息处理流程)
2.1工作流程图如下
该部分主要有两个对外接口,一个是连接管理,另一个是数据处理。
数据处理流程图如下
该部分为收到数据后的整体处理流程,包括数据接收、包头解析和包数据处理。通过调用FindAuthConnByFd接口获取到连接结构AuthConn后,用AuthConnRecv来接收数据,通过ProcessPackets对收到的包处理,在ParsePacketHead中对包头解析,OnDataReceived中对数据处理,MODULE_AUTH_SDK类型包经过hichain处理流程,处理过程中调用回调函数AuthOnTransmit,AuthGetProtocolParams,AuthSetSessionKey,AuthSetServiceResult,AuthConfirmReceiveRequest,其他包都会通过cJSON_Parse函数对数据解析,最后都会为MODULE_TRUST_ENGINE包和MODULE_CONNECTION包构造一个reply包发送给对端验证设备信息,对于验证IP的请求包在回包之后会将设备置为ONLINE状态,在所有数据处理结束之后关闭该连接。
2.2关键数据结构
2.2.1双向链表
typedefstructList{
structList*prev;
structList*next;
}List;
2.2.2保存所有连接的链表头
staticList*g_fdMap=NULL;
2.2.3包类型定义
defineMODULE_TRUST_ENGINE1
defineMODULE_AUTH_SDK3
defineMODULE_CONNECTION5
defineMODULE_SMART_COMM7
defineMODULE_AUTH_MSG9
2.2.4数据缓冲区定义
typedefstructDataBuffer{
char*buf;
intsize;
intused;
}DataBuffer;
2.2.5连接定义,一个AuthConn表示一个真实连接
typedefstructAuthConn{
intfd;
charauthId[MAX_AUTH_ID_LEN];
chardeviceId[MAX_DEV_ID_LEN];
chardeviceIp[MAX_DEV_IP_LEN];
intbusVersion;
intauthPort;
intsessionPort;
intauthState;
intonlineState;
DataBufferdb;
}AuthConn;
2.2.6连接管理节点,用双向链表的方式保存所有连接
typedefstructAuthConnNode{
Listhead;
AuthConn*aconn;
}AuthConnNode;
2.2.7数据包头结构
typedefstruct{
intmodule;
intflags;
longlongseq;
intdataLen;
}Packet;
2.3关键接口
2.3.1ProcessConnectEvent
负责连接建立和管理
连接建立:
在链表g_fdMap中根据fd查找AuthConn,找不到则说明该fd没有被使用,然后为AuthConn分配内存,并且填充fd和ip数据到新建连接的AuthConn中,为AuthConnNode分配空间后将AuthConnNode和AuthConn绑定,最后将AuthConnNode追加在g_fdMap链表尾部后表示连接完成。
连接管理:
用一个g_fdMap为头指针的双向链表来保存所有的连接节点AuthConnNode,每一个AuthConnNode结构体都有自己的AuthConn,表示一个真正的连接,g_fdMap中最多可以保存32个连接,超过32个时建立连接会失败。
2.3.2ProcessDataEvent
负责从fd对应的连接中接收数据包,并且根据包的module不同来分别处理
首先根据fd找到对应的连接AuthConn,如果该连接还没有分配缓冲区,则为其创建一个1536字节大小的接收buf并清空,然后通过AuthConnRecv函数接收数据,其底层也是调用大家所熟悉的socket编程接口recv去接收数据,将接收的数据保存在刚才为AuthConn分配的buf中,并且更新表示当前缓冲区使用属性的变量used。然后调用ProcessPackets函数对接收的数据包解析并处理,该函数中对包头解析,然后根据包头中获取的数据长度来对数据部分进行处理。
2.3.3ParsePacketHead
解析包头
对收到的数据包头进行校验,magicnumber正确后,获取包的module、seq、flags、datalen信息并保存在Packet里面,后续对该包处理。
2.3.4OnDataReceived
对收到的数据进行处理
数据处理主要依赖包头中pkt-module这个值来区分不同类型的包,包的类型共有10种,除了MODULE_AUTH_SDK包通过AuthInterfaceOnDataReceived处理外,其余都会通过DecryptMessage函数进行处理,包处理结束之后会调用cJSON_Parse来获取数据,最后会对MODULE_TRUST_ENGINE包和MODULE_CONNECTION包构造一个新的reply包,将本地的设备信息封装成cJSON格式的msg后发回对端。
3.最终调用封装加密发送流程
3.1工作流程图如下
3.2关键数据结构
3.2.1SessionKey
在hichain处理流程中获取到的key被保存在SessionKey中,在最后发送之前获取sessionkey打包到要发送的buf中。
typedefstructSessionKey{
charkey[AUTH_SESSION_KEY_LEN];
intindex;
intfd;
}SessionKey;
3.2.2AuthSession
每当收到新的连接且类型是MODULE_AUTH_SDK时,创建一个AuthSession,并保存到全局数组g_authSessionMap中,下次再进行连接会话时从全局数据中找AuthSession
typedefstructAuthSession{
intisUsed;
longlongseqId;
uint32_tsessionId;
AuthConn*conn;
}AuthSession;
3.3关键接口
3.3.1AuthConnPackBytes
打包与加密接口,首先打包关键信息identifier,module等到传输buf中,判断isCipherText,是否需要加密,判断标准为module是否为MODULE_CONNECTION,MODULE_SESSIONMODULE_SMART_COMM
3.3.2AuthConnPackBytes
获取sessionkey,打包入要传输的buf中
3.3.3EncryptTransData
实际调用mbedtls加密框架,进行加密的接口
3.3.4AuthConnS
调用s函数,把打包好的buf通过套接字fd发送出去。
五.结束
当初步建立信任关系的IoT主控设备与IoT设备间在进行通信时,双方首先完成信任关系绑定,然后基于存储在本地的对端身份公钥相互进行认证;在每次通信时完成双向身份认证以及会话密钥协商,之后设备使用此会话密钥来解密双方设备间的传输通道。